#ifndef BUFFER_H #define BUFFER_H struct buffer { DA_DEF_STRUCT_ITEM(char, data); size_t cur; }; enum buffer_err { BUFFER_ERR_OK = 0, BUFFER_ERR_EMPTY, BUFFER_ERR_NOT_FOUND, BUFFER_ERR_INVALID_CUR_POS, BUFFER_ERR_FAIL_READ_FILE, BUFFER_ERR_START_GT_END, BUFFER_ERR_INVALID_END_SIZE, }; struct ret_buffer_err { struct buffer f1; enum buffer_err f2; }; struct ret_size_t_err { size_t f1; enum buffer_err f2; }; struct ret_buffer_size_t_err { struct buffer f1; size_t f2; enum buffer_err f3; }; struct buffer buffer_create(void); void buffer_destroy(struct buffer buf); struct ret_buffer_err buffer_load_from_file(struct buffer buf, const char *filepath); enum buffer_err buffer_save_to_file(struct buffer buf, const char *filepath); struct buffer buffer_mv_cur_left(struct buffer buf); struct buffer buffer_mv_cur_right(struct buffer buf); struct buffer buffer_mv_cur_up(struct buffer buf); struct buffer buffer_mv_cur_down(struct buffer buf); struct buffer buffer_insert_char(struct buffer buf, size_t index, char c); struct buffer buffer_remove_char_mv_cur(struct buffer buf, size_t index); struct buffer buffer_remove_char(struct buffer buf, size_t index); struct ret_buffer_size_t_err buffer_remove_between(struct buffer buf, size_t start, size_t end); struct ret_size_t_err buffer_index_bw_word(struct buffer buf); struct ret_size_t_err buffer_index_fw_word(struct buffer buf); struct ret_size_t_err buffer_index_bw_char(struct buffer buf, char c); struct ret_size_t_err buffer_index_fw_char(struct buffer buf, char c); #if defined(BUFFER_IMP) || defined(IMP) #include #include "file.h" #include "da.h" #include "unwrap.h" struct buffer buffer_create(void) { struct buffer buf = {0}; DA_CREATE(buf.data, sizeof(char)); return buf; } void buffer_destroy(struct buffer buf) { free(buf.data.items); } struct ret_buffer_err buffer_load_from_file(struct buffer buf, const char *filepath) { void *ptr; size_t file_size; enum file_err err; RET_UNWRAP3(ptr, file_size, err, struct ret_void_p_err, file_read_all(filepath)); if ( err != FILE_ERR_OK ) { return (struct ret_buffer_err) { .f1 = buf, .f2 = BUFFER_ERR_FAIL_READ_FILE }; } buffer_destroy(buf); buf.data.items = ptr; buf.data.size = file_size - 1; buf.data.cap = file_size; return (struct ret_buffer_err) { .f1 = buf, .f2 = BUFFER_ERR_OK }; } enum buffer_err buffer_save_to_file(struct buffer buf, const char *filepath) { (void) buf; (void) filepath; return BUFFER_ERR_OK; } struct buffer buffer_mv_cur_left(struct buffer buf) { if ( buf.cur == 0 ) { return buf; } --buf.cur; return buf; } struct buffer buffer_mv_cur_right(struct buffer buf) { if ( buf.cur == buf.data.size ) { return buf; } ++buf.cur; return buf; } struct buffer buffer_mv_cur_up(struct buffer buf) { return buf; } struct buffer buffer_mv_cur_down(struct buffer buf) { return buf; } struct buffer buffer_insert_char(struct buffer buf, size_t index, char c) { if ( index > buf.data.size ) { DA_APPEND(buf.data, c); ++buf.cur; return buf; } DA_INSERT(buf.data, c, index); ++buf.cur; return buf; } struct buffer buffer_remove_char_mv_cur(struct buffer buf, size_t index) { if ( buf.data.size == 0 ) { return buf; } if ( index > buf.data.size ) { return buf; } if ( buf.data.size == index ) { buf.data.items[--buf.data.size] = 0; --buf.cur; return buf; } DA_DELETE(buf.data, index); --buf.cur; return buf; } struct buffer buffer_remove_char(struct buffer buf, size_t index) { if ( buf.data.size == 0 ) { return buf; } if ( index > buf.data.size ) { return buf; } if ( buf.data.size == index ) { buf.data.items[--buf.data.size] = 0; return buf; } DA_DELETE(buf.data, index); return buf; } struct ret_buffer_size_t_err buffer_remove_between(struct buffer buf, size_t start, size_t end) { enum buffer_err err = BUFFER_ERR_OK; if ( buf.data.size == 0 ) { err = BUFFER_ERR_EMPTY; goto err; } if ( start == end ) { return (struct ret_buffer_size_t_err) { .f1 = buffer_remove_char(buf, start), .f2 = 1, .f3 = BUFFER_ERR_OK, }; } if ( start > end ) { err = BUFFER_ERR_START_GT_END; goto err; } DA_DEF_STRUCT_ITEM(char, da); DA_ASSIGN(da, buf.data); /* There is no need to check start > buf.data.size, because */ /* we know that start < end */ if ( end > da.size ) { err = BUFFER_ERR_INVALID_END_SIZE; goto err; } size_t nrm = end - start; memmove(da.items+start, da.items+end, da.size - nrm); da.size -= nrm; return (struct ret_buffer_size_t_err) { .f1 = buf, .f2 = nrm, .f3 = BUFFER_ERR_OK, }; err: ; return (struct ret_buffer_size_t_err) { .f1 = buf, .f2 = 0, .f3 = err }; } struct ret_size_t_err buffer_index_bw_word(struct buffer buf) { enum buffer_err err = BUFFER_ERR_OK; if ( buf.data.size == 0 ) { err = BUFFER_ERR_EMPTY; goto err; } if ( buf.cur > buf.data.size ) { err = BUFFER_ERR_INVALID_CUR_POS; goto err; } bool found_letter = false; size_t i = buf.cur - 1; for ( ; i > 0; --i) { char c = buf.data.items[i]; if ( isalnum(c) ) { found_letter = true; } else if ( found_letter ) { ++i; goto exit; } } if ( i == 0 ) { char c = buf.data.items[i]; if ( isalnum(c) ) { found_letter = true; } else if ( found_letter ) { ++i; goto exit; } } exit: ; return (struct ret_size_t_err) { .f1 = i, .f2 = BUFFER_ERR_OK, }; err: ; return (struct ret_size_t_err) { .f1 = 0, .f2 = err, }; } struct ret_size_t_err buffer_index_fw_word(struct buffer buf) { enum buffer_err err = BUFFER_ERR_OK; if ( buf.data.size == 0 ) { err = BUFFER_ERR_EMPTY; goto err; } if ( buf.cur > buf.data.size ) { err = BUFFER_ERR_INVALID_CUR_POS; goto err; } bool found_letter = false; size_t i = buf.cur; for ( ; i < buf.data.size; ++i) { char c = buf.data.items[i]; if ( isalnum(c) ) { found_letter = true; } else if ( found_letter ) { goto exit; } } if ( i == 0 ) { char c = buf.data.items[i]; if ( isalnum(c) ) { found_letter = true; } else if ( found_letter ) { goto exit; } } exit: ; return (struct ret_size_t_err) { .f1 = i, .f2 = BUFFER_ERR_OK, }; err: ; return (struct ret_size_t_err) { .f1 = 0, .f2 = err, }; } struct ret_size_t_err buffer_index_bw_char(struct buffer buf, char c) { enum buffer_err err; if ( buf.data.size == 0 ) { err = BUFFER_ERR_EMPTY; goto err; } if ( buf.cur > buf.data.size ) { err = BUFFER_ERR_INVALID_CUR_POS; goto err; } const char *str = buf.data.items; bool cond = false; /* TODO: Find a way to not use ssize_t buf size_t */ ssize_t closest = -1; for ( ssize_t i = 0; i < (ssize_t) buf.cur; ++i ) { cond = str[i] == c; closest = ( cond ) * i + ( ! cond ) * closest; } if ( closest == -1 ) { err = BUFFER_ERR_NOT_FOUND; goto err; } return (struct ret_size_t_err) { .f1 = (size_t) closest, .f2 = BUFFER_ERR_OK, }; err: ; return (struct ret_size_t_err) { .f1 = 0, .f2 = err, }; } struct ret_size_t_err buffer_index_fw_char(struct buffer buf, char c) { enum buffer_err err; if ( buf.data.size == 0 ) { err = BUFFER_ERR_EMPTY; goto err; } if ( buf.cur > buf.data.size ) { err = BUFFER_ERR_INVALID_CUR_POS; goto err; } const char *str = buf.data.items; for ( size_t i = buf.cur; i < buf.data.size; ++i ) { if ( str[i] == c ) { return (struct ret_size_t_err) { .f1 = i, .f2 = BUFFER_ERR_OK, }; } } err = BUFFER_ERR_NOT_FOUND; err: ; return (struct ret_size_t_err) { .f1 = 0, .f2 = err, }; } #endif /* defined(BUFFER_IMP) || defined(IMP) */ #endif