чување 61f8bd03e533f48a6d2883f733254fc8c711468d
родитељ 8c6c68719557ac042e43fda7974ecdd5478ad8ae
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Tue, 17 Feb 2026 21:16:11 +0100
Continue WIP; str* -> memccpy; Add -B -b -L -W -w
Diffstat:
| M | TODO | | | 19 | +++++++++++++++---- |
| M | config.def.h | | | 39 | ++++++++++++++++++++++++++++++--------- |
| M | draw.c | | | 49 | ++++++++++++++++++++++++++++++++++++++++--------- |
| M | draw.h | | | 13 | +++++++------ |
| M | limit.h | | | 4 | +++- |
| M | po.c | | | 551 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
| M | po.h | | | 52 | +++++++++++++++++----------------------------------- |
| M | poe.1.in | | | 57 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
| M | poe.c | | | 1474 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
| M | poe.h | | | 26 | +++++++++++++++++++------- |
| M | termbox.h | | | 4 | ++++ |
| M | util.c | | | 60 | ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
| M | util.h | | | 123 | +++++++++++++++++++++++++++++++++++-------------------------------------------- |
измењених датотека: 13, додавања: 1477(+), брисања: 994(-)
diff --git a/TODO b/TODO
@@ -4,12 +4,23 @@ TODO
[ ] Support Yudit's nonstandard PO format (no empty lines between individual
entries)
-[ ] Tidy up basic logic everywhere (based on sled)
+[~] Tidy up basic logic everywhere (based on sled)
[ ] Check cleanness against sled, function-by-function
- Last: erase_search_prev_word
- [ ] str* -> memccpy
+ Last: save_msgstr
+ [ ] Investigate insert_char
+ [ ] Revise dirty <-> dirty_before_edit and the interaction with keys
+ [x] Copy join_lines from sled's simple_join_lines
+ [x] str* -> memccpy
[ ] Tidy up return codes and error handling
- [ ] Introduce position_to (sled)
+ [ ] Get rid of SAVE_*
+ [x] Introduce position_to (sled)
+
+[x] Add -B, -b, -L, -W, -w
+ [x] --no-backup
+ [x] --backup
+ [x] --dont-break-literals
+ [x] --no-wrap
+ [x] --wrap-width
< > Wrap long lines? Not if it would complicate the code too much.
diff --git a/config.def.h b/config.def.h
@@ -69,11 +69,12 @@ static const struct Color colors[] = {
extern int backup_fail;
extern char* backup_suffix;
+extern int break_literals;
extern int create_backups;
+extern int literal_break_threshold;
extern int match_msgstr_ending;
extern char* plural_string;
extern int warn_count_dots;
-extern int wrap_first_msgstr;
extern int wrap_width;
#ifdef POE_C_GLOBALS
@@ -83,7 +84,14 @@ extern int wrap_width;
* directory permissions? */
int backup_fail = 1;
char* backup_suffix = "~";
+int break_literals = 1; /* break long literals into an empty string + a
+ * literal on a separate line */
int create_backups = 1; /* comment out to not create backups */
+int literal_break_threshold
+ = 80; /* if "msgid: \"" (or msgstr, etc) + literal are
+ * longer than this, the string will be split
+ * into an empty string + a literal on a
+ * separate line */
int match_msgstr_ending = 1; /* correct the ending of msgstr to
* match msgid if ' ', '.' or '\\n'? */
/* Uncomment/comment the appropriate definition to insert this after
@@ -94,8 +102,7 @@ char* plural_string = NULL;
/*char* plural_string = "nplurals=3; plural=(n%10==1 && n%100!=11 ?"
" 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";*/
int warn_count_dots = 0;
-int wrap_first_msgstr = 0;
-int wrap_width = 70;
+int wrap_width = 77; /* set to 0 to turn off wrap */
/* Always processed */
static const struct Key top_level_keys[] = {
@@ -114,9 +121,11 @@ static const struct Key edit_keys[] = {
.callback = move_right },
{ .ev = { .key = TB_KEY_ARROW_UP },
.callback = move_up },
- { .ev = { .key = TB_KEY_BACKSPACE },
+ { .ev = { .key = TB_KEY_BACKSPACE,
+ .mod = TB_MOD_CTRL },
.callback = erase_backwards },
- { .ev = { .key = TB_KEY_BACKSPACE2 },
+ { .ev = { .key = TB_KEY_BACKSPACE2,
+ .mod = TB_MOD_CTRL },
.callback = erase_backwards },
{ .ev = { .key = TB_KEY_CTRL_A, .mod = TB_MOD_CTRL },
.callback = move_start },
@@ -147,7 +156,9 @@ static const struct Key edit_keys[] = {
{ .ev = { .key = TB_KEY_DELETE },
.callback = erase_forward },
{ .ev = { .key = TB_KEY_END }, .callback = move_end },
- { .ev = { .key = TB_KEY_ENTER },
+ /* Enter = C-M, hence the TB_MOD_CTRL; tb doesn't make a difference
+ * between C-Enter and Enter... */
+ { .ev = { .key = TB_KEY_ENTER, .mod = TB_MOD_CTRL },
.callback = insert_line },
{ .ev = { .key = TB_KEY_F5 }, .callback = copy_msgid_to_input },
{ .ev = { .key = TB_KEY_F6 }, .callback = toggle_info_focused },
@@ -158,7 +169,10 @@ static const struct Key edit_keys[] = {
{ .ev = { .key = TB_KEY_PGUP }, .callback = edit_page_up },
{ .ev = { .key = TB_KEY_SPACE },
.callback = insert_space },
- { .ev = { .key = TB_KEY_TAB }, .callback = insert_tab },
+ /* Tab = C-I, hence the TB_MOD_CTRL; tb doesn't make a difference
+ * between C-I and Tab... */
+ { .ev = { .key = TB_KEY_TAB, .mod = TB_MOD_CTRL },
+ .callback = insert_tab },
};
/* Search box open */
@@ -167,9 +181,11 @@ static const struct Key search_keys[] = {
.callback = move_search_left },
{ .ev = { .key = TB_KEY_ARROW_RIGHT },
.callback = move_search_right },
- { .ev = { .key = TB_KEY_BACKSPACE, .mod = TB_MOD_CTRL },
+ { .ev = { .key = TB_KEY_BACKSPACE,
+ .mod = TB_MOD_CTRL },
.callback = erase_search_backwards },
- { .ev = { .key = TB_KEY_BACKSPACE2, .mod = TB_MOD_CTRL },
+ { .ev = { .key = TB_KEY_BACKSPACE2,
+ .mod = TB_MOD_CTRL },
.callback = erase_search_backwards },
{ .ev = { .key = TB_KEY_CTRL_A, .mod = TB_MOD_CTRL },
.callback = move_search_start },
@@ -205,6 +221,11 @@ static const struct Key search_keys[] = {
.callback = insert_search_tab },
};
+/* Help dialog */
+static const struct Key help_keys[] = {
+ { .ev = { .ch = 'q' }, .callback = exit_program },
+};
+
/* Main window */
static const struct Key main_keys[] = {
{ .ev = { .key = TB_KEY_ARROW_DOWN },
diff --git a/draw.c b/draw.c
@@ -40,6 +40,8 @@ static const char* help[] = {
static const char* editbox_title = "Edit translation";
const char* errors[] = {
[ERR_NO_CL_ARG] = "No filename given",
+ [ERR_NO_CL_ARG_PARAM] = "Option requires an argument: %s",
+ [ERR_BAD_CL_ARG] = "Invalid argument: %s",
[ERR_NOTPO_FILE] = "Not a PO file",
[ERR_NOTREG_FILE] = "'%s' is not a regular file",
[ERR_TB_ERROR] = "termbox error",
@@ -48,7 +50,7 @@ const char* errors[] = {
[ERR_EXIT_KEY] = "Press q or C-Q to quit",
[ERR_DLG_OPEN] = "Press Esc to close dialog or q/C-Q to quit",
[ERR_DLG_OPEN_QUIT] = "Press Esc to close dialog first",
- [ERR_DLG_FOCUS_EDIT] = "Switch to edit box first with F6",
+ [ERR_DLG_FOCUS_EDIT] = "Switch to edit box with F6 or press Esc",
[ERR_EMPTY_FILE] = "No msgids to edit",
[ERR_CANT_ALLOC] = "Memory allocation failed",
[ERR_CANT_SAVE] = "File is not writeable",
@@ -79,6 +81,35 @@ assign_coord(struct Coord* dest, const struct Coord src)
init_coord(dest, src.col, src.row);
}
+/* Calculates buffer length from a display length.
+ * max_index = the display index up to which the length is calculated
+ */
+ssize_t
+buffer_length(uint32_t* buffer, const ssize_t max_index)
+{
+ uint32_t* pbuf = buffer;
+ ssize_t len = 0;
+ ssize_t i;
+ int w;
+
+ if (!pbuf)
+ return 0;
+
+ for (i = 0; *pbuf && len < max_index; i++)
+ {
+ pbuf = buffer + i;
+ if (*pbuf == '\t')
+ len += MIN(TAB_SIZE - (len % TAB_SIZE), max_index - len);
+ else
+ {
+ w = wcwidth((wchar_t)*pbuf);
+ if (w > 0)
+ len += MIN(w, max_index - len);
+ }
+ }
+ return i;
+}
+
int
calculate_edit_width(const struct DrawState* state)
{
@@ -224,8 +255,8 @@ draw_editbox(const struct DrawState* state)
{
struct PoEntry* entry;
char flags_buf[MAXFLAGSBUF];
- char sbuf[MAXBUFLINE];
- ssize_t dlen;
+ char sbuf[LINE_DEFAULT];
+ ssize_t dlen, i;
uint16_t fg, bg;
int startx, endx, starty, endy;
int w, h;
@@ -237,7 +268,6 @@ draw_editbox(const struct DrawState* state)
maxx = state->maxx;
maxy = state->maxy;
entry = state->entries + state->msgid_number - 1;
- dlen = 0;
format_flags(flags_buf, MAXFLAGSBUF, entry, 1);
@@ -259,7 +289,7 @@ draw_editbox(const struct DrawState* state)
: colors[C_EDIT_MSGID].bg;
draw_rect(startx + 1, endx - 1, starty + 1, endy - h / 2 - 1, fg, bg);
- for (ssize_t i = 0; i < (h - 3) / 2 + 1
+ for (i = 0; i < (h - 3) / 2 + 1
&& (ssize_t)state->info_first_shown.row + i
< state->info_rows_count;
i++)
@@ -313,13 +343,14 @@ draw_editbox(const struct DrawState* state)
- state->input_first_shown.row);
if (entry->msgstr_count > 1)
- snprintf(sbuf, MAXBUFLINE, "%d[%d]:%d[%d]/%ld (plural: %d/%d)",
+ snprintf(sbuf, LINE_DEFAULT,
+ "%d[%d]:%d[%d]/%ld (plural: %d/%d)",
state->input_display_column,
state->input_first_shown.col, state->coord.row,
state->input_first_shown.row, state->input_rows_count,
state->msgstr_index + 1, entry->msgstr_count);
else
- snprintf(sbuf, MAXBUFLINE, "%d[%d]:%d[%d]/%ld",
+ snprintf(sbuf, LINE_DEFAULT, "%d[%d]:%d[%d]/%ld",
state->input_display_column,
state->input_first_shown.col, state->coord.row,
state->input_first_shown.row, state->input_rows_count);
@@ -702,7 +733,7 @@ init_drawstate(struct DrawState* state, char* filename, char* prompt)
/*state->info_first_shown_column = 0;
state->info_first_shown_row = 0;*/
state->info_rows_count = 0;
- state->info_rows_maxlen = 0;
+ state->info_maxlen = 0;
state->help_width = calculate_help_width(state);
state->edit_width = calculate_edit_width(state);
state->search_width = calculate_search_width(state);
@@ -801,7 +832,7 @@ set_nplurals(struct DrawState* state, struct PoEntry* entry)
int read_number = 0;
uint32_t* ppf = entry->plural_forms;
- char token[MAXBUFLINE];
+ char token[LINE_DEFAULT];
char* ptoken = token;
*ptoken = 0;
diff --git a/draw.h b/draw.h
@@ -26,7 +26,7 @@
#define SEARCH_WIDTH 20
#define SEARCH_HEIGHT 4
#define TAB_SIZE 8
-#define MAXSEARCH (512 + 1)
+#define MAXSEARCH 512
typedef enum { LEFT, CENTER, RIGHT } Alignment;
@@ -96,7 +96,7 @@ struct DrawState {
int error;
int action;
struct BufferLine* input_buffer; /* edit box */
- ssize_t buffer_size; /* buffer parameter */
+ ssize_t buffer_size; /* buffer parameter */
struct Coord coord; /* buffer coordinates */
struct Coord first_shown; /* display coordinates */
struct Coord input_first_shown; /* display coordinates */
@@ -114,10 +114,10 @@ struct DrawState {
/*int info_first_shown_column;
int info_first_shown_row;*/
int info_rows_count;
- int info_rows_maxlen;
- int help_width; /* display parameter */
- int edit_width; /* display parameter */
- int search_width; /* display parameter */
+ int info_maxlen;
+ int help_width; /* display parameter */
+ int edit_width; /* display parameter */
+ int search_width; /* display parameter */
struct BufferLine* paste;
ssize_t paste_count;
ssize_t paste_size;
@@ -166,6 +166,7 @@ struct StatusSegment {
};
void assign_coord(struct Coord* dest, const struct Coord src);
+ssize_t buffer_length(uint32_t* buffer, const ssize_t max_index);
int calculate_edit_width(const struct DrawState* state);
int calculate_help_width(const struct DrawState* state);
int calculate_search_width(const struct DrawState* state);
diff --git a/limit.h b/limit.h
@@ -20,7 +20,9 @@ extern long limits[];
/* initial line size (not length) */
#define LINE_DEFAULT 85
/* maximum size of field in input dialog */
-#define MAXINPUT (512 + 1)
+#define MAXINPUT 512
+/* fallback buffer size before we determine limits */
+#define PRINT_BUF_MAX_FALLBACK 2048
/* maximum chars for UTF-8 representations of Unicode chars, per Unicode char */
#define UTF8REPMAX 6
diff --git a/po.c b/po.c
@@ -20,8 +20,6 @@
extern const char* errors[];
extern const char* flag_strings[];
-// TODO: Check ifdef PLURAL_ ...
-
extern int cp(const char* from, const char* to);
extern int print_error(const int code, const char* msg, ...);
extern void redraw_status(struct DrawState* state);
@@ -118,94 +116,102 @@ set_flags(struct PoEntry* entry, const Flags flags)
return entry;
}
-struct PoEntry*
-set_msgid(struct PoEntry* entry, const char* msgid, int append)
+int
+set_msgid(struct DrawState* state, struct PoEntry* entry, const char* msgid,
+ int append)
{
uint32_t umsgid[MAXMSGLINE];
- size_t msgid_size = 0;
+ size_t msgid_len = 0;
assert(entry != NULL);
if (msgid)
- msgid_size = u8_string_to_unicode(umsgid, msgid, MAXMSGLINE);
- return u32_set_msgid(entry, umsgid, msgid_size, append);
+ msgid_len = u8_string_to_unicode(umsgid, msgid, MAXMSGLINE);
+ return u32_set_msgid(state, entry, umsgid, msgid_len, append);
}
-struct PoEntry*
-set_msgid_plural(struct PoEntry* entry, const char* msgid_plural, int append)
+int
+set_msgid_plural(struct DrawState* state, struct PoEntry* entry,
+ const char* msgid_plural, int append)
{
uint32_t umsgid_plural[MAXMSGLINE];
- size_t msgid_plural_size = 0;
+ size_t msgid_plural_len = 0;
assert(entry != NULL);
if (msgid_plural)
- msgid_plural_size = u8_string_to_unicode(umsgid_plural,
+ msgid_plural_len = u8_string_to_unicode(umsgid_plural,
msgid_plural, MAXMSGLINE);
- return u32_set_msgid_plural(entry, umsgid_plural, msgid_plural_size,
- append);
+ return u32_set_msgid_plural(state, entry, umsgid_plural,
+ msgid_plural_len, append);
}
-struct PoEntry*
-set_plural_forms(struct PoEntry* entry, const char* plural_forms, int append)
+int
+set_plural_forms(struct DrawState* state, struct PoEntry* entry,
+ const char* plural_forms, int append)
{
uint32_t uplural_forms[MAXMSGLINE];
+ size_t plural_forms_len = 0;
assert(entry != NULL);
if (plural_forms)
- u8_string_to_unicode(uplural_forms, plural_forms, MAXMSGLINE);
- return u32_set_plural_forms(entry, uplural_forms, append);
+ plural_forms_len = u8_string_to_unicode(uplural_forms,
+ plural_forms, MAXMSGLINE);
+ return u32_set_plural_forms(state, entry, uplural_forms,
+ plural_forms_len, append);
}
-struct PoEntry*
-set_msgstr(struct PoEntry* entry, const char* msgstr, int msgstr_index,
- int append, struct DrawState* state)
+int
+set_msgstr(struct DrawState* state, struct PoEntry* entry, const char* msgstr,
+ int msgstr_index, int append)
{
uint32_t umsgstr[MAXMSGLINE];
assert(entry != NULL);
umsgstr[0] = 0;
if (msgstr)
u8_string_to_unicode(umsgstr, msgstr, MAXMSGLINE);
- return u32_set_msgstr(entry, umsgstr, msgstr_index, append, state);
+ return u32_set_msgstr(state, entry, umsgstr, msgstr_index, append);
}
-struct PoEntry*
-u32_set_msgid(struct PoEntry* entry, const uint32_t* msgid, size_t msgid_size,
- int append)
+int
+u32_set_msgid(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgid, size_t msgid_len, int append)
{
- size_t msgid_len = 0;
- /* TODO: Unused? */
- UNUSED(msgid_size);
- if (!entry)
- return NULL;
- if (msgid)
- msgid_len = u32_strlen(msgid);
+ uint32_t* temp = NULL;
+
+ assert((state != NULL) && (entry != NULL));
if (!entry->msgid)
{
entry->msgid_size = MSGDELTA;
entry->msgid_len = 0;
entry->msgid = calloc(entry->msgid_size, sizeof(uint32_t));
+ if (!entry->msgid)
+ goto u32_set_msgid_alloc_error;
}
else if (entry->msgid_len + msgid_len >= entry->msgid_size)
{
entry->msgid_size += MSGDELTA;
- entry->msgid = realloc(entry->msgid,
+ temp = realloc(entry->msgid,
entry->msgid_size * sizeof(uint32_t));
+ if (!temp)
+ goto u32_set_msgid_alloc_error;
+ entry->msgid = temp;
}
entry->msgid_len += msgid_len;
- if (!entry->msgid)
- return NULL;
if (append)
- u32_strncat(entry->msgid, msgid, entry->msgid_size);
+ U32_MEMCCPY(entry->msgid + entry->msgid_len - msgid_len, msgid,
+ entry->msgid_size - msgid_len, temp);
else
- u32_strncpy(entry->msgid, msgid, entry->msgid_size);
- return entry;
+ U32_MEMCCPY(entry->msgid, msgid, entry->msgid_size, temp);
+ return 0;
+
+u32_set_msgid_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
-struct PoEntry*
-u32_set_msgid_plural(struct PoEntry* entry, const uint32_t* msgid_plural,
- size_t msgid_plural_size, int append)
+int
+u32_set_msgid_plural(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgid_plural, size_t msgid_plural_len, int append)
{
- size_t msgid_plural_len = 0;
- /* TODO: Unused? */
- UNUSED(msgid_plural_size);
- if (!entry)
- return NULL;
+ uint32_t* temp = NULL;
+
+ assert((state != NULL) && (entry != NULL));
if (msgid_plural)
msgid_plural_len = u32_strlen(msgid_plural);
if (!entry->msgid_plural)
@@ -214,52 +220,86 @@ u32_set_msgid_plural(struct PoEntry* entry, const uint32_t* msgid_plural,
entry->msgid_plural_len = 0;
entry->msgid_plural
= calloc(entry->msgid_plural_size, sizeof(uint32_t));
+ if (!entry->msgid_plural)
+ goto u32_set_msgid_plural_alloc_error;
}
else if (entry->msgid_plural_size + msgid_plural_len
>= entry->msgid_plural_size)
{
entry->msgid_plural_size += MSGDELTA;
- entry->msgid_plural = realloc(entry->msgid_plural,
+ temp = realloc(entry->msgid_plural,
entry->msgid_plural_size * sizeof(uint32_t));
+ if (!temp)
+ goto u32_set_msgid_plural_alloc_error;
+ entry->msgid_plural = temp;
}
entry->msgid_plural_len += msgid_plural_len;
- if (!entry->msgid_plural)
- return NULL;
if (append)
- u32_strncat(entry->msgid_plural, msgid_plural,
- entry->msgid_plural_size);
+ U32_MEMCCPY(entry->msgid_plural + entry->msgid_plural_len
+ - msgid_plural_len,
+ msgid_plural,
+ entry->msgid_plural_size - msgid_plural_len, temp);
else
- u32_strncpy(entry->msgid_plural, msgid_plural,
- entry->msgid_plural_size);
- return entry;
+ U32_MEMCCPY(entry->msgid_plural, msgid_plural,
+ entry->msgid_plural_size, temp);
+ return 0;
+
+u32_set_msgid_plural_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
-struct PoEntry*
-u32_set_plural_forms(struct PoEntry* entry, const uint32_t* plural_forms,
- int append)
+int
+u32_set_plural_forms(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* plural_forms, const size_t plural_forms_len, int append)
{
- if (!entry)
- return NULL;
+ uint32_t* temp = NULL;
+
+ assert((state != NULL) && (entry != NULL));
+ if (plural_forms_len >= MSGDELTA)
+ return 1;
if (!entry->plural_forms)
{
- entry->plural_forms = calloc(MAXMSGLINE, sizeof(uint32_t));
+ entry->plural_forms_size = MSGDELTA;
+ entry->plural_forms_len = 0;
+ entry->plural_forms = calloc(MAXMSGLINE, sizeof(uint32_t));
if (!entry->plural_forms)
- return NULL;
+ goto u32_set_plural_forms_alloc_error;
+ }
+ else if (entry->plural_forms_size + plural_forms_len
+ >= entry->plural_forms_size)
+ {
+ entry->plural_forms_size += MSGDELTA;
+ temp = realloc(entry->plural_forms,
+ entry->plural_forms_size * sizeof(uint32_t));
+ if (!temp)
+ goto u32_set_plural_forms_alloc_error;
+ entry->plural_forms = temp;
}
+ entry->plural_forms_len += plural_forms_len;
if (append)
- u32_strncat(entry->plural_forms, plural_forms, MAXMSGLINE);
+ U32_MEMCCPY(entry->plural_forms + entry->plural_forms_size
+ - plural_forms_len,
+ plural_forms,
+ entry->plural_forms_size - plural_forms_len, temp);
else
- u32_strncpy(entry->plural_forms, plural_forms, MAXMSGLINE);
- return entry;
+ U32_MEMCCPY(entry->plural_forms, plural_forms,
+ entry->plural_forms_size, temp);
+ return 0;
+
+u32_set_plural_forms_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
-struct PoEntry*
-u32_set_msgstr(struct PoEntry* entry, const uint32_t* msgstr, int msgstr_index,
- int append, struct DrawState* state)
+int
+u32_set_msgstr(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgstr, int msgstr_index, int append)
{
+ uint32_t* temp = NULL;
size_t msgstr_len = 0;
- if (!entry)
- return NULL;
+
+ assert((state != NULL) && (entry != NULL));
if (msgstr)
msgstr_len = u32_strlen(msgstr);
if (entry->msgstr_count == 0 || msgstr_index + 1 > entry->msgstr_count)
@@ -272,10 +312,16 @@ u32_set_msgstr(struct PoEntry* entry, const uint32_t* msgstr, int msgstr_index,
{
newmsgstr = calloc(entry->msgstr_count,
sizeof(uint32_t*));
+ if (!newmsgstr)
+ goto u32_set_msgstr_alloc_error;
newmsgstr_size
= calloc(entry->msgstr_count, sizeof(size_t));
+ if (!newmsgstr_size)
+ goto u32_set_msgstr_alloc_error;
newmsgstr_len
= calloc(entry->msgstr_count, sizeof(size_t));
+ if (!newmsgstr_len)
+ goto u32_set_msgstr_alloc_error;
/* when the .po file is not a standard text file (no LF
* at end) */
if (state->untranslated_count > 0)
@@ -283,32 +329,33 @@ u32_set_msgstr(struct PoEntry* entry, const uint32_t* msgstr, int msgstr_index,
}
else
{
- newmsgstr = realloc(entry->msgstr,
- entry->msgstr_count * sizeof(uint32_t*));
+ newmsgstr = realloc(entry->msgstr,
+ entry->msgstr_count * sizeof(uint32_t*));
+ if (!newmsgstr)
+ goto u32_set_msgstr_alloc_error;
newmsgstr_size = realloc(entry->msgstr_size,
entry->msgstr_count * sizeof(size_t));
- newmsgstr_len = realloc(entry->msgstr_len,
- entry->msgstr_count * sizeof(size_t));
- }
- if (!newmsgstr || !newmsgstr_size || !newmsgstr_len)
- {
- /*free(newmsgstr);
- free(newmsgstr_len);
- free(newmsgstr_size);*/
- return NULL;
+ if (!newmsgstr_size)
+ goto u32_set_msgstr_alloc_error;
+ newmsgstr_len = realloc(entry->msgstr_len,
+ entry->msgstr_count * sizeof(size_t));
+ if (!newmsgstr_len)
+ goto u32_set_msgstr_alloc_error;
}
newmsgstr[msgstr_index] = NULL;
- entry->msgstr = newmsgstr;
- entry->msgstr_size = newmsgstr_size;
- entry->msgstr_len = newmsgstr_len;
+ entry->msgstr = newmsgstr;
+ entry->msgstr_size = newmsgstr_size;
+ entry->msgstr_len = newmsgstr_len;
}
if (!entry->msgstr[msgstr_index])
{
entry->msgstr_size[msgstr_index] = MSGDELTA;
- entry->msgstr_len[msgstr_index] = 0;
+ entry->msgstr_len[msgstr_index] = 0;
entry->msgstr[msgstr_index]
= calloc(entry->msgstr_size[msgstr_index],
sizeof(uint32_t));
+ if (!entry->msgstr[msgstr_index])
+ goto u32_set_msgstr_alloc_error;
}
else if (entry->msgstr_len[msgstr_index] + msgstr_len
>= entry->msgstr_size[msgstr_index])
@@ -318,17 +365,23 @@ u32_set_msgstr(struct PoEntry* entry, const uint32_t* msgstr, int msgstr_index,
= realloc(entry->msgstr[msgstr_index],
entry->msgstr_size[msgstr_index]
* sizeof(uint32_t));
+ if (!entry->msgstr[msgstr_index])
+ goto u32_set_msgstr_alloc_error;
}
entry->msgstr_len[msgstr_index] += msgstr_len;
- if (!entry->msgstr[msgstr_index])
- return NULL;
if (append)
- u32_strncat(entry->msgstr[msgstr_index], msgstr,
- entry->msgstr_size[msgstr_index]);
+ U32_MEMCCPY(entry->msgstr[msgstr_index]
+ + entry->msgstr_len[msgstr_index] - msgstr_len,
+ msgstr, entry->msgstr_size[msgstr_index] - msgstr_len,
+ temp);
else
- u32_strncpy(entry->msgstr[msgstr_index], msgstr,
- entry->msgstr_size[msgstr_index]);
- return entry;
+ U32_MEMCCPY(entry->msgstr[msgstr_index], msgstr,
+ entry->msgstr_size[msgstr_index], temp);
+ return 0;
+
+u32_set_msgstr_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
struct PoEntry*
@@ -466,7 +519,15 @@ load_file(struct DrawState* dstate, long* lineno, long* col)
char* nulbyte = NULL;
if (!fgets(input_line, input_size, input))
- continue;
+ {
+ if (ferror(input))
+ {
+ fclose(input);
+ return 1;
+ }
+ else
+ continue;
+ }
if (possible_nulbyte)
{
@@ -488,8 +549,8 @@ load_file(struct DrawState* dstate, long* lineno, long* col)
possible_nulbyte = 1;
if (parse_po_line(input_line, dstate, &entry, &pstate, col,
- &msgstr_index))
- return 1;
+ &msgstr_index))
+ goto load_file_cleanup;
if (entry && entry->msgid_plural)
has_plural_msgid = 1;
@@ -563,6 +624,8 @@ load_file(struct DrawState* dstate, long* lineno, long* col)
}
load_file_cleanup:
+ if (dstate->error == ERR_CANT_ALLOC)
+ goto load_file_alloc_error;
fclose(input);
dstate->action = ACT_IDLE;
free(input_line);
@@ -696,18 +759,18 @@ save_loop_entries_start:
if (!current->obsolete && current->comment_lines > 0)
if (save_comment(output, state, current))
- return 1;
+ goto save_file_error_cleanup;
if (current->extr_comment_lines > 0)
if (save_extr_comment(output, state, current))
- return 1;
+ goto save_file_error_cleanup;
if (current->ref_comment_lines > 0)
if (save_ref_comment(output, state, current))
- return 1;
+ goto save_file_error_cleanup;
if (save_flags(output, state, current))
- return 1;
+ goto save_file_error_cleanup;
if (current->obsolete && current->comment_lines > 0)
if (save_comment(output, state, current))
- return 1;
+ goto save_file_error_cleanup;
if (current->obsolete)
{
@@ -720,10 +783,10 @@ save_loop_entries_start:
save_msgid(output, state, current);
if (current->msgid_plural)
if (save_msgid_plural(output, state, current))
- return 1;
+ goto save_file_error_cleanup;
if (save_msgstrs(output, state, current))
- return 1;
+ goto save_file_error_cleanup;
if (current < state->entries + state->real_msgid_count - 1)
fprintf(output, "\n");
@@ -735,6 +798,9 @@ save_loop_entries_start:
fclose(output);
return 1;*/
+save_file_error_cleanup:
+ result = 1;
+
save_loop_entries_done:
save_file_cleanup:
saved_errno = errno;
@@ -791,6 +857,7 @@ save_msgid(FILE* output, struct DrawState* state, const struct PoEntry* current)
size_t len = 0;
size_t num_lines;
size_t size;
+ int first_line = 1;
assert((output != NULL) && (state != NULL) && (current != NULL));
if (!current->msgid)
@@ -799,22 +866,24 @@ save_msgid(FILE* output, struct DrawState* state, const struct PoEntry* current)
return 0;
}
num_lines = u32_lines_in_string(current->msgid, 1, wrap_width);
-
if ((num_lines > 1)
- && (u32_strlen(current->msgid) > SAVE_MULTILINE_TRESHOLD))
+ || u32_strlen(current->msgid) + strlen("msgid: \"") + 1
+ > (size_t)literal_break_threshold)
{
pumsgid = current->msgid;
- fprintf(output, "msgid \"\"\n");
+ fprintf(output, "msgid %s", break_literals ? "\"\"\n" : "");
while (*pumsgid)
{
u8_msgid = NULL;
old_pumsgid = pumsgid;
- len = 0;
len = u32_next_line(current->msgid, &pumsgid, 1,
wrap_width);
if (len == 0)
+ {
+ first_line = 0;
continue;
+ }
size = len * UTF8REPMAX + 1;
@@ -828,8 +897,11 @@ save_msgid(FILE* output, struct DrawState* state, const struct PoEntry* current)
memset(u8_msgid, 0, size);
unicode_string_to_u8(u8_msgid, old_pumsgid, len);
- fprintf(output, "\"%s\"\n", u8_msgid);
+ fprintf(output, "%s%s\"\n",
+ break_literals && first_line ? "" : "\"",
+ u8_msgid);
free(u8_msgid);
+ first_line = 0;
}
}
else
@@ -861,23 +933,29 @@ save_msgid_plural(FILE* output, struct DrawState* state,
char* u8_msgid = NULL;
size_t len = 0;
size_t msgid_plural_len, num_lines, size;
+ int first_line = 1;
assert((output != NULL) && (state != NULL) && (current != NULL));
num_lines = u32_lines_in_string(current->msgid_plural, 1, wrap_width);
if ((num_lines > 1)
- && (u32_strlen(current->msgid_plural) > SAVE_MULTILINE_TRESHOLD))
+ || u32_strlen(current->msgid_plural)
+ + strlen("msgid_plural: \"") + 1
+ > (size_t)literal_break_threshold)
{
pumsgid = current->msgid_plural;
- fprintf(output, "msgid_plural \"\"\n");
+ fprintf(output, "msgid_plural %s",
+ break_literals ? "\"\"\n" : "");
while (*pumsgid)
{
- len = 0;
u8_msgid = NULL;
old_pumsgid = pumsgid;
len = u32_next_line(current->msgid_plural, &pumsgid, 1,
wrap_width);
if (len == 0)
+ {
+ first_line = 0;
continue;
+ }
size = len * UTF8REPMAX + 1;
u8_msgid = malloc(size);
@@ -890,7 +968,10 @@ save_msgid_plural(FILE* output, struct DrawState* state,
memset(u8_msgid, 0, size);
unicode_string_to_u8(u8_msgid, old_pumsgid, len);
- fprintf(output, "\"%s\"\n", u8_msgid);
+ fprintf(output, "%s%s\"\n",
+ break_literals && first_line ? "" : "\"",
+ u8_msgid);
+ first_line = 0;
free(u8_msgid);
}
}
@@ -930,7 +1011,7 @@ save_msgstrs(FILE* output, struct DrawState* state,
int i;
int seen_generator = 0;
int seen_plural_forms = 0;
- int first_entry;
+ int first_entry, first_line;
assert((output != NULL) && (state != NULL) && (current != NULL));
first_entry = (current == state->entries) && !current->msgid;
@@ -951,20 +1032,31 @@ save_msgstrs(FILE* output, struct DrawState* state,
}
for (m = 0; m < current->msgstr_count; m++)
{
+ assert(current->msgstr);
num_lines = u32_lines_in_string(current->msgstr[m], 1,
wrap_width);
if ((num_lines > 1)
- && (u32_strlen(current->msgstr[m])
- > SAVE_MULTILINE_TRESHOLD))
+ || u32_strlen(current->msgstr[m])
+ + (current->msgstr_count == 1
+ ? strlen("msgst"
+ "r: "
+ "\"")
+ : strlen("msgst"
+ "r[ "
+ "]: "
+ "\""))
+ + 1
+ > (size_t)literal_break_threshold)
{
pumsgstr = current->msgstr[m];
if (current->msgstr_count == 1)
- fprintf(output, "msgstr \"\"\n");
+ fprintf(output, "msgstr %s",
+ break_literals ? "\"\"\n" : "");
else
- fprintf(output, "msgstr[%ld] \"\"\n", m);
+ fprintf(output, "msgstr[%ld] %s", m,
+ break_literals ? "\"\"\n" : "");
save_msgstrs_pumsgstr_loop:
- len = 0;
old_pumsgstr = pumsgstr;
len = u32_next_line(current->msgstr[m], &pumsgstr, 1,
wrap_width);
@@ -995,8 +1087,11 @@ save_msgstrs(FILE* output, struct DrawState* state,
plural_string);
}
else
- fprintf(output, "\"%s\"\n", u8_msgstr);
+ fprintf(output, "%s%s\"\n",
+ break_literals && first_line ? "" : "\"",
+ u8_msgstr);
free(u8_msgstr);
+ first_line = 0;
if (*pumsgstr)
goto save_msgstrs_pumsgstr_loop;
@@ -1281,15 +1376,17 @@ parse_po_line(const char* line, struct DrawState* dstate,
}
break;
case '\\':
- if (*pstate & PS_COMMENT)
+ if ((*pstate & PS_STRING) && *(pline + 1) == '"')
{
*ptoken++ = *pline++;
INC_COL();
+ /* Skip parsing '"' */
+ *ptoken++ = *pline++;
+ INC_COL();
}
- else if ((*pstate & PS_STRING) && *(pstate + 1))
+ else
{
*ptoken++ = *pline++;
- *ptoken++ = *pline++;
INC_COL();
}
break;
@@ -1353,129 +1450,131 @@ parse_po_line(const char* line, struct DrawState* dstate,
init_po_entry(*current_entry);
*msgstr_index = -1;
}
- if (*token)
+
+ if (!*token)
+ goto parse_po_empty_token;
+
+ if (*pstate & PS_MSGID)
{
- if (*pstate & PS_MSGID)
- set_msgid(*current_entry, token, 1);
- else if (*pstate & PS_MSGID_PLURAL)
- {
- set_msgid_plural(*current_entry, token, 1);
- if (*current_entry != dstate->entries)
- for (int i = 0; i < dstate->nplurals; i++)
- if (!set_msgstr(*current_entry, NULL, i,
- 0, dstate))
- goto parse_po_line_alloc_error;
- }
- else if (*pstate & PS_MSGSTR)
+ if (set_msgid(dstate, *current_entry, token, 1))
+ goto parse_po_line_alloc_error;
+ }
+ else if (*pstate & PS_MSGID_PLURAL)
+ {
+ if (set_msgid_plural(dstate, *current_entry, token, 1))
+ goto parse_po_line_alloc_error;
+ if (*current_entry != dstate->entries)
+ for (int i = 0; i < dstate->nplurals; i++)
+ if (set_msgstr(dstate, *current_entry, NULL, i,
+ 0))
+ goto parse_po_line_alloc_error;
+ }
+ else if (*pstate & PS_MSGSTR)
+ {
+ /* first entry */
+ if (*current_entry == dstate->entries)
{
- /* first entry */
- if (*current_entry == dstate->entries)
+ if (starts_with(token, "Plural-Forms: "))
{
- if (starts_with(token, "Plural-Forms: "))
- {
- set_plural_forms(*current_entry,
- token + strlen("Plural-Forms: "),
- 0);
- set_nplurals(dstate, *current_entry);
- }
+ if (set_plural_forms(dstate, *current_entry,
+ token + strlen("Plural-Forms: "), 0))
+ goto parse_po_line_alloc_error;
+ set_nplurals(dstate, *current_entry);
}
-
- if (!set_msgstr(*current_entry, token, 0, 1, dstate))
- goto parse_po_line_alloc_error;
- }
- else if (*pstate & PS_MSGSTR_ARRAY)
- {
- if (!set_msgstr(*current_entry, token, *msgstr_index, 1,
- dstate))
- goto parse_po_line_alloc_error;
- }
- else if (*pstate & PS_COMMENT_TRAN)
- {
- uint32_t* u32_token = NULL;
- size_t len = strlen(token) + 1;
- u32_token = calloc(len, sizeof(uint32_t));
- if (!u32_token)
- goto parse_po_line_alloc_error;
- u8_string_to_unicode(u32_token, token, len);
- u32_add_comment(*current_entry, u32_token);
- free(u32_token);
- }
- else if (*pstate & PS_COMMENT_EXTR)
- {
- uint32_t* u32_token = NULL;
- size_t len = strlen(token) + 1;
- u32_token = calloc(len, sizeof(uint32_t));
- if (!u32_token)
- goto parse_po_line_alloc_error;
- u8_string_to_unicode(u32_token, token, len);
- u32_add_extr_comment(*current_entry, u32_token);
- free(u32_token);
}
- else if (*pstate & PS_COMMENT_FLAG)
+
+ if (set_msgstr(dstate, *current_entry, token, 0, 1))
+ goto parse_po_line_alloc_error;
+ }
+ else if (*pstate & PS_MSGSTR_ARRAY)
+ {
+ if (set_msgstr(dstate, *current_entry, token, *msgstr_index, 1))
+ goto parse_po_line_alloc_error;
+ }
+ else if (*pstate & PS_COMMENT_TRAN)
+ {
+ uint32_t* u32_token = NULL;
+ size_t len = strlen(token) + 1;
+ u32_token = calloc(len, sizeof(uint32_t));
+ if (!u32_token)
+ goto parse_po_line_alloc_error;
+ u8_string_to_unicode(u32_token, token, len);
+ u32_add_comment(*current_entry, u32_token);
+ free(u32_token);
+ }
+ else if (*pstate & PS_COMMENT_EXTR)
+ {
+ uint32_t* u32_token = NULL;
+ size_t len = strlen(token) + 1;
+ u32_token = calloc(len, sizeof(uint32_t));
+ if (!u32_token)
+ goto parse_po_line_alloc_error;
+ u8_string_to_unicode(u32_token, token, len);
+ u32_add_extr_comment(*current_entry, u32_token);
+ free(u32_token);
+ }
+ else if (*pstate & PS_COMMENT_FLAG)
+ {
+ ptoken = token;
+ while (*ptoken)
{
- ptoken = token;
- while (*ptoken)
+ int first = *current_entry == dstate->entries;
+ if (starts_with(ptoken, flag_strings[FL_C_FORMAT]))
{
- int first = *current_entry == dstate->entries;
- if (starts_with(ptoken,
- flag_strings[FL_C_FORMAT]))
- {
- (*current_entry)->flags |= FL_C_FORMAT;
- ptoken += strlen(
- flag_strings[FL_C_FORMAT]);
- }
- else if (starts_with(ptoken,
- flag_strings[FL_NO_C_FORMAT]))
- {
- (*current_entry)->flags
- |= FL_NO_C_FORMAT;
- ptoken += strlen(
- flag_strings[FL_NO_C_FORMAT]);
- }
- else if (starts_with(ptoken,
- flag_strings[FL_FUZZY])
- && !first)
- {
- (*current_entry)->flags |= FL_FUZZY;
- dstate->fuzzy_count++;
- ptoken += strlen(flag_strings[FL_FUZZY]);
- }
- else if (*ptoken == ',' && *(ptoken + 1) == ' ')
- ptoken += 2;
- else
- {
- /* Let this slip, ignore everything
- * instead; see po.h for rationale */
- while (*ptoken)
- ptoken++;
- }
+ (*current_entry)->flags |= FL_C_FORMAT;
+ ptoken += strlen(flag_strings[FL_C_FORMAT]);
+ }
+ else if (starts_with(ptoken,
+ flag_strings[FL_NO_C_FORMAT]))
+ {
+ (*current_entry)->flags |= FL_NO_C_FORMAT;
+ ptoken += strlen(flag_strings[FL_NO_C_FORMAT]);
+ }
+ else if (starts_with(ptoken, flag_strings[FL_FUZZY])
+ && !first)
+ {
+ (*current_entry)->flags |= FL_FUZZY;
+ dstate->fuzzy_count++;
+ ptoken += strlen(flag_strings[FL_FUZZY]);
+ }
+ else if (*ptoken == ',' && *(ptoken + 1) == ' ')
+ ptoken += 2;
+ else
+ {
+ /* Let this slip, ignore
+ * everything instead; see po.h
+ * for rationale */
+ while (*ptoken)
+ ptoken++;
}
}
- else if (*pstate & PS_COMMENT_REFN)
- add_ref_comment(*current_entry, token);
- else if (*pstate & PS_COMMENT_OBSO)
- {
- uint32_t* u32_token = NULL;
- size_t len = strlen(token) + 1;
- u32_token = calloc(len, sizeof(uint32_t));
- if (!u32_token)
- goto parse_po_line_alloc_error;
- u8_string_to_unicode(u32_token, token, len);
- if (u32_add_comment(*current_entry, u32_token))
- (*current_entry)->obsolete = 1;
- free(u32_token);
- }
- *token = 0;
}
- else if (*pstate & PS_COMMENT_TRAN)
+ else if (*pstate & PS_COMMENT_REFN)
+ add_ref_comment(*current_entry, token);
+ else if (*pstate & PS_COMMENT_OBSO)
+ {
+ uint32_t* u32_token = NULL;
+ size_t len = strlen(token) + 1;
+ u32_token = calloc(len, sizeof(uint32_t));
+ if (!u32_token)
+ goto parse_po_line_alloc_error;
+ u8_string_to_unicode(u32_token, token, len);
+ if (u32_add_comment(*current_entry, u32_token))
+ (*current_entry)->obsolete = 1;
+ free(u32_token);
+ }
+ *token = 0;
+ goto parse_po_cleanup;
+
+parse_po_empty_token:
+ if (*pstate & PS_COMMENT_TRAN)
u32_add_comment(*current_entry, (uint32_t*)L"");
else if (*pstate & PS_COMMENT_EXTR)
u32_add_extr_comment(*current_entry, (uint32_t*)L"");
+parse_po_cleanup:
/* one-line states */
*pstate &= ~PS_COMMENT;
-
-parse_po_cleanup:
return !!dstate->error;
parse_po_line_alloc_error:
diff --git a/po.h b/po.h
@@ -7,32 +7,11 @@
#define MSGSTR_MAX 4096
// #define ALLOC_DELTA 10
+/* lines to tolerate the lack of msgid */
#define PO_DETECTION_LINES 24
-/* If msgid/msgstr is longer, it will be saved as multiple lines */
-#define SAVE_MULTILINE_TRESHOLD 70
-
-// #define LOAD_PARSE_ERR(e) (LOAD_ERR_PARSE_PREFIX + (e))
struct DrawState;
-/*enum {
- PARSE_ERR_NONE = 0,
- PARSE_ERR_INVAL = 1,
- PARSE_ERR_ALLOC = 2,
- PARSE_ERR_SYNTAX = 3
-};
-
-enum {
- LOAD_ERR_NONE = 0,
- LOAD_ERR_CANT_ALLOC = 1,
- LOAD_ERR_CANT_OPEN_FILE = 2,
- LOAD_ERR_NOT_PO_FILE = 3,
- LOAD_ERR_PARSE_PREFIX = 100,
- LOAD_ERR_P_INVAL = LOAD_PARSE_ERR(PARSE_ERR_INVAL),
- LOAD_ERR_P_ALLOC = LOAD_PARSE_ERR(PARSE_ERR_ALLOC),
- LOAD_ERR_P_SYNTAX = LOAD_PARSE_ERR(PARSE_ERR_SYNTAX)
-};*/
-
enum {
SAVE_ERR_NONE = 0,
SAVE_ERR_CANT_ALLOC = 1,
@@ -89,6 +68,8 @@ struct PoEntry {
size_t msgid_plural_size;
size_t msgid_plural_len;
uint32_t* plural_forms;
+ size_t plural_forms_size;
+ size_t plural_forms_len;
uint32_t** msgstr;
int msgstr_count;
size_t* msgstr_size;
@@ -106,21 +87,22 @@ char* format_flags(char* buffer, const size_t max, const struct PoEntry* entry,
void init_po_entry(struct PoEntry* entry);
void free_po_entry(struct PoEntry* entry);
struct PoEntry* set_flags(struct PoEntry* entry, const Flags flags);
-struct PoEntry* set_msgid(struct PoEntry* entry, const char* msgid, int append);
-struct PoEntry* set_msgid_plural(struct PoEntry* entry,
+int set_msgid(struct DrawState* state, struct PoEntry* entry, const char* msgid, int append);
+int set_msgid_plural(struct DrawState* state, struct PoEntry* entry,
const char* msgid_plural, int append);
-struct PoEntry* set_plural_forms(struct PoEntry* entry,
+int set_plural_forms(struct DrawState* state, struct PoEntry* entry,
const char* plural_forms, int append);
-struct PoEntry* set_msgstr(struct PoEntry* entry, const char* msgstr,
- int msgstr_index, int append, struct DrawState* state);
-struct PoEntry* u32_set_msgid(struct PoEntry* entry, const uint32_t* msgid,
- size_t msgid_size, int append);
-struct PoEntry* u32_set_msgid_plural(struct PoEntry* entry,
- const uint32_t* msgid_plural, size_t msgid_plural_size, int append);
-struct PoEntry* u32_set_plural_forms(struct PoEntry* entry,
- const uint32_t* plural_forms, int append);
-struct PoEntry* u32_set_msgstr(struct PoEntry* entry, const uint32_t* msgstr,
- int msgstr_index, int append, struct DrawState* state);
+int set_msgstr(struct DrawState* state, struct PoEntry* entry,
+ const char* msgstr, int msgstr_index, int append);
+int u32_set_msgid(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgid, size_t msgid_size, int append);
+int u32_set_msgid_plural(struct DrawState* state,
+ struct PoEntry* entry, const uint32_t* msgid_plural,
+ size_t msgid_plural_size, int append);
+int u32_set_plural_forms(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* plural_forms, const size_t plural_forms_len, int append);
+int u32_set_msgstr(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgstr, int msgstr_index, int append);
struct PoEntry* u32_add_comment(struct PoEntry* entry, const uint32_t* comment);
struct PoEntry* u32_add_extr_comment(struct PoEntry* entry,
const uint32_t* extr_comment);
diff --git a/poe.1.in b/poe.1.in
@@ -11,20 +11,73 @@
.Nm
.Fl h | \-help | Fl V | \-full\-version | Fl v | \-version
.Nm
+.Op Fl B | \-no\-backup
+.Op Fl b | \-backup
+.Op Fl L | \-dont\-break\-literals
+.Op Fl W | \-no\-wrap
+.Op Fl w Ar cols No | Fl \-wrap\-width= Ns Ar cols
.Ar filename.po
.Sh DESCRIPTION
.Nm
is a .po (GNU gettext) file editor with a terminal UI.
.Bl -tag -width Ds
+.It Fl B , \-no\-backup
+Disables backups.
+This option overrides the setting in
+.Pa config.h .
+.It Fl b , \-backup
+Enables backups.
+This option overrides the setting in
+.Pa config.h .
.It Fl h , \-help
Show option summary.
+.It Fl L , \-dont\-break\-literals
+Don't break long literals into an empty string and a literal on a separate line.
+By default, if the length of the text
+.Bd -literal -offset indent
+msgid: \(dq
+.Ed
+.Pp
+(or msgid_plural:, msgstr:, etc) plus the length of the literal, plus one (for
+the closing quote) are greater than
+.Va literal_break_threshold ,
+a line of the form
+.Bd -literal -offset indent
+msgid: \(dqSome really long literal string\(dq
+.Ed
+.Pp
+will be broken into two lines:
+.Bd -literal -offset indent
+msgid: \(dq\(dq
+\(dqSome really long literal string\(dq
+.Ed
+.Pp
+This option prevents that.
+It overrides the setting in
+.Pa config.h .
.It Fl V , \-full\-version
Show full version information: like
.Fl v ,
-followed by copyright notice and defines set in
-.Pa config.h .
+followed by copyright notice and the state of options.
.It Fl v , \-version
Show version information: program version and source git repository commit date.
+.It Fl W , \-no\-wrap
+Sets
+.Va wrap_width
+to 0, effectively turning off wrapping of
+.Ic msgid Ns s,
+.Ic msgid_plural Ns s,
+.Ic msgstr Ns s
+and
+.Ic msgstr[nn] Ns s
+on save.
+.It Fl w Ar cols , Fl \-wrap\-width= Ns Ar cols
+Sets
+.Va wrap_width
+to the specified value.
+If
+.Ad cols
+is negative, it will be set to zero, effectively turning off wrapping on save.
.El
.Ss Key bindings
Main window key bindings are as follows:
diff --git a/poe.c b/poe.c
@@ -14,9 +14,6 @@
#include <sys/stat.h>
#include <unistd.h>
-#define TB_OPT_V1_COMPAT
-#define TB_IMPL
-
#define COPYRIGHT \
(" This program is licensed under the terms of GNU GPL v3" \
" or (at your option)\n" \
@@ -29,12 +26,16 @@
" LICENSE.termbox.\n")
#define POE_C_GLOBALS
#define TB_IMPL
+#define BSLNEWLINE ((uint32_t*){'\\', 'n'})
+#define SPACE ((uint32_t)0x0020)
+#define TAB ((uint32_t)0x0009)
+/* Order is important! */
#include "draw.h"
+#include "poe.h"
#include "config.h"
#include "limit.h"
#include "po.h"
-#include "poe.h"
#include "util.h"
#include "version.h"
@@ -79,13 +80,16 @@ cancel_close(struct DrawState* state)
static int
cancel_msgstr(struct DrawState* state)
{
+ char* temp = NULL;
ssize_t i;
assert(state != NULL);
- if (!state->in_prompt && state->dirty)
+ if (!state->in_prompt
+ && (state->dirty
+ || (state->show_edit && state->dirty_before_edit)))
{
state->in_prompt = 1;
- STRLCPY(prompt_cancel_dirty, state->prompt, MAXBUFLINE);
+ MEMCCPY(state->prompt, prompt_cancel_dirty, LINE_DEFAULT, temp);
state->prompt_callback = cancel_callback;
return 0;
}
@@ -140,18 +144,22 @@ copy_msgid_to_input(struct DrawState* state)
const uint32_t* pmsgid;
const uint32_t* old_pmsgid;
uint32_t* newtext;
+ char* temp = NULL;
ssize_t msgid_num_lines, lines_to_init, lines_to_free, i;
size_t len, newlen;
assert(state != NULL);
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 0;
+ }
if (!state->in_prompt && *state->input_buffer->text)
{
state->in_prompt = 1;
- STRLCPY(prompt_overwrite, state->prompt, MAXBUFLINE);
+ MEMCCPY(state->prompt, prompt_overwrite, LINE_DEFAULT, temp);
state->prompt_callback = overwrite_copy_msgid_callback;
return 0;
}
@@ -186,7 +194,7 @@ copy_msgid_to_input(struct DrawState* state)
{
pbuffer = newbuf + msgid_num_lines - 1 - i;
init_bufferline(pbuffer);
- newtext = calloc(MAXBUFLINE, sizeof(uint32_t));
+ newtext = calloc(LINE_DEFAULT, sizeof(uint32_t));
if (!newtext)
return 0;
pbuffer->text = newtext;
@@ -195,12 +203,11 @@ copy_msgid_to_input(struct DrawState* state)
pbuffer = newbuf;
while (pmsgid && *pmsgid)
{
- len = 0;
- newlen = 0;
old_pmsgid = pmsgid;
len = u32_next_line(current->msgid, &pmsgid, 0, 0);
- u32_strncpy(pbuffer->text, old_pmsgid, MIN(len + 1, MAXBUFLINE));
- newlen = u32_decode_tabs(pbuffer->text, MAXBUFLINE);
+ u32_strncpy(pbuffer->text, old_pmsgid,
+ MIN(len + 1, LINE_DEFAULT));
+ newlen = u32_decode_tabs(pbuffer->text, LINE_DEFAULT);
pbuffer->length = newlen;
pbuffer++;
}
@@ -361,7 +368,10 @@ erase_backwards(struct DrawState* state)
assert((state != NULL) && (state->input_buffer != NULL));
buffer_line = &state->input_buffer[state->coord.row];
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
if (state->coord.col > 0)
{
@@ -411,13 +421,16 @@ erase_forward(struct DrawState* state)
assert((state != NULL) && (state->input_buffer != NULL));
buffer_line = &state->input_buffer[state->coord.row];
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
assert(buffer_line->text != NULL);
if (buffer_line->text[state->coord.col])
{
i = state->coord.col;
- while (i < MAXBUFLINE - 2 && buffer_line->text[i + 1])
+ while (i < LINE_DEFAULT - 2 && buffer_line->text[i + 1])
{
buffer_line->text[i] = buffer_line->text[i + 1];
i++;
@@ -428,10 +441,11 @@ erase_forward(struct DrawState* state)
}
else if (state->coord.row < state->input_rows_count - 1)
{
- if (!join_lines(state, state->coord.row, 1))
+ if (join_lines(state))
{
state->error = ERR_CANT_ALLOC;
state->running = 0;
+ return 1;
}
}
return 0;
@@ -446,7 +460,10 @@ erase_prev_word(struct DrawState* state)
assert(state != NULL);
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
i = state->coord.col;
len = state->input_buffer[state->coord.row].length;
pline = state->input_buffer[state->coord.row].text;
@@ -491,19 +508,7 @@ erase_search_backwards(struct DrawState* state)
i++;
} while (state->search[i]);
state->search[i - 1] = 0;
- state->search_column--;
- if (state->search_column < state->search_first_shown_column)
- {
- if (state->search_column > state->search_width - 4)
- state->search_first_shown_column
- = state->search_column
- - state->search_width + 4;
- else
- state->search_first_shown_column = 0;
- }
- state->search_display_column
- = display_length(state->search, state->search_column);
-
+ search_position_to(state, state->search_column - 1);
return next_match(state);
}
return 0;
@@ -553,29 +558,16 @@ erase_search_prev_word(struct DrawState* state)
for (j = i; j < len - d; j++)
pline[j] = pline[j + d];
- len -= state->search_column - i;
- pline[len] = 0;
- state->search_column = i;
- state->search_display_column
- = display_length(state->search, state->search_column);
-
- if (state->search_column < state->search_first_shown_column)
- {
- if (state->search_column > state->search_width - 4)
- state->search_first_shown_column = state->search_column
- - state->search_width + 4;
- else
- state->search_first_shown_column = 0;
- }
- state->search_display_column
- = display_length(state->search, state->search_column);
-
+ len -= d;
+ pline[len] = 0;
+ search_position_to(state, i);
return next_match(state);
}
static int
erase_search_to_end(struct DrawState* state)
{
+ assert(state != NULL);
state->search[state->search_column] = 0;
move_search_end(state);
return next_match(state);
@@ -584,10 +576,14 @@ erase_search_to_end(struct DrawState* state)
static int
erase_search_to_start(struct DrawState* state)
{
- size_t i = state->search_column;
- size_t len = u32_strlen(state->search);
+ size_t i, len;
+
+ assert((state != NULL) && (state->search != NULL));
+ i = state->search_column;
+ len = u32_strlen(state->search);
do
{
+ assert(i < MAXSEARCH);
state->search[i - state->search_column] = state->search[i];
i++;
} while (state->search[i]);
@@ -601,10 +597,15 @@ erase_to_end(struct DrawState* state)
{
struct BufferLine* buffer_line = NULL;
+ assert((state != NULL) && (state->input_buffer != NULL));
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
buffer_line = &state->input_buffer[state->coord.row];
+ assert(buffer_line->text != NULL);
buffer_line->text[state->coord.col] = 0;
buffer_line->length = state->coord.col;
move_end(state);
@@ -619,15 +620,20 @@ erase_to_start(struct DrawState* state)
ssize_t i;
ssize_t len;
+ assert((state != NULL) && (state->input_buffer != NULL));
i = state->coord.col;
buffer_line = &state->input_buffer[state->coord.row];
len = buffer_line->length;
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
do
{
+ assert(i <= len);
buffer_line->text[i - state->coord.col] = buffer_line->text[i];
i++;
} while (buffer_line->text[i]);
@@ -641,29 +647,29 @@ erase_to_start(struct DrawState* state)
static int
exit_program(struct DrawState* state)
{
- if (state->show_edit)
- {
- state->error = ERR_DLG_OPEN;
- return 0;
- }
- if (state->dirty)
+ char* temp = NULL;
+
+ assert(state != NULL);
+ if (state->dirty || (state->show_edit && state->dirty_before_edit))
{
state->in_prompt = 1;
- STRLCPY(prompt_dirty, state->prompt, MAXBUFLINE);
+ MEMCCPY(state->prompt, prompt_dirty, LINE_DEFAULT, temp);
state->prompt_callback = quit_callback;
}
else
state->running = 0;
- //*state->error = 0;
+ state->error = ERR_NONE;
return 0;
}
static void
goto_msgid(struct DrawState* state, const ssize_t msgid_number)
{
- ssize_t last_non_obsolete
- = state->real_msgid_count - state->obsolete_at_end_count;
+ ssize_t last_non_obsolete;
+ assert(state != NULL);
+ last_non_obsolete
+ = state->real_msgid_count - state->obsolete_at_end_count;
if (msgid_number > state->real_msgid_count)
return;
@@ -685,6 +691,7 @@ static void
handle_key_event(struct tb_event* ev, struct DrawState* state)
{
const struct Key* current = NULL;
+ size_t key;
assert((state != NULL) && (ev != NULL));
state->error = ERR_NONE;
@@ -706,17 +713,11 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
/* Remember to also edit the following condition if you
* reassign motion keys */
- /* TODO: Condition in sled also contains:
- && ev->key != TB_KEY_PGDN && ev->key != TB_KEY_PGUP
- && ev->key != TB_KEY_CTRL_B && ev->key != TB_KEY_CTRL_F
- && !(IN(state->mode, M_COMMAND) && strchr("jkgGHLM", ev->ch)))
- Check?
- */
if (ev->key != TB_KEY_ARROW_DOWN && ev->key != TB_KEY_ARROW_UP
&& state->show_edit)
state->saved_column = -1;
- for (size_t key = 0; key < LEN(top_level_keys); key++)
+ for (key = 0; key < LEN(top_level_keys); key++)
{
current = top_level_keys + key;
if (((current->ev.mod == ev->mod)
@@ -731,9 +732,9 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
if (state->show_edit)
{
- for (size_t key = 0; key < LEN(edit_keys); key++)
+ for (key = 0; key < LEN(edit_keys); key++)
{
- current = edit_keys + key;
+ current = &edit_keys[key];
if (((current->ev.mod == ev->mod)
&& (current->ev.key == ev->key) && !ev->ch)
|| (current->ev.ch
@@ -744,7 +745,12 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
return;
}
}
- if (!state->edit_info_focused && ev->ch)
+ if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
+ return;
+ }
+ if (ev->ch)
{
insert_char(state, ev->ch);
return;
@@ -753,9 +759,9 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
if (state->show_search)
{
- for (size_t key = 0; key < LEN(search_keys); key++)
+ for (key = 0; key < LEN(search_keys); key++)
{
- current = search_keys + key;
+ current = &search_keys[key];
if (((current->ev.mod == ev->mod)
&& (current->ev.key == ev->key) && !ev->ch)
|| (current->ev.ch
@@ -775,13 +781,33 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
if (state->show_help)
{
+ for (key = 0; key < LEN(help_keys); key++)
+ {
+ current = help_keys + key;
+ if (((current->ev.mod == ev->mod)
+ && (current->ev.key == ev->key) && !ev->ch)
+ || (current->ev.ch
+ && (current->ev.ch == ev->ch)))
+ if (current->callback)
+ {
+ current->callback(state);
+ return;
+ }
+ }
+
state->error = ERR_DLG_OPEN;
return;
}
- for (size_t key = 0; key < LEN(main_keys); key++)
+ if (state->show_search || state->show_edit)
+ {
+ state->error = ERR_DLG_OPEN_QUIT;
+ return;
+ }
+
+ for (key = 0; key < LEN(main_keys); key++)
{
- current = main_keys + key;
+ current = &main_keys[key];
if (((current->ev.mod == ev->mod)
&& (current->ev.key == ev->key) && !ev->ch)
|| (current->ev.ch && (current->ev.ch == ev->ch)))
@@ -803,6 +829,7 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
static int
hide_search(struct DrawState* state)
{
+ assert(state != NULL);
state->show_search = 0;
tb_hide_cursor();
return 0;
@@ -812,91 +839,118 @@ static int
insert_char(struct DrawState* state, uint32_t ch)
{
struct BufferLine* buffer_line;
- ssize_t len;
- assert(state != NULL);
+ uint32_t* temp = NULL;
+ ssize_t i, len, size;
+ int add_null;
+
+ assert((state != NULL) && (state->input_buffer != NULL));
if (state->edit_info_focused)
return 1;
buffer_line = &state->input_buffer[state->coord.row];
len = buffer_line->length;
- if (state->coord.col < MAXBUFLINE - 1)
+ size = buffer_line->size;
+
+ // TODO: realloc
+ if (len + 1 > size)
{
- ssize_t i = len + 1;
- int add_null = buffer_line->text[state->coord.col] == 0;
- while (i < MAXBUFLINE - 2 && i > state->coord.col)
- {
- buffer_line->text[i] = buffer_line->text[i - 1];
- i--;
- }
- buffer_line->text[state->coord.col++] = ch;
- buffer_line->length++;
- if (state->coord.col == MAXBUFLINE)
- state->coord.col = MAXBUFLINE - 1;
+ size += LINE_ALLOC_DELTA;
+ buffer_line->size = size;
+ temp = realloc(buffer_line->text, size * sizeof(uint32_t));
+ if (!temp)
+ goto insert_char_alloc_error;
+ buffer_line->text = temp;
+ }
+
+ i = len;
+ add_null = buffer_line->text[state->coord.col] == 0;
+ assert(buffer_line->text != NULL);
+ while (i + 1 <= size && i > state->coord.col)
+ {
+ buffer_line->text[i] = buffer_line->text[i - 1];
+ i--;
+ }
+ buffer_line->text[state->coord.col] = ch;
+ buffer_line->length++;
+ state->coord.col++;
+ state->input_display_column
+ = display_length(state->input_buffer[state->coord.row].text,
+ state->coord.col);
+ if (state->input_display_column - state->input_first_shown.col
+ > state->edit_width - 4)
+ {
+ state->input_first_shown.col
+ = state->input_display_column - state->edit_width + 4;
state->input_display_column
= display_length(state->input_buffer[state->coord.row]
.text,
state->coord.col);
- if (state->input_display_column - state->input_first_shown.col
- > state->edit_width - 4)
- {
- state->input_first_shown.col
- = state->input_display_column
- - state->edit_width + 4;
- state->input_display_column = display_length(
- state->input_buffer[state->coord.row].text,
- state->coord.col);
- }
- if (add_null)
- buffer_line->text[state->coord.col] = 0;
}
+ if (add_null)
+ buffer_line->text[state->coord.col] = 0;
state->dirty = 1;
return 0;
+
+insert_char_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
static int
insert_line(struct DrawState* state)
{
struct BufferLine* newbuf = NULL;
+ struct BufferLine* line = NULL;
+ uint32_t* newtext = NULL;
+ uint32_t* ptext = NULL;
+ ssize_t i;
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
- state->input_rows_count++;
+ assert(state != NULL);
newbuf = realloc(state->input_buffer,
- state->input_rows_count * sizeof(struct BufferLine));
+ (state->input_rows_count + 1) * sizeof(struct BufferLine));
if (!newbuf)
- {
- state->error = ERR_CANT_ALLOC;
- state->running = 0;
- return 0;
- }
-
+ goto insert_line_alloc_error;
state->input_buffer = newbuf;
- init_bufferline(&state->input_buffer[state->input_rows_count - 1]);
- uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t));
+ line = &state->input_buffer[state->input_rows_count];
+ init_bufferline(line);
+ newtext = calloc(LINE_DEFAULT, sizeof(uint32_t));
if (!newtext)
+ goto insert_line_alloc_error;
+ line->text = newtext;
+ line->size = LINE_DEFAULT;
+ state->input_rows_count++;
+ for (i = state->input_rows_count - 1; i > state->coord.row + 1; i--)
{
- state->error = ERR_CANT_ALLOC;
- state->running = 0;
- return 0;
- }
- state->input_buffer[state->input_rows_count - 1].text = newtext;
- for (ssize_t i = state->input_rows_count - 1; i > state->coord.row + 1;
- i--)
- {
- u32_strncpy(state->input_buffer[i].text,
- state->input_buffer[i - 1].text, MAXBUFLINE);
+ U32_SAFE_COPY(state->input_buffer[i].text, ptext,
+ state->input_buffer[i].size,
+ state->input_buffer[i - 1].text,
+ state->input_buffer[i].size, insert_line_alloc_error);
state->input_buffer[i].length
= state->input_buffer[i - 1].length;
}
- u32_strncpy(state->input_buffer[state->coord.row + 1].text,
- state->input_buffer[state->coord.row].text + state->coord.col,
- MAXBUFLINE);
+ ENSURE_SIZE(state->input_buffer[state->coord.row + 1].text, ptext,
+ state->input_buffer[state->coord.row + 1].size, LINE_DEFAULT,
+ LINE_DEFAULT, insert_line_alloc_error, uint32_t);
+ *state->input_buffer[state->coord.row + 1].text = 0;
+ if (state->coord.col < state->input_buffer[state->coord.row].length)
+ U32_SAFE_COPY(state->input_buffer[state->coord.row + 1].text,
+ ptext, state->input_buffer[state->coord.row + 1].size,
+ state->input_buffer[state->coord.row].text
+ + state->coord.col,
+ state->input_buffer[state->coord.row].size,
+ insert_line_alloc_error);
state->input_buffer[state->coord.row + 1].length
- = u32_strlen(state->input_buffer[state->coord.row + 1].text);
+ = state->input_buffer[state->coord.row].length
+ - state->coord.col;
state->input_buffer[state->coord.row].text[state->coord.col] = 0;
- state->input_buffer[state->coord.row].length
- = u32_strlen(state->input_buffer[state->coord.row].text);
+ state->input_buffer[state->coord.row].length = state->coord.col;
+ state->saved_column = -1;
state->coord.row++;
if (state->coord.row
> state->input_first_shown.row + (EDIT_HEIGHT - 3) / 2)
@@ -904,19 +958,25 @@ insert_line(struct DrawState* state)
= state->coord.row - (EDIT_HEIGHT - 3) / 2;
move_start(state);
state->dirty = 1;
-
return 0;
+
+insert_line_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
-static void
+static int
insert_search_char(struct DrawState* state, uint32_t ch)
{
- ssize_t len = u32_strlen(state->search);
- if (state->search_column < MAXSEARCH - 1)
+ ssize_t len, i;
+ int add_null;
+ assert(state != NULL);
+ len = u32_strlen(state->search);
+ if (state->search_column + 1 < MAXSEARCH)
{
- ssize_t i = len + 1;
- int add_null = state->search[state->search_column] == 0;
- while (i < MAXSEARCH - 2 && i > state->search_column)
+ i = len + 1;
+ add_null = state->search[state->search_column] == 0;
+ while (i + 2 < MAXSEARCH && i > state->search_column)
{
state->search[i] = state->search[i - 1];
i--;
@@ -942,91 +1002,97 @@ insert_search_char(struct DrawState* state, uint32_t ch)
next_match(state);
}
+ return 0;
}
static int
insert_search_space(struct DrawState* state)
{
- insert_search_char(state, (uint32_t)L' ');
- return 0;
+ return insert_search_char(state, SPACE);
}
static int
insert_search_tab(struct DrawState* state)
{
- insert_search_char(state, (uint32_t)L'\t');
- return 0;
+ return insert_search_char(state, TAB);
}
static int
insert_space(struct DrawState* state)
{
- insert_char(state, (uint32_t)L' ');
- return 0;
+ return insert_char(state, SPACE);
}
static int
insert_tab(struct DrawState* state)
{
- insert_char(state, (uint32_t)L'\t');
- return 0;
+ return insert_char(state, TAB);
}
-static struct DrawState*
-join_lines(struct DrawState* state, size_t first_line, int forward)
+static int
+join_lines(struct DrawState* state)
{
- state->coord.col = state->input_buffer[first_line].length;
- state->input_display_column
- = display_length(state->input_buffer[state->coord.row].text,
- state->coord.col);
- u32_strncat(state->input_buffer[first_line].text,
- state->input_buffer[first_line + 1].text, MAXBUFLINE);
- state->input_buffer[first_line].length
- = u32_strlen(state->input_buffer[first_line].text);
- if (!forward)
- {
- state->coord.row--;
- if (state->coord.row < 0)
- state->coord.row = 0;
- }
- for (ssize_t i = first_line + 1; i < state->input_rows_count - 1; i++)
- {
- u32_strncpy(state->input_buffer[i].text,
- state->input_buffer[i + 1].text, MAXBUFLINE);
+ struct BufferLine* first_line = NULL;
+ struct BufferLine* next_line = NULL;
+ uint32_t* ptext = NULL;
+ ssize_t i;
+
+ assert((state != NULL) && (state->input_buffer != NULL));
+ if (state->coord.row + 1 == state->input_rows_count)
+ return 1;
+
+ first_line = &state->input_buffer[state->coord.row];
+ next_line = &state->input_buffer[state->coord.row + 1];
+ ENSURE_SIZE(first_line->text, ptext, first_line->size,
+ first_line->length + next_line->length + 1,
+ first_line->length + next_line->length + LINE_ALLOC_DELTA,
+ join_lines_alloc_error, uint32_t);
+ U32_MEMCCPY(first_line->text + first_line->length, next_line->text,
+ next_line->length + 1, ptext);
+ first_line->length = u32_strlen(first_line->text);
+ for (i = state->coord.row + 1; i + 1 < state->input_rows_count; i++)
+ {
+ U32_SAFE_COPY(state->input_buffer[i].text, ptext,
+ state->input_buffer[i].size,
+ state->input_buffer[i + 1].text,
+ state->input_buffer[i + 1].size,
+ join_lines_alloc_error);
state->input_buffer[i].length
= state->input_buffer[i + 1].length;
}
- free_bufferline(state->input_buffer + state->input_rows_count - 1);
+ free_bufferline(&state->input_buffer[state->input_rows_count - 1]);
state->input_rows_count--;
- struct BufferLine* newbuf = realloc(state->input_buffer,
- state->input_rows_count * sizeof(struct BufferLine));
- if (!newbuf)
- return NULL;
- state->input_buffer = newbuf;
- state->dirty = 1;
+ state->dirty = 1;
+ return 0;
- return state;
+join_lines_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
-static struct BufferLine*
+static int
load_info(struct DrawState* state)
{
- struct PoEntry* first = &state->entries[0];
- struct PoEntry* current = &state->entries[state->msgid_number - 1];
+ struct PoEntry* first = NULL;
+ struct PoEntry* current = NULL;
struct BufferLine* newbuf = NULL;
struct BufferLine* pnewbuf = NULL;
- const uint32_t* pumsgid = NULL;
- ssize_t msgid_num_lines = u32_lines_in_string(current->msgid, 0, 0);
- ssize_t msgid_plural_num_lines
+ uint32_t* newtext = NULL;
+ ssize_t msgid_num_lines, msgid_plural_num_lines, num_lines, i;
+
+ assert((state != NULL) && (state->entries != NULL));
+ first = &state->entries[0];
+ current = &state->entries[state->msgid_number - 1];
+ msgid_num_lines = u32_lines_in_string(current->msgid, 0, 0);
+ msgid_plural_num_lines
= u32_lines_in_string(current->msgid_plural, 0, 0);
- ssize_t num_lines = 0;
- ssize_t newlen = 0;
+ num_lines = 0;
- for (ssize_t i = 0; i < state->info_rows_count; i++)
- free_bufferline(state->info_buffer + i);
+ for (i = 0; i < state->info_rows_count; i++)
+ free_bufferline(&state->info_buffer[i]);
free(state->info_buffer);
- state->info_rows_maxlen = 0;
+ state->info_maxlen = 0;
if (current->msgid)
num_lines += msgid_num_lines + 1;
@@ -1044,15 +1110,15 @@ load_info(struct DrawState* state)
num_lines += current->ref_comment_lines + 1;
newbuf = calloc(num_lines, sizeof(struct BufferLine));
if (!newbuf)
- return NULL;
+ goto load_info_alloc_error;
pnewbuf = newbuf;
- for (ssize_t i = 0; i < num_lines; i++)
+ for (i = 0; i < num_lines; i++)
{
init_bufferline(pnewbuf);
- uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t));
+ newtext = calloc(LINE_DEFAULT, sizeof(uint32_t));
if (!newtext)
- return NULL;
+ goto load_info_alloc_error;
pnewbuf->text = newtext;
pnewbuf++;
}
@@ -1060,155 +1126,231 @@ load_info(struct DrawState* state)
state->info_rows_count = num_lines;
pnewbuf = newbuf;
- newlen = 0;
- pumsgid = NULL;
+
if (current->msgid)
- {
- pumsgid = current->msgid;
- newlen = u32_u8_strncpy(pnewbuf->text, "msgid:", MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf->fg = colors[C_EDIT_MSGID_HEADING].fg;
- pnewbuf->bg = colors[C_EDIT_MSGID_HEADING].bg;
- pnewbuf++;
- while (*pumsgid)
- {
- size_t len = 0;
- const uint32_t* old_pumsgid = pumsgid;
-
- len = u32_next_line(current->msgid, &pumsgid, 0, 0);
- u32_strncpy(pnewbuf->text, old_pumsgid,
- MIN(len + 1, MAXBUFLINE));
- newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf++;
- }
- }
+ if (load_info_msgid(state, &pnewbuf))
+ return 1;
+
if (current->msgid_plural)
- {
- newlen = u32_u8_strncpy(pnewbuf->text,
- "msgid_plural:", MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf->fg = colors[C_EDIT_MSGID_HEADING].fg;
- pnewbuf->bg = colors[C_EDIT_MSGID_HEADING].bg;
- pnewbuf++;
- pumsgid = current->msgid_plural;
- while (*pumsgid)
- {
- size_t len = 0;
- const uint32_t* old_pumsgid = pumsgid;
-
- len = u32_next_line(current->msgid_plural, &pumsgid, 0,
- 0);
- u32_strncpy(pnewbuf->text, old_pumsgid,
- MIN(len + 1, MAXBUFLINE));
- newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf++;
- }
- if (first->plural_forms)
- {
- newlen = u32_u8_strncpy(pnewbuf->text,
- "Plural forms:", MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf->fg = colors[C_EDIT_MSGID_HEADING].fg;
- pnewbuf->bg = colors[C_EDIT_MSGID_HEADING].bg;
- pnewbuf++;
- newlen = u32_strncpy(pnewbuf->text, first->plural_forms,
- MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf++;
- }
- }
+ if (load_info_msgid_plural(state, &pnewbuf))
+ return 1;
+
if (current->comments)
- {
- newlen = u32_u8_strncpy(pnewbuf->text, "Comments:", MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf->fg = colors[C_EDIT_MSGID_HEADING].fg;
- pnewbuf->bg = colors[C_EDIT_MSGID_HEADING].bg;
- pnewbuf++;
- for (size_t i = 0; i < current->comment_lines; i++)
- {
- uint32_t* comment = current->comments[i];
- size_t len = u32_strlen(comment);
- newlen = u32_strncpy(pnewbuf->text, comment,
- MIN(len + 1, MAXBUFLINE));
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf++;
- }
- }
+ if (load_info_comments(state, &pnewbuf))
+ return 1;
+
if (current->extr_comments)
- {
- newlen = u32_u8_strncpy(pnewbuf->text,
- "Translation comments:", MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf->fg = colors[C_EDIT_MSGID_HEADING].fg;
- pnewbuf->bg = colors[C_EDIT_MSGID_HEADING].bg;
- pnewbuf++;
- for (size_t i = 0; i < current->extr_comment_lines; i++)
- {
- uint32_t* extr_comment = current->extr_comments[i];
- size_t len = u32_strlen(extr_comment);
- newlen = u32_strncpy(pnewbuf->text, extr_comment,
- MIN(len + 1, MAXBUFLINE));
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf++;
- }
- }
+ if (load_info_extr_comments(state, &pnewbuf))
+ return 1;
+
if (current->ref_comments)
- {
- newlen = u32_u8_strncpy(pnewbuf->text,
- "References:", MAXBUFLINE);
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf->fg = colors[C_EDIT_MSGID_HEADING].fg;
- pnewbuf->bg = colors[C_EDIT_MSGID_HEADING].bg;
- pnewbuf++;
- for (size_t i = 0; i < current->ref_comment_lines; i++)
- {
- char* ref_comment = current->ref_comments[i];
- size_t len = strlen(ref_comment);
- newlen = u32_u8_strncpy(pnewbuf->text, ref_comment,
- MIN(len + 1, MAXBUFLINE));
- pnewbuf->length = newlen;
- if (newlen > state->info_rows_maxlen)
- state->info_rows_maxlen = newlen;
- pnewbuf++;
- }
- }
+ if (load_info_ref_comments(state, &pnewbuf))
+ return 1;
state->info_buffer = newbuf;
+ return 0;
+
+load_info_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+}
+
+static int
+load_info_comments(struct DrawState* state, struct BufferLine** lines)
+{
+ struct PoEntry* current = NULL;
+ uint32_t* comment = NULL;
+ uint32_t* ptext = NULL;
+ ssize_t len, llen;
+ size_t i;
+
+ current = &state->entries[state->msgid_number - 1];
+ ptext = u32_u8_memccpy((*lines)->text, "Comments:", 0, LINE_DEFAULT);
+ (*lines)->length = llen = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
+ (*lines)->bg = colors[C_EDIT_MSGID_HEADING].bg;
+ (*lines)++;
+ for (i = 0; i < current->comment_lines; i++)
+ {
+ comment = current->comments[i];
+ len = u32_strlen(comment);
+ U32_MEMCCPY((*lines)->text, comment, MIN(len + 1, LINE_DEFAULT),
+ ptext);
+ (*lines)->length = llen
+ = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)++;
+ }
+ return 0;
+}
+
+static int
+load_info_extr_comments(struct DrawState* state, struct BufferLine** lines)
+{
+ struct PoEntry* current = NULL;
+ uint32_t* extr_comment = NULL;
+ uint32_t* ptext = NULL;
+ ssize_t len, llen;
+ size_t i;
+
+ current = &state->entries[state->msgid_number - 1];
+ ptext = u32_u8_memccpy((*lines)->text, "Translation comments:", 0,
+ LINE_DEFAULT);
+ (*lines)->length = llen = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
+ (*lines)->bg = colors[C_EDIT_MSGID_HEADING].bg;
+ (*lines)++;
+ for (i = 0; i < current->extr_comment_lines; i++)
+ {
+ extr_comment = current->extr_comments[i];
+ len = u32_strlen(extr_comment);
+ U32_MEMCCPY((*lines)->text, extr_comment,
+ MIN(len + 1, LINE_DEFAULT), ptext);
+ (*lines)->length = llen
+ = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)++;
+ }
+ return 0;
+}
+
+static int
+load_info_msgid(struct DrawState* state, struct BufferLine** lines)
+{
+ struct PoEntry* current = NULL;
+ const uint32_t* pumsgid = NULL;
+ const uint32_t* old_pumsgid = NULL;
+ uint32_t* ptext = NULL;
+ ssize_t len, llen;
+
+ current = &state->entries[state->msgid_number - 1];
+ ptext = u32_u8_memccpy((*lines)->text, "msgid:", 0, LINE_DEFAULT);
+ (*lines)->length = llen = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
+ (*lines)->bg = colors[C_EDIT_MSGID_HEADING].bg;
+ (*lines)++;
+ pumsgid = current->msgid;
+ while (*pumsgid)
+ {
+ old_pumsgid = pumsgid;
+ len = u32_next_line(current->msgid, &pumsgid, 0, 0);
+ U32_MEMCCPY((*lines)->text, old_pumsgid,
+ MIN(len + 1, LINE_DEFAULT), ptext);
+ llen = u32_decode_tabs((*lines)->text, LINE_DEFAULT);
+ (*lines)->length = llen;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)++;
+ }
+ return 0;
+}
+
+static int
+load_info_msgid_plural(struct DrawState* state, struct BufferLine** lines)
+{
+ struct PoEntry* current = NULL;
+ struct PoEntry* first = NULL;
+ const uint32_t* pumsgid = NULL;
+ const uint32_t* old_pumsgid = NULL;
+ uint32_t* ptext = NULL;
+ ssize_t len, llen;
+
+ first = &state->entries[0];
+ current = &state->entries[state->msgid_number - 1];
+ ptext = u32_u8_memccpy((*lines)->text, "msgid_plural:", 0, LINE_DEFAULT);
+ (*lines)->length = llen = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
+ (*lines)->bg = colors[C_EDIT_MSGID_HEADING].bg;
+ (*lines)++;
+ pumsgid = current->msgid_plural;
+ while (*pumsgid)
+ {
+ old_pumsgid = pumsgid;
+ len = u32_next_line(current->msgid_plural, &pumsgid, 0, 0);
+ U32_MEMCCPY((*lines)->text, old_pumsgid,
+ MIN(len + 1, LINE_DEFAULT), ptext);
+ llen = u32_decode_tabs((*lines)->text, LINE_DEFAULT);
+ (*lines)->length = llen;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)++;
+ }
+ if (first->plural_forms)
+ {
+ ptext = u32_u8_memccpy((*lines)->text, "Plural forms:", 0,
+ LINE_DEFAULT);
+ (*lines)->length = llen
+ = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
+ (*lines)->bg = colors[C_EDIT_MSGID_HEADING].bg;
+ (*lines)++;
+ ptext = u32_memccpy((*lines)->text, first->plural_forms, 0,
+ LINE_DEFAULT);
+ (*lines)->length = llen
+ = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)++;
+ }
+ return 0;
+}
+
+static int
+load_info_ref_comments(struct DrawState* state, struct BufferLine** lines)
+{
+ struct PoEntry* current = NULL;
+ char* ref_comment = NULL;
+ uint32_t* ptext = NULL;
+ ssize_t len, llen;
+ size_t i;
- return state->info_buffer;
+ current = &state->entries[state->msgid_number - 1];
+ ptext = u32_u8_memccpy((*lines)->text, "References:", 0, LINE_DEFAULT);
+ (*lines)->length = llen = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
+ (*lines)->bg = colors[C_EDIT_MSGID_HEADING].bg;
+ (*lines)++;
+ for (i = 0; i < current->ref_comment_lines; i++)
+ {
+ ref_comment = current->ref_comments[i];
+ len = strlen(ref_comment);
+ ptext = u32_u8_memccpy((*lines)->text, ref_comment, 0,
+ MIN(len + 1, LINE_DEFAULT));
+ (*lines)->length = llen
+ = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ if (llen > state->info_maxlen)
+ state->info_maxlen = llen;
+ (*lines)++;
+ }
+ return 0;
}
-static struct BufferLine*
+static int
load_msgstr(struct DrawState* state)
{
struct PoEntry* current;
struct BufferLine* newbuf;
struct BufferLine* pnewbuf;
- size_t num_lines;
+ const uint32_t* pumsgstr = NULL;
+ const uint32_t* old_pumsgstr = NULL;
+ uint32_t* newtext = NULL;
+ uint32_t* temp = NULL;
+ size_t num_lines, i, len, newlen;
+ ssize_t row;
int msgstr_index;
assert((state != NULL) && (state->entries != NULL));
@@ -1220,22 +1362,24 @@ load_msgstr(struct DrawState* state)
? 1
: u32_lines_in_string(*(current->msgstr + msgstr_index), 0, 0);
- for (ssize_t i = 0; i < state->input_rows_count; i++)
- free_bufferline(state->input_buffer + i);
+ for (row = 0; row < state->input_rows_count; row++)
+ free_bufferline(state->input_buffer + row);
free(state->input_buffer);
newbuf = calloc(num_lines, sizeof(struct BufferLine));
if (!newbuf)
- return NULL;
+ goto load_msgstr_alloc_error;
pnewbuf = newbuf;
- for (size_t i = 0; i < num_lines; i++)
+ for (i = 0; i < num_lines; i++)
{
init_bufferline(pnewbuf);
- uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t));
+ newtext = calloc(LINE_DEFAULT, sizeof(uint32_t));
if (!newtext)
- return NULL;
- pnewbuf->text = newtext;
+ goto load_msgstr_alloc_error;
+ pnewbuf->text = newtext;
+ pnewbuf->size = LINE_DEFAULT;
+ pnewbuf->length = 0;
pnewbuf++;
}
@@ -1243,23 +1387,21 @@ load_msgstr(struct DrawState* state)
if (current->msgstr_count > 0)
{
- const uint32_t* pumsgstr = *(current->msgstr + msgstr_index);
+ pumsgstr = *(current->msgstr + msgstr_index);
if (pumsgstr)
{
pnewbuf = newbuf;
while (*pumsgstr)
{
- size_t len = 0;
- size_t newlen = 0;
- const uint32_t* old_pumsgstr = pumsgstr;
- len = u32_next_line(*(current->msgstr
- + msgstr_index),
+ old_pumsgstr = pumsgstr;
+ len = u32_next_line(current->msgstr[msgstr_index],
&pumsgstr, 0, 0);
- u32_strncpy(pnewbuf->text, old_pumsgstr,
- MIN(len + 1, MAXBUFLINE));
+ U32_MEMCCPY(pnewbuf->text, old_pumsgstr,
+ MIN(len + 1, LINE_DEFAULT), temp);
newlen = u32_decode_tabs(pnewbuf->text,
- MAXBUFLINE);
+ LINE_DEFAULT); /* TODO: Check */
pnewbuf->length = newlen;
+ pnewbuf->size = LINE_DEFAULT;
pnewbuf++;
}
}
@@ -1270,14 +1412,17 @@ load_msgstr(struct DrawState* state)
newbuf[0].length = 0;
state->input_buffer = newbuf;
- return state->input_buffer;
+ return 0;
+
+load_msgstr_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
static int
move_down(struct DrawState* state)
{
- ssize_t dlen;
-
+ assert(state != NULL);
if (state->edit_info_focused)
{
if (state->info_first_shown.row + (EDIT_HEIGHT - 3) / 2
@@ -1285,94 +1430,46 @@ move_down(struct DrawState* state)
state->info_first_shown.row++;
return 0;
}
-
- if (state->coord.row < state->input_rows_count - 1)
- state->coord.row++;
- if (state->input_first_shown.row + (EDIT_HEIGHT - 3) / 2
- < state->coord.row)
- state->input_first_shown.row
- = state->coord.row - (EDIT_HEIGHT - 3) / 2;
- if (state->saved_column == -1)
- state->saved_column = state->input_display_column;
- dlen = display_length(state->input_buffer[state->coord.row].text,
- state->input_buffer[state->coord.row].length);
- if (dlen < state->saved_column)
- state->input_display_column = dlen;
- else
- state->input_display_column = state->saved_column;
- state->coord.col
- = input_length(state->input_buffer[state->coord.row].text,
- state->input_display_column);
- if (state->input_first_shown.col > state->input_display_column)
- state->input_first_shown.col = state->input_display_column;
- if (state->input_first_shown.col + state->edit_width - 4
- < state->input_display_column)
- state->input_first_shown.col
- = state->input_display_column - state->edit_width + 4;
- state->input_display_column
- = display_length(state->input_buffer[state->coord.row].text,
- state->coord.col);
+ position_to(state, state->coord.row + 1, state->coord.col);
return 0;
}
static int
move_end(struct DrawState* state)
{
- ssize_t len;
- ssize_t dlen;
-
+ assert((state != NULL) && (state->input_buffer != NULL));
if (state->edit_info_focused)
{
- if (state->info_rows_count > (EDIT_HEIGHT - 3) / 2)
- state->info_first_shown.row = state->info_rows_count
- - (EDIT_HEIGHT - 3) / 2;
- state->info_first_shown.col = 0;
+ if (state->info_maxlen < state->edit_width - 3)
+ state->info_first_shown.col = 0;
+ else
+ state->info_first_shown.col
+ = state->info_maxlen - state->edit_width + 3;
return 0;
}
-
- len = state->input_buffer[state->coord.row].length;
- state->coord.col = len;
- dlen = display_length(state->input_buffer[state->coord.row].text,
- state->coord.col);
- state->input_display_column = dlen;
- if (dlen > state->edit_width - 4)
- state->input_first_shown.col = dlen - state->edit_width + 4;
- else
- state->input_first_shown.col = 0;
+ position_to(state, state->coord.row,
+ state->input_buffer[state->coord.row].length);
return 0;
}
static int
move_left(struct DrawState* state)
{
+ assert((state != NULL) && (state->input_buffer != NULL));
if (state->edit_info_focused)
- {
- if (state->info_first_shown.col > 0)
- state->info_first_shown.col--;
- return 0;
- }
-
- if (state->coord.col == 0)
- return 0;
-
- if (state->input_buffer[state->coord.row].text[state->coord.col - 1]
- == '\t')
- state->input_display_column
- = display_length(state->input_buffer[state->coord.row]
- .text,
- state->coord.col - 1);
- else
- state->input_display_column--;
- state->coord.col--;
-
- if (state->input_display_column < state->input_first_shown.col)
- state->input_first_shown.col = state->input_display_column;
+ {
+ if (state->info_first_shown.col > 0)
+ state->info_first_shown.col--;
+ return 0;
+ }
+ position_to(state, state->coord.row, state->coord.col - 1);
return 0;
}
static int
move_list_down(struct DrawState* state)
{
+ assert(state != NULL);
goto_msgid(state, next_msgid(state, 1));
return 0;
}
@@ -1380,6 +1477,7 @@ move_list_down(struct DrawState* state)
static int
move_list_end(struct DrawState* state)
{
+ assert(state != NULL);
goto_msgid(state,
next_msgid(state,
state->real_msgid_count - state->msgid_number));
@@ -1389,6 +1487,7 @@ move_list_end(struct DrawState* state)
static int
move_list_page_down(struct DrawState* state)
{
+ assert(state != NULL);
state->error = ERR_NONE;
goto_msgid(state, next_msgid(state, state->maxy - 2));
return 0;
@@ -1397,6 +1496,7 @@ move_list_page_down(struct DrawState* state)
static int
move_list_page_up(struct DrawState* state)
{
+ assert(state != NULL);
state->error = ERR_NONE;
goto_msgid(state, prev_msgid(state, state->maxy - 2));
return 0;
@@ -1405,6 +1505,7 @@ move_list_page_up(struct DrawState* state)
static int
move_list_start(struct DrawState* state)
{
+ assert(state != NULL);
goto_msgid(state, 1);
return 0;
}
@@ -1412,6 +1513,7 @@ move_list_start(struct DrawState* state)
static int
move_list_up(struct DrawState* state)
{
+ assert(state != NULL);
goto_msgid(state, prev_msgid(state, 1));
return 0;
}
@@ -1419,12 +1521,16 @@ move_list_up(struct DrawState* state)
static int
move_next_word(struct DrawState* state)
{
- int i;
uint32_t* pline;
ssize_t len;
+ int i;
+ assert(state != NULL);
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
i = state->coord.col;
pline = state->input_buffer[state->coord.row].text;
@@ -1434,25 +1540,23 @@ move_next_word(struct DrawState* state)
i++;
while (i < len && u32_is_word_boundary(pline[i], 0))
i++;
- state->coord.col = i;
- state->input_display_column
- = display_length(state->input_buffer[state->coord.row].text,
- state->coord.col);
- if (state->input_display_column - state->input_first_shown.col
- > state->edit_width - 4)
- state->input_first_shown.col
- = state->input_display_column - state->edit_width + 4;
+
+ position_to(state, state->coord.row, i);
return 0;
}
static int
move_prev_word(struct DrawState* state)
{
- int i;
uint32_t* pline;
+ int i;
+ assert((state != NULL) && (state->input_buffer != NULL));
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
i = state->coord.col;
pline = state->input_buffer[state->coord.row].text;
@@ -1465,113 +1569,64 @@ move_prev_word(struct DrawState* state)
&& !u32_is_word_boundary(pline[i - 1], 0))
i--;
- state->coord.col = i;
- state->input_display_column
- = display_length(state->input_buffer[state->coord.row].text,
- state->coord.col);
- if (state->input_display_column < state->input_first_shown.col)
- state->input_first_shown.col = state->input_display_column;
+ position_to(state, state->coord.row, i);
return 0;
}
static int
move_right(struct DrawState* state)
{
- ssize_t len;
-
- if (state->edit_info_focused)
- {
- if (state->info_first_shown.col + state->edit_width - 3
- < state->info_rows_maxlen + 1)
- state->info_first_shown.col++;
- return 0;
- }
-
- len = state->input_buffer[state->coord.row].length;
- if (state->coord.col == len)
- return 0;
-
- if (state->input_buffer[state->coord.row].text[state->coord.col] == '\t')
- state->input_display_column
- = display_length(state->input_buffer[state->coord.row]
- .text,
- state->coord.col + 1);
- else
- state->input_display_column++;
- state->coord.col++;
-
- if (state->input_display_column - state->input_first_shown.col
- > state->edit_width - 4)
- state->input_first_shown.col
- = state->input_display_column - state->edit_width + 4;
+ assert(state != NULL);
+ position_to(state, state->coord.row, state->coord.col + 1);
return 0;
}
static int
move_search_end(struct DrawState* state)
{
- ssize_t len = u32_strlen(state->search);
- state->search_column = len;
- ssize_t dlen = display_length(state->search, state->search_column);
- state->search_display_column = dlen;
- if (dlen > state->search_width - 4)
- state->search_first_shown_column
- = dlen - state->search_width + 4;
- else
- state->search_first_shown_column = 0;
+ assert(state != NULL);
+ search_position_to(state, u32_strlen(state->search));
return 0;
}
static int
move_search_left(struct DrawState* state)
{
+ assert((state != NULL) && (state->search != NULL));
if (state->search_column == 0)
- return 0;
-
- if (state->search[state->search_column - 1] == '\t')
- state->search_display_column = display_length(state->search,
- state->search_column - 1);
- else
- state->search_display_column--;
- state->search_column--;
-
- if (state->search_display_column < state->search_first_shown_column)
- state->search_first_shown_column = state->search_display_column;
+ return 1;
+ search_position_to(state, state->search_column - 1);
return 0;
}
static int
move_search_next_word(struct DrawState* state)
{
- int i = state->search_column;
- uint32_t* pline = state->search;
- ssize_t len = u32_strlen(state->search);
+ uint32_t* pline = NULL;
+ ssize_t len;
+ int i;
+ assert((state != NULL) && (state->search != NULL));
+ i = state->search_column;
+ pline = state->search;
+ len = u32_strlen(state->search);
while (i < len && !u32_is_word_boundary(pline[i], 0))
i++;
while (i < len && u32_is_word_boundary(pline[i], 0))
i++;
- state->search_column = i;
- state->search_display_column
- = display_length(state->search, state->search_column);
-
- if (state->search_display_column - state->search_first_shown_column
- > state->search_width - 4)
- {
- state->search_first_shown_column = state->search_display_column
- - state->search_width + 4;
- state->search_display_column
- = display_length(state->search, state->search_column);
- }
+ search_position_to(state, i);
return 0;
}
static int
move_search_prev_word(struct DrawState* state)
{
- int i = state->search_column;
- uint32_t* pline = state->search;
+ uint32_t* pline = NULL;
+ int i;
+ assert((state != NULL) && (state->search != NULL));
+ i = state->search_column;
+ pline = state->search;
if (i > 0 && u32_is_word_boundary(pline[i - 1], 0))
i--;
while (i > 0 && u32_is_word_boundary(pline[i], 0))
@@ -1579,106 +1634,52 @@ move_search_prev_word(struct DrawState* state)
while (i > 0 && !u32_is_word_boundary(pline[i], 0)
&& !u32_is_word_boundary(pline[i - 1], 0))
i--;
-
- state->search_column = i;
- state->search_display_column
- = display_length(state->search, state->search_column);
-
- if (state->search_column < state->search_first_shown_column)
- {
- if (state->search_column > state->search_width - 4)
- state->search_first_shown_column = state->search_column
- - state->search_width + 4;
- else
- state->search_first_shown_column = 0;
- }
- state->search_display_column
- = display_length(state->search, state->search_column);
+ search_position_to(state, i);
return 0;
}
static int
move_search_right(struct DrawState* state)
{
- ssize_t len = u32_strlen(state->search);
- if (state->search_column == len)
- return 0;
-
- if (state->search[state->search_column] == '\t')
- state->search_display_column = display_length(state->search,
- state->search_column + 1);
- else
- state->search_display_column++;
- state->search_column++;
-
- if (state->search_display_column - state->search_first_shown_column
- > state->search_width - 4)
- state->search_first_shown_column = state->search_display_column
- - state->search_width + 4;
+ assert(state != NULL);
+ search_position_to(state, state->search_display_column + 1);
return 0;
}
static int
move_search_start(struct DrawState* state)
{
- state->search_column = 0;
- state->search_display_column = 0;
- state->search_first_shown_column = 0;
+ assert(state != NULL);
+ search_position_to(state, 0);
return 0;
}
static int
move_start(struct DrawState* state)
{
+ assert(state != NULL);
if (state->edit_info_focused)
{
state->info_first_shown.row = 0;
state->info_first_shown.col = 0;
return 0;
}
-
- state->coord.col = 0;
- state->input_display_column = 0;
- state->input_first_shown.col = 0;
+ position_to(state, state->coord.row, 0);
return 0;
}
static int
move_up(struct DrawState* state)
{
- ssize_t dlen;
-
+ assert(state != NULL);
if (state->edit_info_focused)
{
if (state->info_first_shown.row > 0)
state->info_first_shown.row--;
return 0;
}
-
- if (state->coord.row > 0)
- state->coord.row--;
- if (state->input_first_shown.row > state->coord.row)
- state->input_first_shown.row = state->coord.row;
- if (state->saved_column == -1)
- state->saved_column = state->input_display_column;
- dlen = display_length(state->input_buffer[state->coord.row].text,
- state->input_buffer[state->coord.row].length);
- if (dlen < state->saved_column)
- state->input_display_column = dlen;
- else
- state->input_display_column = state->saved_column;
- state->coord.col
- = input_length(state->input_buffer[state->coord.row].text,
- state->input_display_column);
- if (state->input_first_shown.col > state->input_display_column)
- state->input_first_shown.col = state->input_display_column;
- if (state->input_first_shown.col + state->edit_width - 4
- < state->input_display_column)
- state->input_first_shown.col
- = state->input_display_column - state->edit_width + 4;
- state->input_display_column
- = display_length(state->input_buffer[state->coord.row].text,
- state->coord.col);
+ position_to(state, state->coord.row > 1 ? state->coord.row - 1 : 0,
+ state->coord.col);
return 0;
}
@@ -1686,17 +1687,19 @@ static int
next_fuzzy(struct DrawState* state)
{
struct PoEntry* current = NULL;
+ ssize_t e;
+ int saved_show_edit;
+ assert(state != NULL);
if (state->msgid_count == 0)
- return 0;
+ return 1;
- state->error = ERR_NONE;
- for (ssize_t e = state->msgid_number; e < state->msgid_count; e++)
+ for (e = state->msgid_number; e < state->msgid_count; e++)
{
current = state->entries + e;
if (current->flags & FL_FUZZY)
{
- int saved_show_edit = state->show_edit;
+ saved_show_edit = state->show_edit;
if (saved_show_edit)
{
if (state->dirty)
@@ -1723,12 +1726,13 @@ static int
next_match(struct DrawState* state)
{
struct PoEntry* current = NULL;
+ ssize_t e;
+ assert(state != NULL);
if (state->msgid_count == 0 || !state->search || !*state->search)
- return 0;
+ return 1;
- state->error = ERR_NONE;
- for (ssize_t e = state->msgid_number; e < state->real_msgid_count; e++)
+ for (e = state->msgid_number; e < state->real_msgid_count; e++)
{
current = state->entries + e;
if (current->obsolete)
@@ -1750,8 +1754,12 @@ static int
next_plural(struct DrawState* state)
{
struct PoEntry* current = NULL;
+ assert((state != NULL) && (state->entries != NULL));
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
current = &state->entries[state->msgid_number - 1];
save_msgstr(state);
if (state->msgstr_index + 1 < current->msgstr_count)
@@ -1764,19 +1772,18 @@ static int
next_untranslated(struct DrawState* state)
{
struct PoEntry* current = NULL;
-
+ ssize_t e;
+ int saved_show_edit;
+ assert((state != NULL) && (state->entries != NULL));
if (state->msgid_count == 0)
- return 0;
-
- state->error = ERR_NONE;
-
- for (ssize_t e = state->msgid_number; e < state->msgid_count; e++)
+ return 1;
+ for (e = state->msgid_number; e < state->msgid_count; e++)
{
current = state->entries + e;
if (!current->msgstr || !*current->msgstr
|| u32_strlen(*current->msgstr) == 0)
{
- int saved_show_edit = state->show_edit;
+ saved_show_edit = state->show_edit;
if (saved_show_edit)
{
if (state->dirty)
@@ -1802,24 +1809,25 @@ next_untranslated(struct DrawState* state)
static size_t
next_msgid(struct DrawState* state, const int delta)
{
- size_t ret = state->msgid_number;
- size_t start = ret;
- size_t last_non_obsolete
+ size_t ret, start, last_non_obsolete;
+ assert((state != NULL) && (state->entries != NULL));
+ ret = state->msgid_number;
+ start = ret;
+ last_non_obsolete
= state->real_msgid_count - state->obsolete_at_end_count;
-
while (ret < last_non_obsolete + 1)
{
ret++;
if (!state->entries[ret - 1].obsolete && ret >= start + delta)
break;
}
-
return ret == last_non_obsolete + 1 ? last_non_obsolete : ret;
}
static int
overwrite_copy_msgid_callback(struct DrawState* state, struct tb_event* ev)
{
+ assert((state != NULL) && (ev != NULL));
if (ev->ch == 'y')
copy_msgid_to_input(state);
state->prompt_callback = NULL;
@@ -1829,6 +1837,7 @@ overwrite_copy_msgid_callback(struct DrawState* state, struct tb_event* ev)
static int
overwrite_paste_callback(struct DrawState* state, struct tb_event* ev)
{
+ assert((state != NULL) && (ev != NULL));
if (ev->ch == 'y')
paste_paste_buffer_to_input(state);
state->prompt_callback = NULL;
@@ -1841,16 +1850,24 @@ paste_paste_buffer_to_input(struct DrawState* state)
struct BufferLine* pinput = NULL;
struct BufferLine* newbuf = NULL;
struct BufferLine* ppaste = NULL;
+ uint32_t* newtext = NULL;
+ uint32_t* utemp = NULL;
+ char* temp = NULL;
ssize_t lines_to_init = 0;
ssize_t lines_to_free = 0;
+ ssize_t i;
+ assert(state != NULL);
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
if (!state->in_prompt && *state->input_buffer->text)
{
state->in_prompt = 1;
- STRLCPY(prompt_overwrite, state->prompt, MAXBUFLINE);
+ MEMCCPY(state->prompt, prompt_overwrite, LINE_DEFAULT, temp);
state->prompt_callback = overwrite_paste_callback;
return 0;
}
@@ -1858,16 +1875,18 @@ paste_paste_buffer_to_input(struct DrawState* state)
if (state->msgid_number == 1)
{
state->error = ERR_ILLEGAL_ON_FIRST;
- return 0;
+ return 1;
}
if (!state->paste || !(*state->paste).text || !*(*state->paste).text)
{
/* leave one row */
- for (ssize_t i = 1; i < state->input_rows_count; i++)
+ for (i = 1; i < state->input_rows_count; i++)
free_bufferline(state->input_buffer + i);
- state->input_buffer = realloc(state->input_buffer,
- sizeof(struct BufferLine));
+ state->input_buffer = realloc(state->input_buffer,
+ sizeof(struct BufferLine));
+ if (!state->input_buffer)
+ goto paste_paste_buffer_alloc_error;
*(state->input_buffer->text) = 0;
init_coord(&state->coord, 0, 0);
state->input_display_column = 0;
@@ -1884,7 +1903,7 @@ paste_paste_buffer_to_input(struct DrawState* state)
? state->input_rows_count - state->paste_count
: 0;
- for (ssize_t i = 0; i < lines_to_free; i++)
+ for (i = 0; i < lines_to_free; i++)
free_bufferline(
state->input_buffer + state->input_rows_count - i - 1);
newbuf = realloc(state->input_buffer,
@@ -1892,25 +1911,24 @@ paste_paste_buffer_to_input(struct DrawState* state)
ppaste = state->paste;
if (!newbuf)
- return 0;
+ goto paste_paste_buffer_alloc_error;
- for (ssize_t i = 0; i < lines_to_init; i++)
+ for (i = 0; i < lines_to_init; i++)
{
- uint32_t* newtext;
pinput = newbuf + state->paste_count - 1 - i;
init_bufferline(pinput);
- newtext = calloc(MAXBUFLINE, sizeof(uint32_t));
+ newtext = calloc(LINE_DEFAULT, sizeof(uint32_t));
if (!newtext)
- return 0;
+ goto paste_paste_buffer_alloc_error;
pinput->text = newtext;
}
if (ppaste)
- for (ssize_t i = 0; i < state->paste_count; i++)
+ for (i = 0; i < state->paste_count; i++)
{
pinput = newbuf + i;
- u32_strncpy(pinput->text, ppaste->text,
- MIN(ppaste->length + 1, MAXBUFLINE));
+ U32_MEMCCPY(pinput->text, ppaste->text,
+ MIN(ppaste->length + 1, LINE_DEFAULT), utemp);
pinput->length = ppaste->length;
ppaste++;
}
@@ -1918,20 +1936,132 @@ paste_paste_buffer_to_input(struct DrawState* state)
state->input_rows_count = state->paste_count;
state->input_buffer = newbuf;
state->dirty = 1;
-
return 0;
+
+paste_paste_buffer_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+}
+
+/*
+ * state->saved_column - display coordinate
+ * row, column - buffer coordinates (not display)
+ */
+static void
+position_to(struct DrawState* state, const int row, const int column)
+{
+ ssize_t dlen;
+
+ assert(state != NULL);
+ if (row != state->coord.row)
+ {
+ state->coord.row = row;
+ if ((state->coord.row + 1) > state->input_rows_count)
+ state->coord.row = state->input_rows_count - 1;
+ if (state->coord.row < state->input_first_shown.row)
+ state->input_first_shown.row = state->coord.row;
+ if (state->input_first_shown.row + (EDIT_HEIGHT - 3) / 2
+ < state->coord.row)
+ state->input_first_shown.row
+ = state->coord.row - (EDIT_HEIGHT - 3) / 2;
+ if (state->saved_column == -1)
+ {
+ state->saved_column = state->input_display_column;
+ state->coord.col = column;
+ }
+ else
+ state->coord.col = buffer_length(
+ state->input_buffer[state->coord.row].text,
+ state->saved_column);
+ if (state->coord.col < 0)
+ state->coord.col = 0;
+ else if (state->coord.col
+ > (int)state->input_buffer[state->coord.row].length)
+ state->coord.col
+ = state->input_buffer[state->coord.row].length;
+ dlen = display_length(state->input_buffer[state->coord.row].text,
+ state->coord.col);
+ if (dlen < state->saved_column)
+ state->input_display_column = dlen;
+ else
+ state->input_display_column = state->saved_column;
+ }
+ else
+ {
+ state->coord.col = column;
+ if (state->coord.col < 0)
+ {
+ if (state->coord.row > 0)
+ {
+ state->coord.row--;
+ if (state->input_first_shown.row > 0
+ && state->input_first_shown.row
+ > state->coord.row)
+ state->input_first_shown.row--;
+ state->coord.col
+ = state->input_buffer[state->coord.row]
+ .length;
+ }
+ else
+ state->coord.col = 0;
+ }
+ else if (state->coord.col
+ > state->input_buffer[state->coord.row].length)
+ {
+ if ((state->coord.row + 1) < state->input_rows_count)
+ {
+ state->coord.row++;
+ if (state->input_first_shown.row
+ + (state->maxy - 2)
+ < state->coord.row
+ && state->input_first_shown.row + 1
+ < state->input_rows_count)
+ state->input_first_shown.row++;
+ state->coord.col = 0;
+ }
+ else
+ state->coord.col
+ = state->input_buffer[state->coord.row]
+ .length;
+ }
+ state->input_display_column
+ = display_length(state->input_buffer[state->coord.row]
+ .text,
+ state->coord.col);
+ state->saved_column = state->input_display_column;
+ }
+ if (state->input_first_shown.col > state->input_display_column)
+ state->input_first_shown.col = state->input_display_column;
+ if (state->input_first_shown.col + state->edit_width - 4
+ < state->input_display_column)
+ {
+ int index_first;
+ int fsc = state->input_first_shown.col;
+ index_first
+ = buffer_length(state->input_buffer[state->coord.row]
+ .text,
+ fsc);
+ while (fsc + state->edit_width < state->input_display_column + 4)
+ {
+ index_first++;
+ fsc = display_length(state->input_buffer[state->coord.row]
+ .text,
+ index_first);
+ }
+ state->input_first_shown.col = fsc;
+ }
}
static int
prev_match(struct DrawState* state)
{
struct PoEntry* current = NULL;
+ ssize_t e;
+ assert(state != NULL);
if (state->msgid_count == 0 || !state->search || !*state->search)
- return 0;
-
- state->error = ERR_NONE;
- for (ssize_t e = state->msgid_number - 1; e > 0; e--)
+ return 1;
+ for (e = state->msgid_number - 1; e > 0; e--)
{
current = state->entries + e - 1;
if ((current->msgid && *current->msgid
@@ -1953,34 +2083,43 @@ prev_msgid(struct DrawState* state, const int delta)
ssize_t ret = state->msgid_number;
ssize_t start = ret;
+ assert((state != NULL) && (state->entries != NULL));
if (start < delta)
return state->real_msgid_count ? 1 : 0;
-
while (ret > 1)
{
ret--;
if (!state->entries[ret - 1].obsolete && ret <= start - delta)
break;
}
-
return ret;
}
int
print_error(const int code, const char* msg, ...)
{
- char buf[MAXBUFLINE];
+ char* buf = NULL;
va_list args;
+ long bufsize;
+ assert(msg != NULL);
+ bufsize = limits[L_LINE_MAX] ? limits[L_LINE_MAX]
+ : PRINT_BUF_MAX_FALLBACK;
+ buf = malloc(bufsize);
+ if (!buf)
+ return ERR_CANT_ALLOC;
va_start(args, msg);
- vsnprintf(buf, sizeof(buf), msg, args);
+ if (vsnprintf(buf, bufsize, msg, args) >= bufsize)
+ buf[bufsize - 1] = 0;
va_end(args);
fprintf(stderr, "%s: %s\n", PROGRAM_NAME, buf);
+ free(buf);
return code;
}
static int
quit_callback(struct DrawState* state, struct tb_event* ev)
{
+ assert((state != NULL) && (ev != NULL));
if (ev->ch == 'y')
write_file(state);
state->prompt_callback = NULL;
@@ -2004,8 +2143,12 @@ redraw_status(struct DrawState* state)
static int
prev_plural(struct DrawState* state)
{
+ assert(state != NULL);
if (state->edit_info_focused)
+ {
+ state->error = ERR_DLG_FOCUS_EDIT;
return 1;
+ }
save_msgstr(state);
if (state->msgstr_index > 0)
state->msgstr_index--;
@@ -2017,10 +2160,14 @@ static int
save_msgstr(struct DrawState* state)
{
struct BufferLine* pinput_buffer;
+ struct PoEntry* current = NULL;
uint32_t* to_save = NULL;
+ uint32_t* temp = NULL;
+ uint32_t* temp2 = NULL;
size_t to_save_size = 0;
- struct PoEntry* current = NULL;
+ ssize_t i;
+ assert(state != NULL);
state->show_edit = 0;
state->edit_info_focused = 0;
@@ -2031,21 +2178,28 @@ save_msgstr(struct DrawState* state)
if (!to_save)
{
state->error = ERR_CANT_ALLOC;
- return 0;
+ return 1;
}
pinput_buffer = NULL;
- for (ssize_t i = 0; i < state->input_rows_count; i++)
+ for (i = 0; i < state->input_rows_count; i++)
{
- pinput_buffer = state->input_buffer + i;
+ pinput_buffer = &state->input_buffer[i];
if (i == 0)
- u32_strncpy(to_save, pinput_buffer->text,
- to_save_size * sizeof(uint32_t));
- else
+ U32_MEMCCPY(to_save, pinput_buffer->text,
+ to_save_size * sizeof(uint32_t), temp);
+ else if (temp)
{
- u32_strncat(to_save, (uint32_t*)L"\\n",
+ U32_U8_MEMCCPY((temp - 1), "\\n",
+ to_save_size * sizeof(uint32_t), temp2);
+ if (temp2)
+ U32_MEMCCPY((temp2 - 1),
+ pinput_buffer->text,
+ to_save_size * sizeof(uint32_t),
+ temp);
+ /*u32_strncat(to_save, BSLNEWLINE ,
to_save_size * sizeof(uint32_t));
u32_strncat(to_save, pinput_buffer->text,
- to_save_size * sizeof(uint32_t));
+ to_save_size * sizeof(uint32_t));*/
}
free_bufferline(pinput_buffer);
}
@@ -2053,17 +2207,18 @@ save_msgstr(struct DrawState* state)
free(state->input_buffer);
state->input_buffer = NULL;
state->input_rows_count = 0;
- for (ssize_t i = 0; i < state->info_rows_count; i++)
+ for (i = 0; i < state->info_rows_count; i++)
free_bufferline(state->info_buffer + i);
free(state->info_buffer);
- state->dirty = (state->dirty_before_edit || state->dirty);
+ state->dirty = (state->dirty_before_edit || state->dirty);
+ // state->dirty_before_edit = 0;
state->info_rows_count = 0;
state->info_buffer = NULL;
u32_encode_tabs(to_save, to_save_size * sizeof(uint32_t));
current = &state->entries[state->msgid_number - 1];
u32_match_msgid_ending(current->msgid, to_save,
to_save_size * sizeof(uint32_t));
- u32_set_msgstr(current, to_save, state->msgstr_index, 0, state);
+ u32_set_msgstr(state, current, to_save, state->msgstr_index, 0);
update_warning(current->msgid, to_save, ¤t->warning);
state->input_changed_fuzzy = UNCHANGED;
@@ -2073,17 +2228,38 @@ save_msgstr(struct DrawState* state)
}
static int
+search_position_to(struct DrawState* state, const int column)
+{
+ ssize_t len;
+
+ assert((state != NULL) && (state->search != NULL));
+ len = u32_strlen(state->search);
+ state->search_column = column;
+
+ if (state->search_column > len)
+ state->search_column = len;
+ state->search_display_column
+ = display_length(state->search, state->search_column);
+ if (state->search_first_shown_column > state->search_display_column)
+ state->search_first_shown_column = state->search_display_column;
+ if (state->search_first_shown_column + (state->search_width - 4)
+ < state->search_column)
+ state->search_first_shown_column = state->search_display_column
+ - (state->search_width - 4);
+ return 0;
+}
+
+static int
show_edit(struct DrawState* state)
{
if (state->msgstr_index + 1
> state->entries[state->msgid_number - 1].msgstr_count)
state->msgstr_index = 0;
- if (!load_msgstr(state) || !load_info(state))
+ if (load_msgstr(state) || load_info(state))
{
- state->error = ERR_CANT_ALLOC;
state->running = 0;
- return 0;
+ return 1;
}
state->dirty_before_edit = state->dirty;
@@ -2215,7 +2391,7 @@ yank_input_to_paste_buffer(struct DrawState* state)
uint32_t* newtext;
ppaste = newbuf + state->input_rows_count - 1 - i;
init_bufferline(ppaste);
- newtext = calloc(MAXBUFLINE, sizeof(uint32_t));
+ newtext = calloc(LINE_DEFAULT, sizeof(uint32_t));
if (!newtext)
return 0;
ppaste->text = newtext;
@@ -2226,7 +2402,7 @@ yank_input_to_paste_buffer(struct DrawState* state)
{
ppaste = newbuf + i;
u32_strncpy(ppaste->text, pinput->text,
- MIN(pinput->length + 1, MAXBUFLINE));
+ MIN(pinput->length + 1, LINE_DEFAULT));
ppaste->length = pinput->length;
pinput++;
}
@@ -2287,8 +2463,8 @@ main(int argc, char** argv)
const char* saved_tb_error = NULL;
char* wd = NULL;
ssize_t filename_size = 0;
- long lineno;
- long col;
+ long lineno = 1;
+ long col = 1;
int dir_access;
int dir_access_errno;
int optind = 1;
@@ -2312,8 +2488,8 @@ main(int argc, char** argv)
return print_error(CUSTOM_ERROR_START + ERR_NO_CL_ARG,
"No filename given");
- // main_options_loop:
- if (optind == argc)
+main_options_loop:
+ if (optind >= argc)
return print_error(CUSTOM_ERROR_START + ERR_NO_CL_ARG,
"No filename given");
@@ -2321,7 +2497,10 @@ main(int argc, char** argv)
{
printf("Usage:\t%s -h | --help | -V | --full-version | -v |"
" --version\n"
- "\t%s filename.po\n",
+ "\t%s [-B | --no-backup] [-b | --backup]"
+ " [-L | --dont-break-literals]"
+ " [-W | --no-wrap] [-w <cols> | --wrap-width=<cols>]"
+ " filename.po\n",
PROGRAM_NAME, PROGRAM_NAME);
return 0;
}
@@ -2337,26 +2516,80 @@ main(int argc, char** argv)
printf("%s %s, committed on %s\n", PROGRAM_NAME, VERSION, DATE);
puts(COPYRIGHT);
printf("Features set in config.h:\n");
- printf(" backup_fail:\t\t%s\n", backup_fail ? "set" : "unset");
+ printf(" backup_fail:\t\t\t%s\n",
+ backup_fail ? "set" : "unset");
if (backup_suffix)
- printf(" backup_suffix:\t\"%s\"\n", backup_suffix);
+ printf(" backup_suffix:\t\t\"%s\"\n", backup_suffix);
else
- printf(" backup_suffix:\tunset\n");
- printf(" create_backups:\t%s\n",
+ printf(" backup_suffix:\t\tunset\n");
+ printf(" break_literals:\t\t%s\n",
+ break_literals ? "set" : "unset");
+ printf(" create_backups:\t\t%s\n",
create_backups ? "set" : "unset");
- printf(" match_msgstr_ending:\t%s\n",
+ printf(" literal_break_threshold:\t%d\n",
+ literal_break_threshold);
+ printf(" match_msgstr_ending:\t\t%s\n",
match_msgstr_ending ? "set" : "unset");
if (plural_string)
- printf(" plural_string:\t\"%s\"\n", plural_string);
+ printf(" plural_string:\t\t\"%s\"\n", plural_string);
else
- printf(" plural_string:\tunset\n");
- printf(" warn_count_dots:\t%s\n",
+ printf(" plural_string:\t\tunset\n");
+ printf(" warn_count_dots:\t\t%s\n",
warn_count_dots ? "set" : "unset");
- printf(" wrap_first_msgstr:\t%s\n",
- wrap_first_msgstr ? "set" : "unset");
- printf(" wrap_width:\t\t%d\n", wrap_width);
+ printf(" wrap_width:\t\t\t%d\n", wrap_width);
return 0;
}
+ else if (!strcmp(argv[optind], "-B")
+ || !strcmp(argv[optind], "--no-backup"))
+ {
+ create_backups = 0;
+ optind++;
+ goto main_options_loop;
+ }
+ else if (!strcmp(argv[optind], "-b")
+ || !strcmp(argv[optind], "--backup"))
+ {
+ create_backups = 1;
+ optind++;
+ goto main_options_loop;
+ }
+ else if (!strcmp(argv[optind], "-L")
+ || !strcmp(argv[optind], "--dont-break-literals"))
+ {
+ break_literals = 0;
+ optind++;
+ goto main_options_loop;
+ }
+ else if (!strcmp(argv[optind], "-W")
+ || !strcmp(argv[optind], "--no-wrap"))
+ {
+ wrap_width = 0;
+ optind++;
+ goto main_options_loop;
+ }
+ else if (!strcmp(argv[optind], "-w")
+ || !strcmp(argv[optind], "--wrap-width="))
+ {
+ optind++;
+ if (sscanf(argv[optind], "%d", &wrap_width) < 1)
+ {
+ if (*argv[optind] == '-')
+ state.error = ERR_NO_CL_ARG_PARAM;
+ else
+ state.error = ERR_BAD_CL_ARG;
+ goto main_done;
+ }
+ if (wrap_width < 0)
+ wrap_width = 0;
+ optind++;
+ goto main_options_loop;
+ }
+ else if (starts_with(argv[optind], "--")
+ || starts_with(argv[optind], "-"))
+ {
+ state.error = ERR_BAD_CL_ARG;
+ goto main_done;
+ }
/*
* Chicken and egg problem: to get fpathconf(dirfd, _PC_PATH_MAX)
@@ -2603,7 +2836,6 @@ main_skip_backups:
goto init_termbox;
init_termbox:
- tbires = 0;
if ((tbires = tb_init()))
{
saved_tb_error = tb_strerror(tbires);
@@ -2658,6 +2890,12 @@ main_done:
case ERR_NOTREG_FILE:
print_error(1, errors[state.error], state.filename);
break;
+ case ERR_NO_CL_ARG_PARAM:
+ print_error(1, errors[state.error], argv[optind - 1]);
+ break;
+ case ERR_BAD_CL_ARG:
+ print_error(1, errors[state.error], argv[optind]);
+ break;
case ERR_SYNTAX:
print_error(1, errors[state.error], state.filename, lineno, col);
break;
diff --git a/poe.h b/poe.h
@@ -27,15 +27,22 @@ static void handle_key_event(struct tb_event* ev, struct DrawState* state);
static int hide_search(struct DrawState* state);
static int insert_char(struct DrawState* state, uint32_t ch);
static int insert_line(struct DrawState* state);
-static void insert_search_char(struct DrawState* state, uint32_t ch);
+static int insert_search_char(struct DrawState* state, uint32_t ch);
static int insert_search_space(struct DrawState* state);
static int insert_search_tab(struct DrawState* state);
static int insert_space(struct DrawState* state);
static int insert_tab(struct DrawState* state);
-static struct DrawState* join_lines(struct DrawState* state, size_t first_line,
- int forward);
-static struct BufferLine* load_info(struct DrawState* state);
-static struct BufferLine* load_msgstr(struct DrawState* state);
+static int join_lines(struct DrawState* state);
+static int load_info(struct DrawState* state);
+static int load_info_comments(struct DrawState* state, struct BufferLine** lines);
+static int load_info_extr_comments(struct DrawState* state,
+ struct BufferLine** lines);
+static int load_info_msgid(struct DrawState* state, struct BufferLine** lines);
+static int load_info_msgid_plural(struct DrawState* state,
+ struct BufferLine** lines);
+static int load_info_ref_comments(struct DrawState* state,
+ struct BufferLine** lines);
+static int load_msgstr(struct DrawState* state);
static int move_down(struct DrawState* state);
static int move_end(struct DrawState* state);
static int move_left(struct DrawState* state);
@@ -61,9 +68,13 @@ static int next_match(struct DrawState* state);
static int next_plural(struct DrawState* state);
static int next_untranslated(struct DrawState* state);
static size_t next_msgid(struct DrawState* state, const int delta);
-static int overwrite_copy_msgid_callback(struct DrawState* state, struct tb_event* ev);
-static int overwrite_paste_callback(struct DrawState* state, struct tb_event* ev);
+static int overwrite_copy_msgid_callback(struct DrawState* state,
+ struct tb_event* ev);
+static int overwrite_paste_callback(struct DrawState* state,
+ struct tb_event* ev);
static int paste_paste_buffer_to_input(struct DrawState* state);
+static void position_to(struct DrawState* state, const int row,
+ const int column);
static int prev_match(struct DrawState* state);
static size_t prev_msgid(struct DrawState* state, const int delta);
static int prev_plural(struct DrawState* state);
@@ -71,6 +82,7 @@ int print_error(const int code, const char* msg, ...);
static int quit_callback(struct DrawState* state, struct tb_event* ev);
void redraw_status(struct DrawState* state);
static int save_msgstr(struct DrawState* state);
+static int search_position_to(struct DrawState* state, const int column);
static int show_edit(struct DrawState* state);
static int show_help(struct DrawState* state);
static int show_search(struct DrawState* state);
diff --git a/termbox.h b/termbox.h
@@ -2345,7 +2345,9 @@ static int bytebuf_flush(struct bytebuf *b, int fd);
static int bytebuf_reserve(struct bytebuf *b, size_t sz);
static int bytebuf_free(struct bytebuf *b);
static int tb_iswprint_ex(uint32_t ch, int *width);
+#ifdef TB_OPT_EGC
static int tb_cluster_width(uint32_t *ch, size_t nch);
+#endif
int tb_init(void) {
return tb_init_file("/dev/tty");
@@ -4335,6 +4337,7 @@ int tb_wcwidth(uint32_t ch) {
return w;
}
+#ifdef TB_OPT_EGC
static int tb_cluster_width(uint32_t *ch, size_t nch) {
int wmax = -1;
int vs15 = 0, vs16 = 0, ri = 0, zwj = 0;
@@ -4356,6 +4359,7 @@ static int tb_cluster_width(uint32_t *ch, size_t nch) {
}
return wmax;
}
+#endif
static int tb_iswprint_ex(uint32_t ch, int *w) {
#ifdef TB_OPT_LIBC_WCHAR
diff --git a/util.c b/util.c
@@ -13,9 +13,9 @@
#include "util.h"
/* Whitespace definition for determining word boundaries */
-#define B_WS " \v\t"
+#define B_WS " \v\t-"
/* Full word boundary delimiter definition */
-#define B_FULL " \v\t()[]{},.;:/\\"
+#define B_FULL " \v\t-()[]{},.;:/\\"
enum { UTLERRNONE = 0, UTLERROVFL = 1 };
@@ -84,7 +84,7 @@ u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr, size_t max)
size_t msgid_len = 0;
buf = calloc(max + 1, sizeof(uint32_t));
- if (!buf)
+ if (!buf || !msgid)
return 0;
buf_len = u32_strncpy(buf, msgstr, (max + 1) * sizeof(uint32_t));
@@ -133,6 +133,50 @@ u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr, size_t max)
return buf_len;
}
+uint32_t*
+u32_memccpy(uint32_t* dst, const uint32_t* src, uint32_t c, size_t len)
+{
+ size_t copied = 0;
+ assert((dst != NULL) && (src != NULL));
+ while ((*dst++ = *src++) != c && copied < len)
+ copied++;
+ if (copied == len)
+ return NULL;
+ return dst;
+}
+
+/* len is the max length of src in bytes */
+uint32_t*
+u32_u8_memccpy(uint32_t* dst, const char* src, uint32_t c, size_t len)
+{
+ const char* psrc = src;
+ uint32_t uch;
+ size_t copied = 0;
+ int u8_len;
+
+ assert((dst != NULL) && (src != NULL));
+ do
+ {
+ if (!*psrc)
+ {
+ *dst++ = 0;
+ break;
+ }
+ u8_len = tb_utf8_char_to_unicode(&uch, psrc);
+ if (u8_len < 0)
+ {
+ /* error, replace uch with "error char" */
+ uch = 0xFFFD;
+ u8_len = -u8_len;
+ }
+ psrc += u8_len;
+ copied += u8_len;
+ if (copied >= len)
+ return NULL;
+ } while ((*dst++ = uch) != c && copied < len);
+ return dst;
+}
+
size_t
u32_count_chars(const uint32_t* s, const uint32_t ch)
{
@@ -368,7 +412,7 @@ u32_lines_in_string(const uint32_t* s, const int include_eol, const size_t wrap)
{
size_t result = 1;
const uint32_t* ps = NULL;
- int last_empty = 0;
+ //int last_empty = 0;
if (!s)
return result;
@@ -380,9 +424,9 @@ u32_lines_in_string(const uint32_t* s, const int include_eol, const size_t wrap)
if (*ps)
result++;
}
- if (ps > s + 1 && *(ps - 2) == '\\' && *(ps - 1) == 'n')
- last_empty = 1;
- return result + last_empty;
+ /*if (ps > s + 1 && *(ps - 2) == '\\' && *(ps - 1) == 'n')
+ last_empty = 1;*/
+ return result;// + last_empty;
}
/*
@@ -432,7 +476,7 @@ u32_next_line(const uint32_t* s, const uint32_t** next_line,
if (!u32_is_word_boundary(*ps, 1)
&& u32_is_word_boundary(*(ps + 1), 1))
{
- last_nonblank = ps - start;
+ last_nonblank = ps + 1 - start;
have_last_nonblank = 1;
}
diff --git a/util.h b/util.h
@@ -5,78 +5,60 @@
#include <stdint.h>
#include <sys/types.h>
-#define ABS(a) ((a < 0) ? (-a) : (a))
-#define LEN(x) (sizeof(x) / sizeof(x[0]))
-#define MAX(a, b) ((a > b) ? a : b)
-#define MIN(a, b) ((a < b) ? a : b)
-#define STRLCAT(tail, head, totallen) \
- do \
- { \
- if (strlcat(head, tail, totallen) >= totallen) \
- { \
- print_error(1, "strlcat:%d: Overflow", __LINE__); \
- exit(1); \
- } \
+#define ABS(a) ((a < 0) ? (-a) : (a))
+#define LEN(x) (sizeof(x) / sizeof(x[0]))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MEMCCPY(to, from, tolen, temp) \
+ do \
+ { \
+ temp = memccpy((to), (from), 0, (tolen)); \
+ if (!(temp)) \
+ (to)[(tolen) > 0 ? (tolen) - 1 : 0] = 0; \
} while (0)
-#define STRLCPY(from, to, tolen) \
- do \
- { \
- if (strlcpy(to, from, tolen) >= tolen) \
- { \
- print_error(1, "strlcpy:%d: Overflow", __LINE__); \
- exit(1); \
- } \
- } while (0)
-#define MEMCCPY(to, from, tolen, temp) \
- do \
- { \
- temp = memccpy(to, from, 0, tolen); \
- if (!temp) \
- to[tolen > 0 ? tolen - 1 : 0] = 0; \
- } while (0)
-#define MEMCCPY_EXT(to, fallbackto, from, tolen, temp) \
- do \
- { \
- temp = memccpy(to, from, 0, tolen); \
- if (!temp) \
- fallbackto[tolen > 0 ? tolen - 1 : 0] = 0; \
+#define MEMCCPY_EXT(to, fallbackto, from, tolen, temp) \
+ do \
+ { \
+ temp = memccpy((to), (from), 0, (tolen)); \
+ if (!(temp)) \
+ (fallbackto)[(tolen) > 0 ? (tolen) - 1 : 0] = 0; \
} while (0)
-#define U32_MEMCCPY(to, from, tolen, temp) \
- do \
- { \
- temp = u32_memccpy(to, from, 0L, tolen); \
- if (!temp) \
- to[tolen > 0 ? tolen - 1 : 0] = 0; \
+#define U32_MEMCCPY(to, from, tolen, temp) \
+ do \
+ { \
+ (temp) = u32_memccpy((to), (from), 0L, (tolen)); \
+ if (!(temp)) \
+ (to)[(tolen) > 0 ? (tolen) - 1 : 0] = 0; \
} while (0)
-#define U32_U8_MEMCCPY(to, from, tolen, temp) \
- do \
- { \
- temp = u32_u8_memccpy(to, from, 0L, tolen); \
- if (!temp) \
- to[tolen > 0 ? tolen - 1 : 0] = 0; \
+#define U32_U8_MEMCCPY(to, from, tolen, temp) \
+ do \
+ { \
+ (temp) = u32_u8_memccpy((to), (from), 0L, (tolen)); \
+ if (!(temp)) \
+ (to)[(tolen) > 0 ? (tolen) - 1 : 0] = 0; \
} while (0)
-#define U32_MEMCCPY_EXT(to, fallbackto, from, tolen, fbtolen, temp) \
- do \
- { \
- temp = u32_memccpy(to, from, 0L, tolen); \
- if (!temp) \
- fallbackto[fbtolen > 0 ? fbtolen - 1 : 0] = 0; \
+#define U32_MEMCCPY_EXT(to, fallbackto, from, tolen, fbtolen, temp) \
+ do \
+ { \
+ temp = u32_memccpy((to), (from), 0L, (tolen)); \
+ if (!temp) \
+ (fallbackto)[(fbtolen) > 0 ? (fbtolen) - 1 : 0] = 0; \
} while (0)
-#define ENSURE_SIZE(to, temp, tosize, testsize, fromsize, label, type) \
- do \
- { \
- if (!(to) || (tosize) < (testsize)) \
- { \
- temp = realloc(to, (fromsize) * sizeof(type)); \
- if (!temp) \
- { \
- state->running = 0; \
- 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
@@ -112,6 +94,8 @@
enum {
ERR_NONE,
ERR_NO_CL_ARG,
+ ERR_NO_CL_ARG_PARAM,
+ ERR_BAD_CL_ARG,
ERR_NOTPO_FILE,
ERR_NOTREG_FILE,
ERR_TB_ERROR,
@@ -133,7 +117,7 @@ enum {
enum { ACT_IDLE, ACT_WRITING, ACT_READING };
-#define MAXBUFLINE 4096
+// #define MAXBUFLINE 4096
#define MAXCOPYBUF 8192
#define MAXDATEBUF 80
#define MAXFLAGSBUF (2 + 4 + 2 + 1)
@@ -145,12 +129,13 @@ enum { ACT_IDLE, ACT_WRITING, ACT_READING };
extern int utlerrno;
-size_t strlcpy(char* dst, const char* src, size_t dsize);
-size_t strlcat(char* dst, const char* src, size_t dsize);
size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max);
size_t unicode_string_to_u8(char* s, const uint32_t* us, const size_t max);
size_t u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr,
size_t max);
+uint32_t* u32_memccpy(uint32_t* dst, const uint32_t* src, uint32_t c,
+ size_t len);
+uint32_t* u32_u8_memccpy(uint32_t* dst, const char* src, uint32_t c, size_t len);
size_t u32_count_chars(const uint32_t* s, const uint32_t ch);
size_t u32_count_strings(const uint32_t* haystack, const uint32_t* needle);
size_t u32_encode_tabs(uint32_t* s, size_t max);