sled

Једноставни уређивач текста
git clone https://git.sr.ht/~strahinja/sled
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување a3e96a3b779237982b8f9a7a0cdd460c1bd71a28
родитељ c01ec23d384713be9039c7a5cfdbf0298e0de56b
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Fri, 14 Jun 2024 22:21:04 +0200

Switch {u32_,}str* -> {u32_,}memccpy

Diffstat:
MTODO | 2++
Msled.c | 146++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mutil.c | 113++++++++++++++++++++++++++++++++++---------------------------------------------
Mutil.h | 58++++++++++++++++++++++++++++++++++++++--------------------
измењених датотека: 4, додавања: 182(+), брисања: 137(-)

diff --git a/TODO b/TODO @@ -1,6 +1,8 @@ TODO ==== +[ ] Make y/n prompts case-insensitive + < > Make allocation errors prompt to save the file before exiting? - Would this make sense? diff --git a/sled.c b/sled.c @@ -212,6 +212,8 @@ dirname(char* dir, char* path, const size_t dir_size) if (p > dir + 2 && *(p - 2) == '/') *p = 0; + if (p > dir + 1) + p--; while (p != dir && *p != '/') { @@ -237,7 +239,10 @@ do_search_replace(struct DrawState* state) /* minimum size is LINE_DEFAULT to avoid 0-allocation */ size_t bufsize = LINE_DEFAULT; /* size in uint32_t units */ size_t buflen = 0; + size_t old_buflen = 0; size_t search_len = u32_strlen(state->search); + size_t input_len = u32_strlen(state->input); + size_t after_len = 0; int start_row = 0; int end_row = state->rows_count; uint32_t* before = NULL; @@ -251,7 +256,7 @@ do_search_replace(struct DrawState* state) if (state->buffer[row].size > bufsize) bufsize = state->buffer[row].size; - buf = malloc(bufsize * sizeof(uint32_t)); + buf = calloc(bufsize, sizeof(uint32_t)); if (!buf) goto do_search_replace_error; @@ -259,40 +264,48 @@ do_search_replace(struct DrawState* state) { before = state->buffer[row].text; found = (uint32_t*)u32_strstr(before, state->search); - after = before; - *buf = 0; + if (!found) + continue; - buflen = 0; + state->dirty = 1; + *buf = 0; + *found = 0; + buflen = u32_strlen(before); + ENSURE_SIZE(buf, temp, bufsize, buflen + 1, buflen + 1, + do_search_replace_error, uint32_t); + U32_MEMCCPY(buf, before, bufsize, temp); + after = found + search_len; + *(after - 1) = 0; while (found) { - state->dirty = 1; - *found = 0; - buflen += u32_strlen(before) + u32_strlen(state->input); - + old_buflen = buflen; + buflen += input_len; ENSURE_SIZE(buf, temp, bufsize, buflen + 1, buflen + 1, do_search_replace_error, uint32_t); - u32_strncat(buf, before, bufsize); - u32_strncat(buf, state->input, bufsize); - before = found + search_len; + U32_MEMCCPY((buf + old_buflen), state->input, + input_len + 1, temp); + before = after; found = (uint32_t*)u32_strstr(before, state->search); - if (found) - after = found + search_len; - else - after = before; - } - if (state->buffer[row].text + state->buffer[row].length > after) - { - buflen += u32_strlen(after); + if (found) /* new found, after before */ + *found = 0; + after_len = u32_strlen(after); + old_buflen = buflen; + buflen += after_len; ENSURE_SIZE(buf, temp, bufsize, buflen + 1, buflen + 1, do_search_replace_error, uint32_t); - u32_strncat(buf, after, bufsize); + U32_MEMCCPY((buf + old_buflen), after, after_len + 1, + temp); + if (found) /* new found, after before */ + { + after = found + search_len; + *(after - 1) = 0; + } } - U32_SAFE_COPY(state->buffer[row].text, temp, state->buffer[row].size, buf, bufsize, do_search_replace_error); - state->buffer[row].length = u32_strlen(buf); + state->buffer[row].length = buflen; } free(buf); return 0; @@ -316,6 +329,7 @@ erase_selection(struct DrawState* state) int sec = 0; uint32_t* buf = NULL; size_t bufsize = state->buffer[ser].size; + uint32_t* temp = NULL; buf = calloc(bufsize, sizeof(uint32_t)); if (!buf) @@ -323,10 +337,11 @@ erase_selection(struct DrawState* state) get_selection(&ssr, &ssc, &ser, &sec, state); - u32_strncpy(buf, state->buffer[ser].text + sec, bufsize); + U32_MEMCCPY(buf, state->buffer[ser].text + sec, bufsize - sec, + temp); - *(state->buffer[ssr].text + ssc) = 0; - u32_strncat(state->buffer[ssr].text, buf, bufsize); + U32_MEMCCPY((state->buffer[ssr].text + ssc), buf, bufsize - ssc, + temp); state->buffer[ssr].length = u32_strlen(state->buffer[ssr].text); if (ssr != ser) @@ -334,9 +349,9 @@ erase_selection(struct DrawState* state) for (size_t row = 0; ser + row + 1 < state->rows_count; row++) { - u32_strncpy(state->buffer[ssr + row + 1].text, + U32_MEMCCPY(state->buffer[ssr + row + 1].text, state->buffer[ser + row + 1].text, - bufsize); + bufsize, temp); state->buffer[ssr + row + 1].length = state->buffer[ser + row + 1].length; } @@ -621,7 +636,7 @@ insert_char(struct DrawState* state, uint32_t ch) uint32_t* ptext = NULL; ENSURE_SIZE(state->buffer[state->coord.row].text, ptext, - state->buffer[state->coord.row].size, state->coord.col + 1, + state->buffer[state->coord.row].size, state->coord.col + 2, state->coord.col + LINE_ALLOC_DELTA, insert_char_error, uint32_t); @@ -840,8 +855,8 @@ load_file(struct DrawState* state, long* lineno, long* col) input_len + LINE_ALLOC_DELTA, load_file_alloc_error, uint32_t); - line->length - = u32_u8_strncpy(line->text, input_line, line->size); + U32_U8_MEMCCPY(line->text, input_line, line->size, ptext); + line->length = u32_strlen(line->text); state->rows_count++; } fclose(input); @@ -1140,8 +1155,10 @@ save_skip_backup_symlink: for (size_t row = 0; row < state->rows_count; row++) { - ENSURE_SIZE(buf, pbuf, bufsize, state->buffer[row].length + 1, - state->buffer[row].length + LINE_ALLOC_DELTA, + ENSURE_SIZE(buf, pbuf, bufsize, + UTF8REPMAX * state->buffer[row].length + 1, + UTF8REPMAX * state->buffer[row].length + + LINE_ALLOC_DELTA, save_file_alloc_error, char); unicode_string_to_u8(buf, state->buffer[row].text, bufsize); fprintf(output, "%s\n", buf); @@ -1193,7 +1210,8 @@ search_replace_replace_dialog_callback(struct DrawState* state) void search_update_callback(struct DrawState* state) { - u32_strncpy(state->search, state->input, MAXINPUT); + uint32_t* temp = NULL; + U32_MEMCCPY(state->search, state->input, MAXINPUT, temp); } int @@ -1523,9 +1541,10 @@ input_erase_forward(struct DrawState* state) int input_erase_to_end(struct DrawState* state) { + uint32_t* temp = NULL; state->input[state->input_column] = 0; input_move_end(state); - u32_strncpy(state->search, state->input, MAXINPUT); + U32_MEMCCPY(state->search, state->input, MAXINPUT, temp); if (state->input_update_callback) state->input_update_callback(state); return 0; @@ -1906,7 +1925,7 @@ paste_from_paste(struct DrawState* state) } line = state->buffer + state->coord.row; - newsize = line->size + state->paste[0].length + 1; + newsize = line->length + state->paste[0].length + 1; newtext = calloc(newsize, sizeof(uint32_t)); if (!newtext) { @@ -1915,17 +1934,23 @@ paste_from_paste(struct DrawState* state) temp); goto paste_from_paste_cleanup; } - u32_strncpy(newtext, line->text, state->coord.col); - u32_strncat(newtext, state->paste[0].text, newsize); + U32_MEMCCPY(newtext, line->text, state->coord.col + 1, ptext); + U32_MEMCCPY((newtext + state->coord.col), state->paste[0].text, newsize, + ptext); assign_coord(&newpos, state->coord); if (state->paste_count == 1) { - u32_strncat(newtext, line->text + state->coord.col, newsize); - line->length = u32_strncpy(line->text, newtext, newsize); - line->size = newsize; - newpos.col += state->paste[state->paste_count - 1].length; + if (ptext) + U32_MEMCCPY_EXT((ptext - 1), newtext, + line->text + state->coord.col, + line->length - state->coord.col, newsize, + ptext); + U32_SAFE_COPY(line->text, ptext, line->size, newtext, newsize, + paste_from_paste_cleanup); + line->length = u32_strlen(line->text); + newpos.col += state->paste[0].length; } else { @@ -1939,7 +1964,8 @@ paste_from_paste(struct DrawState* state) LINE_DEFAULT, temp); goto paste_from_paste_cleanup; } - u32_strncpy(rest, line->text + state->coord.col, rest_size); + U32_MEMCCPY(rest, line->text + state->coord.col, rest_size, + ptext); U32_SAFE_COPY(line->text, ptext, line->size, newtext, newsize, paste_from_paste_cleanup); line->length = u32_strlen(line->text); @@ -1975,7 +2001,10 @@ paste_from_paste(struct DrawState* state) state->paste[state->paste_count - 1].text, state->paste[state->paste_count - 1].size + rest_size, paste_from_paste_cleanup); - u32_strncat(newtext, rest, newsize); + if (ptext) + U32_MEMCCPY_EXT((ptext - 1), newtext, rest, + newsize - (ptext - newtext - 1), newsize, + ptext); U32_SAFE_COPY(line->text, ptext, line->size, newtext, newsize, paste_from_paste_cleanup); line->length = u32_strlen(line->text); @@ -2267,11 +2296,15 @@ simple_join_lines(struct DrawState* state) state->buffer[first_line].length + state->buffer[first_line + 1].length + 1, simple_join_lines_error, uint32_t); - u32_strncat(state->buffer[first_line].text, + U32_MEMCCPY((state->buffer[first_line].text + + state->buffer[first_line].length), state->buffer[first_line + 1].text, - state->buffer[first_line].size); + state->buffer[first_line].size + - state->buffer[first_line + 1].length, + ptext); state->buffer[first_line].length = u32_strlen(state->buffer[first_line].text); + //+= state->buffer[first_line + 1].length; for (size_t i = first_line + 1; i < state->rows_count - 1; i++) { U32_SAFE_COPY(state->buffer[i].text, ptext, @@ -2343,17 +2376,16 @@ simple_yank(struct DrawState* state) if (state->paste_count == 1) { U32_SAFE_COPY(state->paste[0].text, ptext, state->paste[0].size, - state->buffer[ssr].text + ssc, sec - ssc, + state->buffer[ssr].text + ssc, sec - ssc + 1, simple_yank_alloc_error); - state->paste[0].length = u32_strlen(state->paste[0].text); + state->paste[0].length = sec - ssc; } else { - size_t first_line_len - = u32_strlen(state->buffer[ssr].text + ssc); + size_t first_line_len = state->buffer[ssr].length - ssc; U32_SAFE_COPY(state->paste[0].text, ptext, state->paste[0].size, - state->buffer[ssr].text + ssc, first_line_len, + state->buffer[ssr].text + ssc, first_line_len + 1, simple_yank_alloc_error); state->paste[0].length = first_line_len; @@ -2370,9 +2402,9 @@ simple_yank(struct DrawState* state) U32_SAFE_COPY(state->paste[state->paste_count - 1].text, ptext, state->paste[state->paste_count - 1].size, - state->buffer[ser].text, sec, simple_yank_alloc_error); - state->paste[state->paste_count - 1].length - = u32_strlen(state->paste[state->paste_count - 1].text); + state->buffer[ser].text, sec + 1, + simple_yank_alloc_error); + state->paste[state->paste_count - 1].length = sec; } return; @@ -2641,6 +2673,12 @@ main(int argc, char** argv) { MEMCCPY(state.real_filename, dir, limits[L_PATH_MAX], temp); + if (!temp) + { + print_error(1, "Pathname too long"); + free(filename); + exit(1); + } *(temp - 1) = '/'; MEMCCPY_EXT(temp, state.real_filename, rfn, limits[L_PATH_MAX] - state.rfn_len - 1, @@ -2757,6 +2795,7 @@ main(int argc, char** argv) perror("sled: unveil"); free(filename); free(dir); + free(rfn); exit(1); } #endif @@ -2792,6 +2831,7 @@ general_error: free(state.backup_filename); free(filename); free(dir); + free(rfn); return result; init_termbox: diff --git a/util.c b/util.c @@ -11,10 +11,6 @@ #include "termbox.h" #include "util.h" -enum { UTLERRNONE = 0, UTLERROVFL = 1 }; - -int utlerrno = UTLERRNONE; - size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max) { @@ -39,12 +35,11 @@ u8_string_to_unicode(uint32_t* us, const char* s, const size_t max) return added; } -/* If the textual representation of characters in us exceeds max, utlerrno is - * set to UTLERROVFL */ size_t unicode_string_to_u8(char* s, const uint32_t* us, const size_t max) { char ch[8]; + char* ps = NULL; const uint32_t* pus = us; size_t len; size_t added = 0; @@ -52,25 +47,65 @@ unicode_string_to_u8(char* s, const uint32_t* us, const size_t max) if (!pus) return added; - *s = 0; + ps = s; while (*pus) { len = tb_utf8_unicode_to_char(ch, *pus); if (added + 1 >= max) - break; - ch[len] = 0; - if (strlcat(s, ch, max) >= max) - { - utlerrno = UTLERROVFL; return added; - } + memccpy(ps, ch, 0, len); + ps += len; added++; pus++; } - utlerrno = UTLERRNONE; + *ps = 0; return added; } +uint32_t* +u32_memccpy(uint32_t* dst, const uint32_t* src, uint32_t c, size_t len) +{ + size_t copied = 0; + while ((*dst++ = *src++) != c && copied < len) + copied++; + if (copied == len) + return NULL; + return dst; +} + +/* len is the max length of src in bytes */ +uint32_t* +u32_u8_memccpy(uint32_t* dst, const char* src, char c, size_t len) +{ + size_t copied = 0; + size_t u8_len; + uint32_t uch; + const char* psrc = src; + + if (!*psrc) + { + *dst = 0; + return dst; + } + + u8_len = tb_utf8_char_to_unicode(&uch, psrc); + while ((*dst++ = uch) != c && copied < len) + { + psrc += u8_len; + copied += u8_len; + if (copied >= len) + return NULL; + if (*psrc) + u8_len = tb_utf8_char_to_unicode(&uch, psrc); + else + { + *dst = 0; + break; + } + } + return dst; +} + size_t u8_strlen(const char* s) { @@ -151,56 +186,6 @@ u32_strchr(const uint32_t* haystack, const uint32_t needle) return NULL; } -size_t -u32_strncpy(uint32_t* to, const uint32_t* from, const size_t max) -{ - const uint32_t* pfrom = from; - size_t copied = 0; - while (*pfrom && copied < max) - { - *to++ = *pfrom++; - copied++; - } - *to = 0; - return copied; -} - -/* - * to - u32 string to concatenate to - * max - total combined string size - * from - u32 string to concatenate */ -size_t -u32_strncat(uint32_t* to, const uint32_t* from, const size_t max) -{ - const uint32_t* pfrom = from; - size_t copied = 0; - while (*to && copied < max) - { - to++; - copied++; - } - while (*pfrom && copied < max) - { - *to++ = *pfrom++; - copied++; - } - *to = 0; - return copied; -} - -size_t -u32_u8_strncpy(uint32_t* to, const char* from, const size_t max) -{ - uint32_t* ufrom = NULL; - size_t len; - if (!(ufrom = malloc(max * sizeof(uint32_t)))) - return 0; - u8_string_to_unicode(ufrom, from, max); - len = u32_strncpy(to, ufrom, max); - free(ufrom); - return len; -} - const int is_word_boundary(const char ch, const int strictly_whitespace) { diff --git a/util.h b/util.h @@ -10,19 +10,40 @@ #define LEN(x) (sizeof(x) / sizeof(x[0])) #define MAX(a, b) ((a > b) ? (a) : (b)) #define MIN(a, b) ((a < b) ? (a) : (b)) -#define MEMCCPY(to, from, tolen, temp) \ - do \ - { \ - temp = memccpy(to, from, 0, tolen); \ - if (!temp) \ - to[tolen - 1] = 0; \ +#define MEMCCPY(to, from, tolen, temp) \ + do \ + { \ + temp = memccpy(to, from, 0, tolen); \ + if (!temp) \ + to[tolen > 0 ? tolen - 1 : 0] = 0; \ } while (0) -#define MEMCCPY_EXT(to, fallbackto, from, tolen, temp) \ - do \ - { \ - temp = memccpy(to, from, 0, tolen); \ - if (!temp) \ - fallbackto[tolen - 1] = 0; \ +#define MEMCCPY_EXT(to, fallbackto, from, tolen, temp) \ + do \ + { \ + temp = memccpy(to, from, 0, tolen); \ + if (!temp) \ + fallbackto[tolen > 0 ? tolen - 1 : 0] = 0; \ + } while (0) +#define U32_MEMCCPY(to, from, tolen, temp) \ + do \ + { \ + temp = u32_memccpy(to, from, 0L, tolen); \ + if (!temp) \ + to[tolen > 0 ? tolen - 1 : 0] = 0; \ + } while (0) +#define U32_U8_MEMCCPY(to, from, tolen, temp) \ + do \ + { \ + temp = u32_u8_memccpy(to, from, 0L, tolen); \ + if (!temp) \ + to[tolen > 0 ? tolen - 1 : 0] = 0; \ + } while (0) +#define U32_MEMCCPY_EXT(to, fallbackto, from, tolen, fbtolen, temp) \ + do \ + { \ + temp = u32_memccpy(to, from, 0L, tolen); \ + if (!temp) \ + fallbackto[fbtolen > 0 ? fbtolen - 1 : 0] = 0; \ } while (0) #define ENSURE_SIZE(to, temp, tosize, testsize, fromsize, label, type) \ @@ -54,7 +75,7 @@ do \ { \ ENSURE_SIZE(to, temp, tosize, fromsize, fromsize, label, char); \ - u8_strncpy(to, from, fromsize); \ + MEMCCPY(to, from, fromsize, temp); \ } while (0) /* * - Make sure the size of the destination string is large enough to copy, and @@ -68,7 +89,7 @@ { \ ENSURE_SIZE(to, temp, tosize, fromsize, fromsize, label, \ uint32_t); \ - u32_strncpy(to, from, fromsize); \ + U32_MEMCCPY(to, from, fromsize, temp); \ } while (0) enum { @@ -101,20 +122,17 @@ enum { ACT_WRITING, ACT_READING }; extern int utlerrno; -size_t strlcpy(char* dst, const char* src, size_t dsize); -size_t strlcat(char* dst, const char* src, size_t dsize); - size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max); size_t unicode_string_to_u8(char* s, const uint32_t* us, const size_t max); +uint32_t* u32_memccpy(uint32_t* dst, const uint32_t* src, uint32_t c, + size_t len); +uint32_t* u32_u8_memccpy(uint32_t* dst, const char* src, char c, size_t len); size_t u8_strlen(const char* s); size_t u32_strlen(const uint32_t* s); const uint32_t* u32_strstr(const uint32_t* haystack, const uint32_t* needle); const uint32_t* u32_strrstr(const uint32_t* haystack, const uint32_t* needle, const uint32_t* haystack_tail); const uint32_t* u32_strchr(const uint32_t* haystack, const uint32_t needle); -size_t u32_strncpy(uint32_t* to, const uint32_t* from, const size_t max); -size_t u32_strncat(uint32_t* to, const uint32_t* from, const size_t max); -size_t u32_u8_strncpy(uint32_t* to, const char* from, const size_t max); const int is_word_boundary(const char ch, const int strictly_whitespace); const int u32_is_word_boundary(const uint32_t ch, const int strictly_whitespace); const int starts_with(const char* s, const char* with);