sled

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

чување 5cc50247e21f89af398eb94693d70f30c83e7580
родитељ cec2b429688d1cf8995d8675aee116801fe55513
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sat,  2 Mar 2024 22:46:28 +0100

Switch from strcpy,strcat to strlcpy,strlcat

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
MTODO | 2--
MTODO.done | 2++
Msled.c | 331+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Astrlcat.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astrlcpy.c | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.c | 83+++++++++++++++++++++++++++++++------------------------------------------------
Mutil.h | 10+++++-----
измењених датотека: 7, додавања: 399(+), брисања: 132(-)

diff --git a/TODO b/TODO @@ -3,8 +3,6 @@ TODO [~] Code optimization (struct coord...) -[ ] Switch to strlcpy, strlcat; check u8_*/u32_* - Legend ------ diff --git a/TODO.done b/TODO.done @@ -1,6 +1,8 @@ Done or canceled todos ====================== +[x] Switch to strlcpy, strlcat; check u8_*/u32_* + [x] Change the backup method, as `crontab -e` doesn't like inode changes (crontab -e with CREATE_BACKUPS gives: diff --git a/sled.c b/sled.c @@ -59,6 +59,13 @@ extern const char* prompt_overwrite; extern const char* prompt_reread_dirty; extern const char* program_name; +#ifndef strlcpy +size_t strlcpy(char* dst, const char* src, size_t dsize); +#endif +#ifndef strlcat +size_t strlcat(char* dst, const char* src, size_t dsize); +#endif + int clear_selection(struct DrawState* state); int cp(const char* from, const char* to); int create_file(struct DrawState* dstate); @@ -203,7 +210,11 @@ dirname(char* path) result = malloc(MAXPATH); memset(result, 0, MAXPATH); - strcpy(result, path); + if (strlcpy(result, path, MAXPATH) >= MAXPATH) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } p = result + strlen(result) - 1; if (*p == '/') *p = 0; @@ -240,8 +251,8 @@ do_search_replace(struct DrawState* state) { state->dirty = 1; *found = 0; - u32_strcat(buf, before); - u32_strcat(buf, state->input); + u32_strncat(buf, before, MAXBUFLINE); + u32_strncat(buf, state->input, MAXBUFLINE); before = found + search_len; found = (uint32_t*)u32_strstr(before, state->search); if (found) @@ -250,9 +261,9 @@ do_search_replace(struct DrawState* state) after = before; } if (state->buffer[row].text + state->buffer[row].length > after) - u32_strcat(buf, after); + u32_strncat(buf, after, MAXBUFLINE); - u32_strcpy(state->buffer[row].text, buf); + u32_strncpy(state->buffer[row].text, buf, MAXBUFLINE); state->buffer[row].length = u32_strlen(buf); } return 0; @@ -277,10 +288,10 @@ erase_selection(struct DrawState* state) get_selection(&ssr, &ssc, &ser, &sec, state); - u32_strcpy(buf, state->buffer[ser].text + sec); + u32_strncpy(buf, state->buffer[ser].text + sec, MAXBUFLINE); *(state->buffer[ssr].text + ssc) = 0; - u32_strcat(state->buffer[ssr].text, buf); + u32_strncat(state->buffer[ssr].text, buf, MAXBUFLINE); state->buffer[ssr].length = u32_strlen(state->buffer[ssr].text); if (ssr != ser) @@ -288,8 +299,9 @@ erase_selection(struct DrawState* state) for (size_t row = 0; ser + row + 1 < state->rows_count; row++) { - u32_strcpy(state->buffer[ssr + row + 1].text, - state->buffer[ser + row + 1].text); + u32_strncpy(state->buffer[ssr + row + 1].text, + state->buffer[ser + row + 1].text, + MAXBUFLINE); state->buffer[ssr + row + 1].length = state->buffer[ser + row + 1].length; } @@ -373,7 +385,13 @@ go_to_line_callback(struct DrawState* state) u8_input = calloc(len + 1, UTF8REPMAX); if (!u8_input) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; return; } @@ -381,7 +399,13 @@ go_to_line_callback(struct DrawState* state) errno = 0; lineno = strtoul(u8_input, NULL, 10); if (errno) - strcpy(state->error, errors[ERR_INVALID_NUM]); + if (strlcpy(state->error, errors[ERR_INVALID_NUM], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } if (!*state->error) { if (lineno > state->rows_count - 1) @@ -447,8 +471,13 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) && strchr("0123456789", (const char)ev->ch)) || !IN(state->mode, M_INPUT_NUM)) input_insert_char(state, ev->ch); - else - strcpy(state->error, errors[ERR_INPUT_NONNUM]); + else if (strlcpy(state->error, errors[ERR_INPUT_NONNUM], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return; } } @@ -465,7 +494,12 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) if (IN(state->mode, M_HELP)) { - strcpy(state->error, errors[ERR_DLG_OPEN]); + if (strlcpy(state->error, errors[ERR_DLG_OPEN], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return; } @@ -513,7 +547,12 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) } } - strcpy(state->error, errors[ERR_UNKNOWN_KEY]); + if (strlcpy(state->error, errors[ERR_UNKNOWN_KEY], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } } int @@ -711,7 +750,13 @@ load_file(struct DrawState* state, long* lineno, long* col) newchunk[row].text = newtext; } - strcpy(state->action, actions[ACT_READING]); + if (strlcpy(state->action, actions[ACT_READING], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } + redraw_status(state); state->buffer = newchunk; @@ -757,8 +802,9 @@ load_file(struct DrawState* state, long* lineno, long* col) } line = state->buffer + state->buffer_size - ALLOC_DELTA; } - line = state->buffer + state->rows_count; - line->length = u32_u8_strcpy(line->text, input_line); + line = state->buffer + state->rows_count; + line->length + = u32_u8_strncpy(line->text, input_line, MAXBUFLINE); state->rows_count++; } fclose(input); @@ -876,7 +922,7 @@ print_error(const int code, const char* msg, ...) char buf[MAXBUFLINE]; va_list args; va_start(args, msg); - vsnprintf(buf, sizeof(buf), msg, args); + vsnprintf(buf, MAXBUFLINE, msg, args); va_end(args); fprintf(stderr, "%s: %s\n", program_name, buf); return code; @@ -908,11 +954,21 @@ reread_file(struct DrawState* state) switch (result) { case LOAD_ERR_CANT_ALLOC: - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; case LOAD_ERR_CANT_OPEN_FILE: - strcpy(state->error, errors[ERR_CANT_OPEN]); + if (strlcpy(state->error, errors[ERR_CANT_OPEN], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; default:; @@ -943,7 +999,12 @@ save_file(struct DrawState* state) if (!(buf = calloc(MAXBUFLINE, 1))) return SAVE_ERR_CANT_ALLOC; - strcpy(state->action, actions[ACT_WRITING]); + if (strlcpy(state->action, actions[ACT_WRITING], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } redraw_status(state); errno = 0; @@ -1054,7 +1115,7 @@ search_replace_replace_dialog_callback(struct DrawState* state) void search_update_callback(struct DrawState* state) { - u32_strcpy(state->search, state->input); + u32_strncpy(state->search, state->input, MAXBUFLINE); } int @@ -1065,8 +1126,12 @@ cancel_close(struct DrawState* state) { if (SEL_NOT_EMPTY(state)) clear_selection(state); - else - strcpy(state->error, errors[ERR_EXIT_KEY]); + else if (strlcpy(state->error, errors[ERR_EXIT_KEY], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } } else { @@ -1193,8 +1258,8 @@ erase_line(struct DrawState* state) for (size_t row = state->coord.row; row < state->rows_count - 1; row++) { current = state->buffer + row; - current->length = u32_strcpy(current->text, - state->buffer[row + 1].text); + current->length = u32_strncpy(current->text, + state->buffer[row + 1].text, MAXBUFLINE); } *state->buffer[state->rows_count - 1].text = 0; state->buffer[state->rows_count - 1].length = 0; @@ -1290,7 +1355,12 @@ exit_program(struct DrawState* state) if (state->dirty) { SET(state->mode, M_PROMPT); - strcpy(state->prompt, prompt_dirty); + if (strlcpy(state->prompt, prompt_dirty, MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->prompt_callback = quit_callback; } else @@ -1383,7 +1453,7 @@ input_erase_to_end(struct DrawState* state) { state->input[state->input_column] = 0; input_move_end(state); - u32_strcpy(state->search, state->input); + u32_strncpy(state->search, state->input, MAXBUFLINE); if (state->input_update_callback) state->input_update_callback(state); return 0; @@ -1762,16 +1832,21 @@ paste_from_paste(struct DrawState* state) if (!newtext) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } goto paste_from_paste_cleanup; } u32_strncpy(newtext, line->text, state->coord.col + 1); - u32_strcat(newtext, state->paste[0].text); + u32_strncat(newtext, state->paste[0].text, MAXBUFLINE); if (state->paste_count == 1) { - u32_strcat(newtext, line->text + state->coord.col); - line->length = u32_strcpy(line->text, newtext); + u32_strncat(newtext, line->text + state->coord.col, MAXBUFLINE); + line->length = u32_strncpy(line->text, newtext, MAXBUFLINE); state->coord.col += state->paste[state->paste_count - 1].length; } else @@ -1781,33 +1856,41 @@ paste_from_paste(struct DrawState* state) if (!rest) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } goto paste_from_paste_cleanup; } - u32_strcpy(rest, line->text + state->coord.col); - line->length = u32_strcpy(line->text, newtext); + u32_strncpy(rest, line->text + state->coord.col, MAXBUFLINE); + line->length = u32_strncpy(line->text, newtext, MAXBUFLINE); for (size_t row = state->rows_count - state->coord.row - (state->paste_count - 2) - 1; row > 0; row--) { line = state->buffer + state->coord.row + state->paste_count - 2 + row; - line->length = u32_strcpy(line->text, - state->buffer[state->coord.row + row - 1].text); + line->length = u32_strncpy(line->text, + state->buffer[state->coord.row + row - 1].text, + MAXBUFLINE); } line = state->buffer + state->coord.row; - line->length = u32_strcpy(line->text, newtext); + line->length = u32_strncpy(line->text, newtext, MAXBUFLINE); for (size_t row = 1; row < state->paste_count - 1; row++) { line = state->buffer + state->coord.row + row; - line->length = u32_strcpy(line->text, - state->paste[row].text); + line->length = u32_strncpy(line->text, + state->paste[row].text, MAXBUFLINE); } line = state->buffer + state->coord.row + state->paste_count - 1; - u32_strcpy(newtext, state->paste[state->paste_count - 1].text); - u32_strcat(newtext, rest); - line->length = u32_strcpy(line->text, newtext); + u32_strncpy(newtext, state->paste[state->paste_count - 1].text, + MAXBUFLINE); + u32_strncat(newtext, rest, MAXBUFLINE); + line->length = u32_strncpy(line->text, newtext, MAXBUFLINE); state->coord.col = state->paste[state->paste_count - 1].length; state->coord.row += state->paste_count - 1; } @@ -1875,7 +1958,12 @@ reread_or_callback(struct DrawState* state) if (state->dirty) { SET(state->mode, M_PROMPT); - strcpy(state->prompt, prompt_reread_dirty); + if (strlcpy(state->prompt, prompt_reread_dirty, MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->prompt_callback = reread_callback; } else @@ -1893,7 +1981,13 @@ show_go_to_line(struct DrawState* state) if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } } @@ -1915,7 +2009,13 @@ show_replace(struct DrawState* state) if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } } @@ -1935,7 +2035,13 @@ show_search(struct DrawState* state) if (!(state->search = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } } @@ -1948,7 +2054,13 @@ show_search(struct DrawState* state) if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } } @@ -1968,7 +2080,13 @@ show_search_replace(struct DrawState* state) if (!(state->search = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } } @@ -1981,7 +2099,13 @@ show_search_replace(struct DrawState* state) if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } } @@ -2017,7 +2141,13 @@ simple_insert_line(struct DrawState* state) if (!newchunk) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return; } state->buffer = newchunk; @@ -2030,7 +2160,14 @@ simple_insert_line(struct DrawState* state) if (!newtext) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, + errors[ERR_CANT_ALLOC], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", + __LINE__); + exit(1); + } return; } line->text = newtext; @@ -2039,11 +2176,12 @@ simple_insert_line(struct DrawState* state) } state->rows_count++; for (size_t i = state->rows_count - 1; i > state->coord.row + 1; i--) - state->buffer[i].length = u32_strcpy(state->buffer[i].text, - state->buffer[i - 1].text); + state->buffer[i].length = u32_strncpy(state->buffer[i].text, + state->buffer[i - 1].text, MAXBUFLINE); state->buffer[state->coord.row + 1].length - = u32_strcpy(state->buffer[state->coord.row + 1].text, - state->buffer[state->coord.row].text + state->coord.col); + = u32_strncpy(state->buffer[state->coord.row + 1].text, + state->buffer[state->coord.row].text + state->coord.col, + MAXBUFLINE); state->buffer[state->coord.row].text[state->coord.col] = 0; state->buffer[state->coord.row].length = state->coord.col; state->dirty = 1; @@ -2057,13 +2195,14 @@ simple_join_lines(struct DrawState* state) if (first_line == state->rows_count - 1) return; - u32_strcat(state->buffer[first_line].text, - state->buffer[first_line + 1].text); + u32_strncat(state->buffer[first_line].text, + state->buffer[first_line + 1].text, MAXBUFLINE); state->buffer[first_line].length = u32_strlen(state->buffer[first_line].text); for (size_t i = first_line + 1; i < state->rows_count - 1; i++) { - u32_strcpy(state->buffer[i].text, state->buffer[i + 1].text); + u32_strncpy(state->buffer[i].text, state->buffer[i + 1].text, + MAXBUFLINE); state->buffer[i].length = state->buffer[i + 1].length; } *state->buffer[state->rows_count - 1].text = 0; @@ -2123,7 +2262,13 @@ simple_yank(struct DrawState* state) if (!newtext) { state->running = 0; - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } } newbuf[row].text = newtext; newbuf[row].length = 0; @@ -2134,12 +2279,13 @@ simple_yank(struct DrawState* state) state->buffer[ssr].text + ssc, sec - ssc + 1); else { - state->paste[0].length = u32_strcpy(state->paste[0].text, - state->buffer[ssr].text + ssc); + state->paste[0].length = u32_strncpy(state->paste[0].text, + state->buffer[ssr].text + ssc, MAXBUFLINE); for (size_t row = 1; row < state->paste_count - 1; row++) state->paste[row].length - = u32_strcpy(state->paste[row].text, - state->buffer[ssr + row].text); + = u32_strncpy(state->paste[row].text, + state->buffer[ssr + row].text, + MAXBUFLINE); state->paste[state->paste_count - 1].length = u32_strncpy(state->paste[state->paste_count - 1].text, state->buffer[ser].text, sec + 1); @@ -2200,22 +2346,42 @@ write_file(struct DrawState* state) switch (result) { case SAVE_ERR_CANT_ALLOC: - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; case SAVE_ERR_CANT_OPEN_FILE: - strcpy(state->error, errors[ERR_CANT_SAVE]); + if (strlcpy(state->error, errors[ERR_CANT_SAVE], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; case SAVE_ERR_CANT_COPY_FILE: - strcpy(state->error, errors[ERR_CANT_COPY]); + if (strlcpy(state->error, errors[ERR_CANT_COPY], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; case SAVE_ERR_CANT_READLINK: case SAVE_ERR_CANT_STAT_FILE: case SAVE_ERR_CANT_SYMLINK: case SAVE_ERR_CANT_UNLINK: - strcpy(state->error, strerror(errno)); + if (strlcpy(state->error, strerror(errno), MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; case SAVE_ERR_NONE: @@ -2358,10 +2524,21 @@ main(int argc, char** argv) /* Backup filename is the target file + suffix if the file to * write is a symlink, otherwise file + suffix */ - strcpy(state.backup_filename, - state.rfn_len > 0 ? state.real_filename - : state.filename); - strcat(state.backup_filename, backup_suffix); + if (strlcpy(state.backup_filename, + state.rfn_len > 0 ? state.real_filename + : state.filename, + MAXPATH) + >= MAXPATH) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } + if (strlcat(state.backup_filename, backup_suffix, MAXPATH) + >= MAXPATH) + { + print_error(1, "strlcat:%d: Overflow", __LINE__); + exit(1); + } #ifdef __OpenBSD__ if (unveil(state.backup_filename, "rwc") < 0) { @@ -2465,7 +2642,13 @@ init_termbox: if (!draw(&state)) { state.running = 0; - strcpy(state.error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state.error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } } tb_present(); result = tb_poll_event(&ev); diff --git a/strlcat.c b/strlcat.c @@ -0,0 +1,54 @@ +/* $OpenBSD: strlcat.c,v 1.9 2019/01/25 00:19:26 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <string.h> + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/strlcpy.c b/strlcpy.c @@ -0,0 +1,49 @@ +/* $OpenBSD: strlcpy.c,v 1.9 2019/01/25 00:19:26 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <string.h> + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} diff --git a/util.c b/util.c @@ -10,6 +10,10 @@ #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) { @@ -34,12 +38,15 @@ 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]; const uint32_t* pus = us; - size_t added = 0; + size_t len; + size_t added = 0; if (!pus) return added; @@ -47,13 +54,19 @@ unicode_string_to_u8(char* s, const uint32_t* us, const size_t max) *s = 0; while (*pus) { - int len = tb_utf8_unicode_to_char(ch, *pus); - if (added + 1 > max) + len = tb_utf8_unicode_to_char(ch, *pus); + if (added + 1 >= max) break; - strncat(s, ch, len); + ch[len] = 0; + if (strlcat(s, ch, max) >= max) + { + utlerrno = UTLERROVFL; + return added; + } added++; pus++; } + utlerrno = UTLERRNONE; return added; } @@ -120,25 +133,13 @@ u32_strchr(const uint32_t* haystack, const uint32_t needle) } size_t -u32_strcpy(uint32_t* to, const uint32_t* from) -{ - const uint32_t* pfrom = from; - size_t copied = 0; - while (*pfrom) - { - *to++ = *pfrom++; - copied++; - } - *to = 0; - return copied; -} - -size_t -u32_strncpy(uint32_t* to, const uint32_t* from, size_t max) +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 - 1) + /* pfrom - from < max - 1 ... except we can't reliably subtract with + * size_t */ + while (*pfrom && pfrom + 1 < max + from) { *to++ = *pfrom++; copied++; @@ -149,41 +150,19 @@ u32_strncpy(uint32_t* to, const uint32_t* from, size_t max) /* * to - u32 string to concatenate to + * max - total combined string size * from - u32 string to concatenate */ size_t -u32_strcat(uint32_t* to, const uint32_t* from) -{ - const uint32_t* pfrom = from; - size_t copied = 0; - while (*to) - { - to++; - copied++; - } - while (*pfrom) - { - *to++ = *pfrom++; - copied++; - } - *to = 0; - return copied; -} - -/* - * to - u32 string to concatenate to - * from - u32 string to concatenate - * max - total combined string size */ -size_t -u32_strncat(uint32_t* to, const uint32_t* from, size_t max) +u32_strncat(uint32_t* to, const uint32_t* from, const size_t max) { const uint32_t* pfrom = from; size_t copied = 0; - while (*to) + while (*to && copied + 1 < max) { to++; copied++; } - while (*pfrom && copied < max - 1) + while (*pfrom && copied + 1 < max) { *to++ = *pfrom++; copied++; @@ -193,13 +172,14 @@ u32_strncat(uint32_t* to, const uint32_t* from, size_t max) } size_t -u32_u8_strcpy(uint32_t* to, const char* from) +u32_u8_strncpy(uint32_t* to, const char* from, const size_t max) { - uint32_t* ufrom = calloc(strlen(from) + 1, sizeof(uint32_t)); + uint32_t* ufrom = calloc(max + 1, sizeof(uint32_t)); + size_t len; if (!ufrom) return 0; - u8_string_to_unicode(ufrom, from, strlen(from)); - size_t len = u32_strcpy(to, ufrom); + u8_string_to_unicode(ufrom, from, max); + len = u32_strncpy(to, ufrom, max); free(ufrom); return len; } @@ -248,9 +228,10 @@ u32_starts_with(const uint32_t* s, const uint32_t* with) const char* u8_basename(const char* path) { + const char* ppath; if (!path) return NULL; - const char* ppath = path + strlen(path); + ppath = path + strlen(path); while (ppath != path && *ppath != '/') ppath--; if (*ppath == '/') diff --git a/util.h b/util.h @@ -47,6 +47,8 @@ enum { ACT_WRITING, ACT_READING }; #define UTF8REPMAX 6 #define TB_KEY_CTRL_SPACE 0x00 +extern int utlerrno; + 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); size_t u32_strlen(const uint32_t* s); @@ -54,11 +56,9 @@ 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_strcpy(uint32_t* to, const uint32_t* from); -size_t u32_strncpy(uint32_t* to, const uint32_t* from, size_t max); -size_t u32_strcat(uint32_t* to, const uint32_t* from); -size_t u32_strncat(uint32_t* to, const uint32_t* from, size_t max); -size_t u32_u8_strcpy(uint32_t* to, const char* from); +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);