чување 6af51bef1e77845f5b594a2745e9507a6f903964
родитељ 5b714fe1a1acb107e15fba2477c5f23956fe391d
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Sat, 2 Nov 2024 09:35:09 +0100
Overhaul and optimize error handling; avoid free on alloc errors
Diffstat:
| M | TODO | | | 7 | ------- |
| M | TODO.done | | | 9 | +++++++++ |
| M | draw.c | | | 34 | +++++++++++++++------------------- |
| M | draw.h | | | 10 | +++++----- |
| M | sled.1.in | | | 22 | ++++++++++++++++++---- |
| M | sled.c | | | 415 | ++++++++++++++++++++++++++----------------------------------------------------- |
| M | termbox.h | | | 27 | ++++++++++++++++----------- |
| M | util.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);