sled

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

чување 6af51bef1e77845f5b594a2745e9507a6f903964
родитељ 5b714fe1a1acb107e15fba2477c5f23956fe391d
Аутор: Страхиња Радић <sr@strahinja.org>
Датум:   Sat,  2 Nov 2024 09:35:09 +0100

Overhaul and optimize error handling; avoid free on alloc errors

Diffstat:
MTODO | 7-------
MTODO.done | 9+++++++++
Mdraw.c | 34+++++++++++++++-------------------
Mdraw.h | 10+++++-----
Msled.1.in | 22++++++++++++++++++----
Msled.c | 415++++++++++++++++++++++++++-----------------------------------------------------
Mtermbox.h | 27++++++++++++++++-----------
Mutil.h | 45+++++++++++++++++++++------------------------
измењених датотека: 8, додавања: 221(+), брисања: 348(-)

diff --git a/TODO b/TODO @@ -1,13 +1,6 @@ TODO ==== -[ ] Reconsider state.error; it might be better to store only the errno code a la - errno - - Should tb_shutdown be called if malloc failed? It deallocates memory, - potentially messing everything up - - Maybe it would be better to just bail out, leaving the - terminal as-is - [~] Code optimization (struct coord...) diff --git a/TODO.done b/TODO.done @@ -1,6 +1,15 @@ Done or canceled todos ====================== +[x] Reconsider state.error; it might be better to store only the errno code a la + errno + - Should tb_shutdown be called if malloc failed? It deallocates memory, + potentially messing everything up + - Maybe it would be better to just bail out, leaving the + terminal as-is + - Yes (added the parameter deallocate). + - Done. + [x] Fix removing blank lines when wrapping selected text containing multiple paragraphs diff --git a/draw.c b/draw.c @@ -60,18 +60,15 @@ static const char* mode_labels[] = { [SELECTION_MODE] = "SELECTION" }; const char* errors[] = { + [ERR_BINARY] = "Not opening a binary file", + [ERR_NOTREG_FILE] = "'%s' is not a regular file", [ERR_UNKNOWN_KEY] = "Unknown key (press F1 for help)", [ERR_EXIT_KEY] = "Press C-Q to quit", [ERR_DLG_OPEN] = "Press Esc to close dialog or C-Q to quit", [ERR_DLG_OPEN_QUIT] = "Press Esc to close dialog", - [ERR_CANT_ALLOC] = "Memory allocation failed", - [ERR_CANT_SAVE] = "File is not writeable", - [ERR_CANT_OPEN] = "Cannot read file", - [ERR_CANT_COPY] = "Cannot create the backup file", [ERR_INPUT_NONNUM] = "Input must be numerical", [ERR_INVALID_NUM] = "Invalid input", - [ERR_NOT_IMP] = "Function not implemented/configured", - [ERR_BINARY] = "Not opening a binary file"}; + [ERR_NOT_IMP] = "Function not implemented/configured"}; const char* actions[] = { [ACT_WRITING] = "Writing...", [ACT_READING] = "Reading...", @@ -463,20 +460,20 @@ draw_status(const struct DrawState* state) NULL, 0, 0, 0, 0, 0, 0)) return 1; } - else if (state->action && *state->action) + else if (state->action) { if (draw_string(0, state->maxy - 1, colors[C_ACTION].fg, - colors[C_ACTION].bg, state->action, - strlen(state->action) + 2, maxx, 1, 1, CENTER, 0, 1, - NULL, 0, 0, 0, 0, 0, 0)) + colors[C_ACTION].bg, actions[state->action], + strlen(actions[state->action]) + 2, maxx, 1, 1, + CENTER, 0, 1, NULL, 0, 0, 0, 0, 0, 0)) return 1; } - else if (state->error && *state->error) + else if (state->error) { if (draw_string(0, state->maxy - 1, colors[C_ERROR].fg, - colors[C_ERROR].bg, state->error, - strlen(state->error) + 2, maxx, 1, 1, CENTER, 0, 1, - NULL, 0, 0, 0, 0, 0, 0)) + colors[C_ERROR].bg, errors[state->error], + strlen(errors[state->error]) + 2, maxx, 1, 1, + CENTER, 0, 1, NULL, 0, 0, 0, 0, 0, 0)) return 1; } else @@ -701,13 +698,12 @@ init_coord(struct Coord* c, const int col, const int row) } void -init_drawstate(struct DrawState* state, char* error, char* action, - char* filename, char* prompt, const int skip_paste_and_mode_init, - const int skip_filenames_init) +init_drawstate(struct DrawState* state, char* filename, char* prompt, + const int skip_paste_and_mode_init, const int skip_filenames_init) { assert(state != NULL); - state->error = error; - state->action = action; + state->error = ERR_NONE; + state->action = ACT_IDLE; if (!skip_filenames_init) { state->filename = filename; diff --git a/draw.h b/draw.h @@ -1,6 +1,7 @@ /* This program is licensed under the terms of GNU GPL v3 or (at your option) * any later version. Copyright (C) 2022-2024 Страхиња Радић. * See the file LICENSE for exact copyright and license details. */ + #include <stddef.h> #include <sys/types.h> #include <termios.h> @@ -76,9 +77,7 @@ struct BufferLine { }; struct DrawState { - char* error; char* prompt; - char* action; char* filename; char* orig_real_filename; /* what symlink points to */ char* real_filename; /* directory holding the symlink prepended to it */ @@ -86,6 +85,8 @@ struct DrawState { ssize_t rfn_len; uint32_t* input; uint32_t* search; + int error; + int action; int chain_dialog; /* show input dialogs in sequence? */ struct BufferLine* buffer; ssize_t buffer_size; /* buffer parameter */ @@ -167,9 +168,8 @@ void free_drawstate(struct DrawState* state, const int skip_paste_free, const int skip_filename_free); void init_bufferline(struct BufferLine* bl); void init_coord(struct Coord* c, const int col, const int row); -void init_drawstate(struct DrawState* state, char* error, char* action, - char* filename, char* prompt, const int skip_paste_and_mode_init, - const int skip_filenames_init); +void init_drawstate(struct DrawState* state, char* filename, char* prompt, + const int skip_paste_and_mode_init, const int skip_filenames_init); void recalculate_line_numbers(struct DrawState* state); void recalculate_size(struct DrawState* state); void redraw_status(struct DrawState* state); diff --git a/sled.1.in b/sled.1.in @@ -188,6 +188,19 @@ Fifth segment shows quick help. . .Sh EXIT STATUS .Ex -std +.Pp +For errors caused by the unsuccessful calls to libc functions setting +.Va errno , +that value is returned as the exit status. +Otherwise, the exit status is one of the following: +.Bl -tag -width Ds -offset indent -compact +.It Li 201 +File is a binary file and +.Dv open_binary +is set to zero. +.It Li 202 +File is not a regular file. +.El . .Sh AUTHORS .An Strahinya Radich Aq Mt sr@strahinja.org , @@ -214,8 +227,9 @@ If backup creation is enabled .Pq Dv create_backups No in Pa config.h , the directory of the edited file must be writable by the user to open the file. .It -Opening binary files (containing NUL bytes) while -.Dv open_binary -is set to a nonzero value can lead to an incorrectly drawn display. -This was the reason for introducing that option, by default set to zero. +Opening binary files (containing NUL bytes) can lead to an incorrectly drawn +display. +This was the reason for introducing the option +.Dv open_binary , +by default set to zero. .El diff --git a/sled.c b/sled.c @@ -40,24 +40,6 @@ ((state->sel_start.row != state->sel_end.row) \ || (state->sel_start.col != state->sel_end.col)) -enum { - LOAD_ERR_NONE = 0, - LOAD_ERR_CANT_ALLOC = 1, - LOAD_ERR_CANT_OPEN_FILE = 2, - LOAD_ERR_BINARY = 3 -}; - -enum { - SAVE_ERR_NONE = 0, - SAVE_ERR_CANT_ALLOC = 1, - SAVE_ERR_CANT_OPEN_FILE = 2, - SAVE_ERR_CANT_COPY_FILE = 3, - SAVE_ERR_CANT_STAT_FILE = 4, - SAVE_ERR_CANT_READLINK = 5, - SAVE_ERR_CANT_SYMLINK = 6, - SAVE_ERR_CANT_UNLINK = 7 -}; - extern const char* errors[]; extern const char* actions[]; extern const char* mode_labels[]; @@ -71,21 +53,18 @@ extern const char* search_dialog_title; static int cancel_close(struct DrawState* state) { - char* temp = NULL; - assert(state != NULL); - if (!*state->error && !IN(state->mode, M_PROMPT) + if (!state->error && !IN(state->mode, M_PROMPT) && !IN(state->mode, M_HELP)) { if (SEL_NOT_EMPTY(state)) clear_selection(state); else - MEMCCPY(state->error, errors[ERR_EXIT_KEY], - LINE_DEFAULT, temp); + state->error = ERR_EXIT_KEY; } else { - *state->error = 0; + state->error = ERR_NONE; *state->prompt = 0; CLEAR(state->mode, M_PROMPT | M_HELP); } @@ -115,6 +94,7 @@ cp(const char* from, const char* to) int nread = 0; int nwritten = 0; int result; + int saved_errno; assert((from != NULL) && (to != NULL)); fromfd = open(from, O_RDONLY); @@ -159,9 +139,10 @@ cp(const char* from, const char* to) result = 1; cp_cleanup: + saved_errno = errno; close(tofd); close(fromfd); - + errno = saved_errno; return result; } @@ -176,7 +157,7 @@ create_file(struct DrawState* state) if (!newchunk) { state->running = 0; - return LOAD_ERR_CANT_ALLOC; + return 1; } for (ssize_t row = 0; row < ALLOC_DELTA; row++) { @@ -185,7 +166,7 @@ create_file(struct DrawState* state) if (!newtext) { state->running = 0; - return LOAD_ERR_CANT_ALLOC; + return 1; } newchunk[row].size = LINE_DEFAULT; newchunk[row].text = newtext; @@ -197,7 +178,7 @@ create_file(struct DrawState* state) state->coord.row = 0; state->dirty = 1; - return LOAD_ERR_NONE; + return 0; } static int @@ -329,8 +310,6 @@ do_search_replace(struct DrawState* state) return 0; do_search_replace_alloc_error: - free(buf); - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, temp); state->running = 0; return 1; } @@ -428,7 +407,6 @@ erase_line(struct DrawState* state) struct BufferLine* current = NULL; struct BufferLine* next = NULL; uint32_t* ptext = NULL; - char* temp = NULL; assert(state != NULL); if (state->rows_count == 1) @@ -455,7 +433,6 @@ erase_line(struct DrawState* state) return 0; erase_line_error: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, temp); state->running = 0; return 1; } @@ -622,7 +599,7 @@ exit_program(struct DrawState* state) } else state->running = 0; - *state->error = 0; + state->error = ERR_NONE; return 0; } @@ -683,7 +660,6 @@ go_to_line_callback(struct DrawState* state) ssize_t lineno = 0; ssize_t len = 0; char* u8_input = NULL; - char* temp = NULL; assert(state != NULL); if (*state->input) @@ -692,8 +668,6 @@ go_to_line_callback(struct DrawState* state) u8_input = calloc(len + 1, UTF8REPMAX); if (!u8_input) { - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); state->running = 0; return 1; } @@ -701,9 +675,8 @@ go_to_line_callback(struct DrawState* state) errno = 0; lineno = strtoul(u8_input, NULL, 10); if (errno) - MEMCCPY(state->error, errors[ERR_INVALID_NUM], - LINE_DEFAULT, temp); - if (!*state->error) + state->error = ERR_INVALID_NUM; + if (!state->error) { if (lineno > state->rows_count - 1) lineno = state->rows_count; @@ -714,7 +687,7 @@ go_to_line_callback(struct DrawState* state) } free(u8_input); } - if (!*state->error) + if (!state->error) state->input_callback = NULL; return 0; } @@ -723,10 +696,9 @@ static void handle_key_event(struct tb_event* ev, struct DrawState* state) { const struct Key* current = NULL; - char* temp = NULL; - assert((state != NULL) && (ev != NULL) && (state->error != NULL)); - *state->error = 0; + assert((state != NULL) && (ev != NULL)); + state->error = ERR_NONE; if (IN(state->mode, M_PROMPT)) { @@ -770,8 +742,7 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) || !IN(state->mode, M_INPUT_NUM)) input_insert_char(state, ev->ch); else - MEMCCPY(state->error, errors[ERR_INPUT_NONNUM], - LINE_DEFAULT, temp); + state->error = ERR_INPUT_NONNUM; return; } } @@ -788,7 +759,7 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) if (IN(state->mode, M_HELP)) { - MEMCCPY(state->error, errors[ERR_DLG_OPEN], LINE_DEFAULT, temp); + state->error = ERR_DLG_OPEN; return; } @@ -838,16 +809,16 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) } } - MEMCCPY(state->error, errors[ERR_UNKNOWN_KEY], LINE_DEFAULT, temp); + state->error = ERR_UNKNOWN_KEY; } static int input_cancel(struct DrawState* state) { - assert((state != NULL) && (state->error != NULL)); - if (*state->error) + assert(state != NULL); + if (state->error) { - *state->error = 0; + state->error = ERR_NONE; return 0; } *state->input = 0; @@ -865,7 +836,7 @@ input_enter(struct DrawState* state) { int hide_dialog = 1; - assert((state != NULL) && (state->error != NULL)); + assert(state != NULL); if (state->input_callback) { state->input_callback(state); @@ -873,7 +844,7 @@ input_enter(struct DrawState* state) || !state->chain_dialog || *state->input != 0); if (hide_dialog) { - if (!*state->error) + if (!state->error) CLEAR(state->mode, M_INPUT | M_INPUT_NUM); state->input_callback = NULL; } @@ -1096,7 +1067,6 @@ insert_char(struct DrawState* state, uint32_t ch) { struct BufferLine* buffer_line = NULL; uint32_t* ptext = NULL; - char* temp = NULL; ssize_t i; ssize_t len; ssize_t size; @@ -1165,7 +1135,6 @@ insert_skip_wrap: return 0; insert_char_error: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, temp); state->running = 0; return 1; } @@ -1235,7 +1204,6 @@ join_lines(struct DrawState* state) struct BufferLine* current = NULL; struct BufferLine* next = NULL; uint32_t* ptext = NULL; - char* temp = NULL; /* Selection start row/col */ int ssr = 0; int ssc = 0; @@ -1298,7 +1266,6 @@ join_lines(struct DrawState* state) return 0; join_lines_error: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, temp); state->running = 0; return 1; } @@ -1318,25 +1285,16 @@ load_file(struct DrawState* state) assert(state != NULL); input_line = calloc(input_size, 1); if (!input_line) - { - state->running = 0; goto load_file_alloc_error; - } newchunk = calloc(ALLOC_DELTA, sizeof(struct BufferLine)); if (!newchunk) - { - state->running = 0; goto load_file_alloc_error; - } for (ssize_t row = 0; row < ALLOC_DELTA; row++) { init_bufferline(newchunk + row); newtext = calloc(LINE_DEFAULT, sizeof(uint32_t)); if (!newtext) - { - state->running = 0; goto load_file_alloc_error; - } newchunk[row].size = LINE_DEFAULT; newchunk[row].text = newtext; } @@ -1347,7 +1305,10 @@ load_file(struct DrawState* state) input = fopen(state->filename, "rt"); if (!input) - return LOAD_ERR_CANT_OPEN_FILE; + return 1; + + state->action = ACT_READING; + redraw_status(state); while (!feof(input)) { @@ -1361,7 +1322,10 @@ load_file(struct DrawState* state) *eol = 0; nulbyte = strchr(input_line, 0); if (!open_binary && nulbyte && (nulbyte != eol)) - goto load_file_binary; + { + state->error = ERR_BINARY; + return 1; + } if (state->rows_count + 1 == state->buffer_size) { @@ -1369,10 +1333,7 @@ load_file(struct DrawState* state) newchunk = realloc(state->buffer, state->buffer_size * sizeof(struct BufferLine)); if (!newchunk) - { - state->running = 0; goto load_file_alloc_error; - } state->buffer = newchunk; for (ssize_t row = state->buffer_size - ALLOC_DELTA; row < state->buffer_size; row++) @@ -1380,10 +1341,7 @@ load_file(struct DrawState* state) init_bufferline(state->buffer + row); newtext = calloc(LINE_DEFAULT, sizeof(uint32_t)); if (!newtext) - { - state->running = 0; goto load_file_alloc_error; - } state->buffer[row].size = LINE_DEFAULT; state->buffer[row].text = newtext; } @@ -1399,21 +1357,16 @@ load_file(struct DrawState* state) state->rows_count++; } fclose(input); - *state->action = 0; + state->action = ACT_IDLE; if (state->rows_count == 0) state->rows_count++; free(input_line); - return LOAD_ERR_NONE; + return 0; load_file_alloc_error: - free(input_line); - return LOAD_ERR_CANT_ALLOC; - -load_file_binary: - free(input_line); - return LOAD_ERR_BINARY; + return 1; } static int @@ -1594,7 +1547,7 @@ next_match(struct DrawState* state) if (!state->search || !*state->search) return 0; - *state->error = 0; + state->error = ERR_NONE; for (ssize_t row = state->coord.row; row < state->rows_count; row++) { current = state->buffer + row; @@ -1626,7 +1579,6 @@ paste_from_paste(struct DrawState* state) uint32_t* newtext = NULL; uint32_t* ptext = NULL; uint32_t* rest = NULL; - char* temp = NULL; ssize_t newsize = 0; ssize_t rest_size = 0; @@ -1669,8 +1621,6 @@ paste_from_paste(struct DrawState* state) if (!newtext) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, - temp); goto paste_from_paste_cleanup; } U32_MEMCCPY(newtext, line->text, state->coord.col + 1, ptext); @@ -1699,8 +1649,6 @@ paste_from_paste(struct DrawState* state) if (!rest) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); goto paste_from_paste_cleanup; } U32_MEMCCPY(rest, line->text + state->coord.col, rest_size, @@ -1930,7 +1878,7 @@ prev_match(struct DrawState* state) if (!state->search || !*state->search) return 0; - *state->error = 0; + state->error = ERR_NONE; row = state->coord.row; while (1) @@ -2009,38 +1957,20 @@ reread_callback(struct DrawState* state, struct tb_event* ev) static int reread_file(struct DrawState* state) { - int result; - char* temp = NULL; - assert(state != NULL); free_drawstate(state, 1, 1); - init_drawstate(state, state->error, state->action, state->filename, - state->prompt, 1, 1); + init_drawstate(state, state->filename, state->prompt, 1, 1); - MEMCCPY(state->action, actions[ACT_READING], LINE_DEFAULT, temp); redraw_status(state); - result = load_file(state); - switch (result) + if (load_file(state)) { - case LOAD_ERR_CANT_ALLOC: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, - temp); - state->running = 0; - break; - case LOAD_ERR_CANT_OPEN_FILE: - MEMCCPY(state->error, errors[ERR_CANT_OPEN], LINE_DEFAULT, temp); - state->running = 0; - break; - case LOAD_ERR_BINARY: - MEMCCPY(state->error, errors[ERR_BINARY], LINE_DEFAULT, temp); - errno = LOAD_ERR_BINARY; state->running = 0; - break; - default: - recalculate_line_numbers(state); + return state->error; } - return result; + + recalculate_line_numbers(state); + return 0; } static int @@ -2067,15 +1997,13 @@ save_file(struct DrawState* state) struct stat st; char* buf = NULL; char* pbuf = NULL; - char* temp = NULL; ssize_t bufsize = LINE_DEFAULT; - int result = SAVE_ERR_NONE; assert(state != NULL); if (!(buf = calloc(bufsize, 1))) - return SAVE_ERR_CANT_ALLOC; + goto save_file_alloc_error; - MEMCCPY(state->action, actions[ACT_WRITING], LINE_DEFAULT, temp); + state->action = ACT_WRITING; redraw_status(state); errno = 0; @@ -2085,9 +2013,9 @@ save_file(struct DrawState* state) if (!backup_fail && !state->backup_possible) goto save_skip_backup_copy; - if (unlink(state->backup_filename) < 0 && errno != ENOENT) + if ((unlink(state->backup_filename) < 0) && (errno != ENOENT)) { - result = SAVE_ERR_CANT_UNLINK; + state->error = ERR_ERRNO_SET; goto save_file_cleanup; } if (cp(state->rfn_len > 0 ? state->real_filename : state->filename, @@ -2095,7 +2023,7 @@ save_file(struct DrawState* state) { if (backup_fail) { - result = SAVE_ERR_CANT_COPY_FILE; + state->error = ERR_ERRNO_SET; goto save_file_cleanup; } else @@ -2107,7 +2035,7 @@ save_skip_backup_copy: : state->filename, "w"))) { - result = SAVE_ERR_CANT_OPEN_FILE; + state->error = ERR_ERRNO_SET; goto save_file_cleanup; } @@ -2118,7 +2046,7 @@ save_skip_backup_copy: &st) < 0) { - result = SAVE_ERR_CANT_STAT_FILE; + state->error = ERR_ERRNO_SET; goto save_file_cleanup; } @@ -2129,12 +2057,12 @@ save_skip_backup_copy: { if (unlink(state->filename) == -1) { - result = SAVE_ERR_CANT_UNLINK; + state->error = ERR_ERRNO_SET; goto save_file_cleanup; } if (symlink(state->orig_real_filename, state->filename) == -1) { - result = SAVE_ERR_CANT_SYMLINK; + state->error = ERR_ERRNO_SET; goto save_file_cleanup; } } @@ -2160,14 +2088,16 @@ save_skip_backup_symlink: goto save_file_cleanup; save_file_alloc_error: - result = SAVE_ERR_CANT_ALLOC; + if (output) + fclose(output); + return 1; save_file_cleanup: if (output) fclose(output); free(buf); - *state->action = 0; - return result; + state->action = ACT_IDLE; + return state->error; } static int @@ -2175,7 +2105,7 @@ search_dialog_callback(struct DrawState* state) { assert(state != NULL); next_match(state); - if (!*state->error) + if (!state->error) state->input_callback = NULL; return 0; } @@ -2188,7 +2118,7 @@ search_replace_replace_dialog_callback(struct DrawState* state) *state->search = 0; /*u32_strcpy(state->search, state->input); next_match(state);*/ - if (!*state->error) + if (!state->error) state->input_callback = NULL; state->chain_dialog = 0; return 0; @@ -2199,7 +2129,7 @@ search_replace_search_dialog_callback(struct DrawState* state) { assert(state != NULL); /*next_match(state);*/ - if (!*state->error) + if (!state->error) state->input_callback = NULL; *state->input = 0; show_replace(state); @@ -2217,8 +2147,6 @@ search_update_callback(struct DrawState* state) static int show_go_to_line(struct DrawState* state) { - char* temp = NULL; - assert(state != NULL); state->input_title = (char*)go_to_dialog_title; state->input_callback = go_to_line_callback; @@ -2227,14 +2155,12 @@ show_go_to_line(struct DrawState* state) if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); - return 0; + return 1; } } SET(state->mode, M_INPUT | M_INPUT_NUM); *state->input = 0; - *state->error = 0; + state->error = ERR_NONE; input_position_to(state, 0); return 0; } @@ -2244,15 +2170,13 @@ show_help(struct DrawState* state) { assert(state != NULL); SET(state->mode, M_HELP); - *state->error = 0; + state->error = ERR_NONE; return 0; } static int show_replace(struct DrawState* state) { - char* temp = NULL; - assert(state != NULL); state->input_title = (char*)replace_dialog_title; state->input_callback = search_replace_replace_dialog_callback; @@ -2262,15 +2186,13 @@ show_replace(struct DrawState* state) if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); - return 0; + return 1; } } *state->input = 0; SET(state->mode, M_INPUT); CLEAR(state->mode, M_INPUT_NUM); - *state->error = 0; + state->error = ERR_NONE; input_position_to(state, 0); return 0; } @@ -2278,17 +2200,13 @@ show_replace(struct DrawState* state) static int show_search(struct DrawState* state) { - char* temp = NULL; - assert(state != NULL); if (!state->search) { if (!(state->search = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); - return 0; + return 1; } } *state->search = 0; @@ -2300,15 +2218,13 @@ show_search(struct DrawState* state) if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); - return 0; + return 1; } } *state->input = 0; SET(state->mode, M_INPUT); CLEAR(state->mode, M_INPUT_NUM); - *state->error = 0; + state->error = ERR_NONE; input_position_to(state, 0); return 0; } @@ -2316,17 +2232,13 @@ show_search(struct DrawState* state) static int show_search_replace(struct DrawState* state) { - char* temp = NULL; - assert(state != NULL); if (!state->search) { if (!(state->search = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); - return 0; + return 1; } } *state->search = 0; @@ -2338,16 +2250,14 @@ show_search_replace(struct DrawState* state) if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t)))) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); - return 0; + return 1; } } *state->input = 0; state->chain_dialog = 1; SET(state->mode, M_INPUT); CLEAR(state->mode, M_INPUT_NUM); - *state->error = 0; + state->error = ERR_NONE; input_position_to(state, 0); return 0; } @@ -2358,7 +2268,6 @@ simple_insert_line(struct DrawState* state) struct BufferLine* newchunk = NULL; struct BufferLine* line = NULL; uint32_t* ptext = NULL; - char* temp = NULL; assert(state != NULL); if (state->rows_count + 1 == state->buffer_size) @@ -2369,8 +2278,6 @@ simple_insert_line(struct DrawState* state) if (!newchunk) { state->running = 0; - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); return; } state->buffer = newchunk; @@ -2414,7 +2321,6 @@ simple_insert_line(struct DrawState* state) return; simple_insert_line_error: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, temp); state->running = 0; return; } @@ -2425,7 +2331,6 @@ simple_join_lines(struct DrawState* state) struct BufferLine* first_line = NULL; struct BufferLine* next_line = NULL; uint32_t* ptext = NULL; - char* temp = NULL; assert(state != NULL); if ((state->coord.row + 1) == state->rows_count) @@ -2455,7 +2360,6 @@ simple_join_lines(struct DrawState* state) return; simple_join_lines_error: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, temp); state->running = 0; return; } @@ -2465,7 +2369,6 @@ simple_yank(struct DrawState* state) { struct BufferLine* newbuf = NULL; uint32_t* ptext = NULL; - char* temp = NULL; ssize_t initialize_start; /* Selection start row/col */ int ssr = 0; @@ -2550,7 +2453,6 @@ simple_yank(struct DrawState* state) return; simple_yank_alloc_error: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, temp); state->running = 0; return; } @@ -2614,7 +2516,6 @@ wrap_para(struct DrawState* state) struct BufferLine* current = NULL; struct BufferLine* next = NULL; uint32_t* ptext = NULL; - char* temp = NULL; int sel; int start_row; int end_row; @@ -2630,7 +2531,7 @@ wrap_para(struct DrawState* state) sel = SEL_NOT_EMPTY(state); - MEMCCPY(state->action, actions[ACT_WRAPPING], LINE_DEFAULT, temp); + state->action = ACT_WRAPPING; redraw_status(state); if (sel) @@ -2876,18 +2777,15 @@ wrap_finish: else position_to(state, cur_row, 0); - *state->action = 0; - goto wrap_success; - -wrap_not_enabled: - MEMCCPY(state->error, errors[ERR_NOT_IMP], LINE_DEFAULT, temp); - -wrap_success: + state->action = ACT_IDLE; recalculate_line_numbers(state); return 0; +wrap_not_enabled: + state->error = ERR_NOT_IMP; + return 1; + wrap_alloc_error: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, temp); state->running = 0; return 1; } @@ -2895,41 +2793,16 @@ wrap_alloc_error: static int write_file(struct DrawState* state) { - int result; - char* temp = NULL; - assert(state != NULL); - result = save_file(state); - switch (result) + if (save_file(state)) { - case SAVE_ERR_CANT_ALLOC: - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], LINE_DEFAULT, - temp); - state->running = 0; - break; - case SAVE_ERR_CANT_OPEN_FILE: - MEMCCPY(state->error, errors[ERR_CANT_SAVE], LINE_DEFAULT, temp); state->running = 0; - break; - case SAVE_ERR_CANT_COPY_FILE: - MEMCCPY(state->error, errors[ERR_CANT_COPY], LINE_DEFAULT, temp); - 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: - MEMCCPY(state->error, strerror(errno), LINE_DEFAULT, temp); - state->running = 0; - break; - case SAVE_ERR_NONE: - *state->error = 0; - state->dirty = 0; - break; - default:; + return 1; } - return result; + state->error = ERR_NONE; + state->dirty = 0; + return 0; } static int @@ -2946,8 +2819,6 @@ main(int argc, char** argv) struct tb_event ev; struct DrawState state; struct stat st; - char error[LINE_DEFAULT]; - char action[LINE_DEFAULT]; char prompt[LINE_DEFAULT]; char* filename = NULL; char* wd = NULL; @@ -2959,9 +2830,8 @@ main(int argc, char** argv) int result = 0; int dir_access; int dir_access_errno; + int saved_errno; - *error = 0; - *action = 0; *prompt = 0; #ifdef __OpenBSD__ @@ -3041,18 +2911,18 @@ main(int argc, char** argv) return print_error(EINVAL, "No filename given"); } - init_drawstate(&state, error, action, filename, prompt, 0, 0); + init_drawstate(&state, filename, prompt, 0, 0); #ifdef __OpenBSD__ if (unveil(state.filename, "rwc") < 0) { perror(PROGRAM_NAME ": unveil"); - goto main_cleanup; + goto main_done; } if (unveil(dir, "rwc") < 0) { perror(PROGRAM_NAME ": unveil"); - goto main_cleanup; + goto main_done; } #endif @@ -3062,18 +2932,18 @@ main(int argc, char** argv) if (!(wd = malloc(limits[L_PATH_MAX]))) { perror(PROGRAM_NAME ": malloc"); - goto main_cleanup; + goto main_done; } if (!getcwd(wd, limits[L_PATH_MAX])) { perror(PROGRAM_NAME ": getcwd"); - goto main_cleanup; + goto main_done; } #ifdef __OpenBSD__ if (unveil(wd, "rwc") < 0) { perror(PROGRAM_NAME ": unveil"); - goto main_cleanup; + goto main_done; } #endif @@ -3085,19 +2955,19 @@ main(int argc, char** argv) if (!(rfn = malloc(limits[L_PATH_MAX]))) { perror(PROGRAM_NAME ": malloc"); - goto main_cleanup; + goto main_done; } if (!(state.real_filename = malloc(limits[L_PATH_MAX]))) { perror(PROGRAM_NAME ": malloc"); - goto main_cleanup; + goto main_done; } state.rfn_len = readlink(state.filename, rfn, limits[L_PATH_MAX]); if (state.rfn_len == -1) - goto errno_set; + goto main_done; rfn[state.rfn_len] = 0; @@ -3116,7 +2986,7 @@ main(int argc, char** argv) if (!state.orig_real_filename) { perror(PROGRAM_NAME ": strndup"); - goto main_cleanup; + goto main_done; } MEMCCPY(state.real_filename, dir, @@ -3124,7 +2994,7 @@ main(int argc, char** argv) if (!temp) { print_error(1, "Pathname too long"); - goto main_cleanup; + goto main_done; } *(temp - 1) = '/'; /* overwrite NUL */ rfn_dir_len = temp - state.real_filename - 1; @@ -3140,22 +3010,22 @@ main(int argc, char** argv) if (unveil(state.real_filename, "rwc") < 0) { perror(PROGRAM_NAME ": unveil"); - goto main_cleanup; + goto main_done; } #endif if (stat(state.real_filename, &st) == -1) - goto errno_set; + goto main_done; } } /* We don't error out here on ENOENT to account for new files */ else if (errno == ENOENT) state.new_file = 1; else - goto errno_set; + goto main_done; if (!(state.backup_filename = malloc(limits[L_PATH_MAX]))) { perror(PROGRAM_NAME ": malloc"); - goto main_cleanup; + goto main_done; } /* Backup filename is the target file + suffix if the file to @@ -3176,7 +3046,7 @@ main(int argc, char** argv) if (unveil(state.backup_filename, "rwc") < 0) { perror(PROGRAM_NAME ": unveil"); - goto main_cleanup; + goto main_done; } #endif @@ -3187,7 +3057,7 @@ main_skip_backups: { result = 1; perror(PROGRAM_NAME ": realloc"); - goto main_cleanup; + goto main_done; } dir = pdir; *dir = 0; @@ -3196,7 +3066,7 @@ main_skip_backups: if (unveil(dir, "rwc") < 0) { perror(PROGRAM_NAME ": unveil"); - goto main_cleanup; + goto main_done; } #endif } @@ -3205,7 +3075,7 @@ main_skip_backups: if (unveil(NULL, NULL) < 0) { perror(PROGRAM_NAME ": unveil"); - goto main_cleanup; + goto main_done; } #endif @@ -3221,54 +3091,38 @@ main_skip_backups: if (errno != ENOENT || dir_access == -1) { errno = dir_access_errno; - goto errno_set; - } - result = create_file(&state); - switch (result) - { - case LOAD_ERR_CANT_ALLOC: - result = print_error(result, - "Allocation failed (out of memory?)"); - goto main_cleanup; - default:; + goto main_done; } + if (create_file(&state)) + goto main_done; + goto init_termbox; } + errno = 0; + if (!S_ISREG(st.st_mode)) { - result = print_error(EINVAL, "'%s' is not a regular file", - state.filename); - goto main_cleanup; + state.error = ERR_NOTREG_FILE; + goto main_done; } if (access(state.filename, F_OK | R_OK | W_OK) == -1) - goto errno_set; + goto main_done; if (state.rfn_len > 0 && access(state.real_filename, F_OK | R_OK | W_OK) == -1) - goto errno_set; - - result = load_file(&state); - switch (result) - { - case LOAD_ERR_CANT_ALLOC: - result = print_error(result, - "Allocation failed (out of memory?)"); - goto main_cleanup; - case LOAD_ERR_CANT_OPEN_FILE: - result = print_error(result, "Cannot open file `%s'", filename); - goto main_cleanup; - case LOAD_ERR_BINARY: - result = print_error(result, "Not opening a binary file"); - goto main_cleanup; - default:; - } + goto main_done; + + if (load_file(&state)) + goto main_done; + goto init_termbox; init_termbox: - tb_init(); - *error = 0; + if (tb_init()) + goto main_done; + errno = 0; state.maxx = 0; state.recalculate_size = 1; @@ -3285,8 +3139,7 @@ init_termbox: if (draw(&state)) { state.running = 0; - MEMCCPY(state.error, errors[ERR_CANT_ALLOC], - LINE_DEFAULT, temp); + goto main_done; } tb_present(); result = tb_poll_event(&ev); @@ -3295,23 +3148,29 @@ init_termbox: else if (result == TB_OK && ev.type == TB_EVENT_KEY) handle_key_event(&ev, &state); } - tb_shutdown(); - if (state.error && *state.error) + +main_done: + saved_errno = errno; + + if (errno) + perror(PROGRAM_NAME); + + if (saved_errno == ENOMEM) { - print_error(1, state.error); - goto errno_set; + tb_shutdown(0); + print_error(1, errors[state.error]); + exit(saved_errno); } - goto main_cleanup; - -errno_set: - result = errno; - perror(PROGRAM_NAME); - /* FALLTHROUGH */ -main_cleanup: + tb_shutdown(1); + errno = saved_errno; + if (state.error == ERR_NOTREG_FILE) + print_error(1, errors[state.error], state.filename); + else if (state.error) + print_error(1, errors[state.error]); free_drawstate(&state, 0, 0); free(wd); free(dir); free(rfn); - return result; + return state.error ? CUSTOM_ERROR_START + state.error : saved_errno; } diff --git a/termbox.h b/termbox.h @@ -463,7 +463,7 @@ int tb_init(void); int tb_init_file(const char *path); int tb_init_fd(int ttyfd); int tb_init_rwfd(int rfd, int wfd); -int tb_shutdown(void); +int tb_shutdown(int deallocate); /* Returns the size of the internal back buffer (which is the same as terminal's * window size in rows and columns). The internal buffer can be resized after @@ -1503,7 +1503,7 @@ static int send_clear(void); static int update_term_size(void); static int update_term_size_via_esc(void); static int init_cellbuf(void); -static int tb_deinit(void); +static int tb_deinit(int deallocate); static int load_terminfo(void); static int load_terminfo_from_path(const char *path, const char *term); static int read_terminfo_path(const char *path); @@ -1587,15 +1587,16 @@ int tb_init_rwfd(int rfd, int wfd) { } while (0); if (rv != TB_OK) { - tb_deinit(); + tb_deinit(1); } return rv; } -int tb_shutdown(void) { +/* Change to the original: add deallocate parameter. [SR] */ +int tb_shutdown(int deallocate) { if_not_init_return(); - tb_deinit(); + tb_deinit(deallocate); return TB_OK; } @@ -2356,7 +2357,8 @@ static int init_cellbuf(void) { return TB_OK; } -static int tb_deinit(void) { +/* Change to the original: add deallocate parameter. [SR] */ +static int tb_deinit(int deallocate) { if (global.caps[0] != NULL && global.wfd >= 0) { bytebuf_puts(&global.out, global.caps[TB_CAP_SHOW_CURSOR]); bytebuf_puts(&global.out, global.caps[TB_CAP_SGR0]); @@ -2380,12 +2382,15 @@ static int tb_deinit(void) { if (global.resize_pipefd[0] >= 0) close(global.resize_pipefd[0]); if (global.resize_pipefd[1] >= 0) close(global.resize_pipefd[1]); - cellbuf_free(&global.back); - cellbuf_free(&global.front); - bytebuf_free(&global.in); - bytebuf_free(&global.out); + if (deallocate) + { + cellbuf_free(&global.back); + cellbuf_free(&global.front); + bytebuf_free(&global.in); + bytebuf_free(&global.out); - if (global.terminfo) tb_free(global.terminfo); + if (global.terminfo) tb_free(global.terminfo); + } cap_trie_deinit(&global.cap_trie); diff --git a/util.h b/util.h @@ -53,23 +53,20 @@ fallbackto[fbtolen > 0 ? fbtolen - 1 : 0] = 0; \ } while (0) -#define ENSURE_SIZE(to, temp, tosize, testsize, fromsize, label, type) \ - do \ - { \ - if (!(to) || (tosize) < (testsize)) \ - { \ - temp = realloc(to, (fromsize) * sizeof(type)); \ - if (!temp) \ - { \ - char* ctemp = NULL; \ - state->running = 0; \ - MEMCCPY(state->error, errors[ERR_CANT_ALLOC], \ - LINE_DEFAULT, ctemp); \ - goto label; \ - } \ - tosize = fromsize; \ - to = temp; \ - } \ +#define ENSURE_SIZE(to, temp, tosize, testsize, fromsize, label, type) \ + do \ + { \ + if (!(to) || (tosize) < (testsize)) \ + { \ + temp = realloc(to, (fromsize) * sizeof(type)); \ + if (!temp) \ + { \ + state->running = 0; \ + goto label; \ + } \ + tosize = fromsize; \ + to = temp; \ + } \ } while (0) /* * - Make sure the size of the destination string is large enough to copy, and @@ -99,23 +96,23 @@ U32_MEMCCPY(to, from, fromsize, temp); \ } while (0) +#define CUSTOM_ERROR_START 200 + enum { + ERR_NONE, + ERR_BINARY, + ERR_NOTREG_FILE, ERR_UNKNOWN_KEY, ERR_EXIT_KEY, ERR_DLG_OPEN, ERR_DLG_OPEN_QUIT, - ERR_EMPTY_FILE, - ERR_CANT_ALLOC, - ERR_CANT_SAVE, - ERR_CANT_OPEN, - ERR_CANT_COPY, ERR_INPUT_NONNUM, ERR_INVALID_NUM, ERR_NOT_IMP, - ERR_BINARY + ERR_ERRNO_SET }; -enum { ACT_WRITING, ACT_READING, ACT_WRAPPING }; +enum { ACT_IDLE, ACT_WRITING, ACT_READING, ACT_WRAPPING }; 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);