чување 9f5ea057100f4dd7471d0c5b48e86da92a7466bd
родитељ 61f8bd03e533f48a6d2883f733254fc8c711468d
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Thu, 19 Feb 2026 19:54:49 +0100
Continue WIP: portable wide literals; handle TODOs; general tidy up
Diffstat:
| M | TODO | | | 29 | +++++++++++++++-------------- |
| M | TODO.done | | | 9 | +++++++++ |
| M | draw.c | | | 115 | +++++++++++++++++++++++++------------------------------------------------------ |
| M | draw.h | | | 13 | +++---------- |
| M | po.c | | | 2558 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
| M | po.h | | | 93 | ++++++++++++++++++++++++++++++++++--------------------------------------------- |
| M | poe.1.in | | | 26 | +++++++++++++++----------- |
| M | poe.c | | | 371 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | poe.h | | | 5 | +++-- |
| M | util.c | | | 135 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
| M | util.h | | | 32 | +++++++++++++++++++++++++------- |
измењених датотека: 11, додавања: 1748(+), брисања: 1638(-)
diff --git a/TODO b/TODO
@@ -1,26 +1,27 @@
TODO
====
-[ ] Support Yudit's nonstandard PO format (no empty lines between individual
- entries)
-
[~] Tidy up basic logic everywhere (based on sled)
- [ ] Check cleanness against sled, function-by-function
- Last: save_msgstr
- [ ] Investigate insert_char
+ [x] Check cleanness against sled, function-by-function
+ [x] draw.c
+ [x] poe.c
+ [x] po.c
+ [x] util.c
+ [x] 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
- [ ] Get rid of SAVE_*
+ [x] Tidy up return codes and error handling
+ [x] Get rid of SAVE_*
[x] Introduce position_to (sled)
+ [x] Handle all TODO comments
+ [x] util.c: u32_match_msgid_ending
+ [x] Check L"" literals
-[x] Add -B, -b, -L, -W, -w
- [x] --no-backup
- [x] --backup
- [x] --dont-break-literals
- [x] --no-wrap
- [x] --wrap-width
+[ ] Document exit statuses in poe.1.in
+
+[ ] Support Yudit's nonstandard PO format (no empty lines between individual
+ entries)
< > Wrap long lines? Not if it would complicate the code too much.
diff --git a/TODO.done b/TODO.done
@@ -1,6 +1,15 @@
Done todos
==========
+[x] Add - to the list of whitespace characters
+
+[x] Add -B, -b, -L, -W, -w
+ [x] --no-backup
+ [x] --backup
+ [x] --dont-break-literals
+ [x] --no-wrap
+ [x] --wrap-width
+
[x] More sophisticated "not PO file" detection - avoid opening "binary"
(relatively speaking) files
diff --git a/draw.c b/draw.c
@@ -58,6 +58,7 @@ const char* errors[] = {
[ERR_ILLEGAL_ON_FIRST] = "Not allowed on first entry",
[ERR_SYNTAX] = "%s:%ld:%ld: Syntax error",
[ERR_NO_PLURAL_FORMS] = "No Plural-Forms (add manually)",
+ [ERR_BAD_NPLURALS] = "Cannot read nplurals",
[ERR_ERRNO_SET] = "System call/library function error"};
const char* actions[] = {
[ACT_WRITING] = "Writing...",
@@ -88,8 +89,8 @@ ssize_t
buffer_length(uint32_t* buffer, const ssize_t max_index)
{
uint32_t* pbuf = buffer;
- ssize_t len = 0;
ssize_t i;
+ ssize_t len = 0;
int w;
if (!pbuf)
@@ -97,7 +98,7 @@ buffer_length(uint32_t* buffer, const ssize_t max_index)
for (i = 0; *pbuf && len < max_index; i++)
{
- pbuf = buffer + i;
+ pbuf = &buffer[i];
if (*pbuf == '\t')
len += MIN(TAB_SIZE - (len % TAB_SIZE), max_index - len);
else
@@ -216,10 +217,10 @@ draw_box(const int startx, const int endx, const int starty, const int endy,
int
draw_help(const struct DrawState* state)
{
+ int maxx, maxy;
+ int row = 0;
int startx, endx, starty, endy;
int w, h;
- int row = 0;
- int maxx, maxy;
assert(state != NULL);
w = state->help_width;
@@ -254,13 +255,14 @@ int
draw_editbox(const struct DrawState* state)
{
struct PoEntry* entry;
+ struct BufferLine* curline;
char flags_buf[MAXFLAGSBUF];
char sbuf[LINE_DEFAULT];
ssize_t dlen, i;
uint16_t fg, bg;
+ int maxx, maxy;
int startx, endx, starty, endy;
int w, h;
- int maxx, maxy;
assert(state != NULL);
w = state->edit_width;
@@ -294,8 +296,7 @@ draw_editbox(const struct DrawState* state)
< state->info_rows_count;
i++)
{
- struct BufferLine* curline
- = &state->info_buffer[state->info_first_shown.row + i];
+ curline = &state->info_buffer[state->info_first_shown.row + i];
if (!curline || !curline->text)
return 1;
dlen = display_length(curline->text, curline->length);
@@ -318,13 +319,12 @@ draw_editbox(const struct DrawState* state)
: colors[C_EDIT_MSGSTR_FOCUS].bg;
draw_rect(startx + 1, endx - 1, endy - h / 2 - 1, endy - 2, fg, bg);
- for (ssize_t i = 0; i < (h - 3) / 2 + 1
+ for (i = 0; i < (h - 3) / 2 + 1
&& (ssize_t)state->input_first_shown.row + i
< state->input_rows_count;
i++)
{
- struct BufferLine* curline
- = &state->input_buffer[state->input_first_shown.row + i];
+ curline = &state->input_buffer[state->input_first_shown.row + i];
if (!curline || !curline->text)
return 1;
dlen = display_length(curline->text, curline->length);
@@ -370,9 +370,9 @@ draw_list_visible(const struct DrawState* state)
{
const struct PoEntry* current = NULL;
ssize_t i = 0;
+ int cy = 0;
int flags_len;
int max_screen_entries = 0;
- int cy = 0;
assert(state != NULL);
@@ -460,8 +460,9 @@ void
draw_rect(const int startx, const int endx, const int starty, const int endy,
const uint16_t fg, const uint16_t bg)
{
- for (int y = starty; y < endy; y++)
- for (int x = startx; x < endx; x++)
+ int x, y;
+ for (y = starty; y < endy; y++)
+ for (x = startx; x < endx; x++)
tb_set_cell(x, y, ' ', fg, bg);
}
@@ -470,9 +471,9 @@ draw_search(const struct DrawState* state)
{
ssize_t len;
ssize_t dlen = 0;
+ int maxx, maxy;
int startx, endx, starty, endy;
int w, h;
- int maxx, maxy;
assert(state != NULL);
w = state->search_width;
@@ -510,7 +511,7 @@ draw_status(const struct DrawState* state)
char* buf = NULL;
ssize_t seg_size;
int current_start;
- int maxx;
+ int last, maxx;
assert(state != NULL);
maxx = state->maxx;
@@ -545,7 +546,7 @@ draw_status(const struct DrawState* state)
else
while (pseg < status_segments + LEN(status_segments))
{
- int last = pseg - status_segments
+ last = pseg - status_segments
== LEN(status_segments) - 1;
buf = calloc(limits[L_LINE_MAX], 1);
if (!buf)
@@ -706,8 +707,6 @@ void
init_drawstate(struct DrawState* state, char* filename, char* prompt)
{
assert(state != NULL);
- state->error = ERR_NONE;
- state->action = ACT_IDLE;
state->prompt = prompt;
state->filename = filename;
state->orig_real_filename = NULL;
@@ -715,27 +714,23 @@ init_drawstate(struct DrawState* state, char* filename, char* prompt)
state->backup_filename = NULL;
state->rfn_len = 0;
state->search = NULL;
+ state->error = ERR_NONE;
+ state->action = ACT_IDLE;
state->input_buffer = NULL;
state->buffer_size = 0;
init_coord(&state->coord, 0, 0);
init_coord(&state->first_shown, 0, 0);
init_coord(&state->input_first_shown, 0, 0);
- // state->input_column = 0;
- // state->input_row = 0;
- /*state->input_first_shown_column = 0;
- state->input_first_shown_row = 0;*/
state->input_rows_count = 0;
state->input_display_column = 0;
state->input_changed_fuzzy = UNCHANGED;
state->saved_column = -1;
state->info_buffer = NULL;
init_coord(&state->info_first_shown, 0, 0);
- /*state->info_first_shown_column = 0;
- state->info_first_shown_row = 0;*/
state->info_rows_count = 0;
state->info_maxlen = 0;
- state->help_width = calculate_help_width(state);
state->edit_width = calculate_edit_width(state);
+ state->help_width = calculate_help_width(state);
state->search_width = calculate_search_width(state);
state->paste = NULL;
state->paste_count = 0;
@@ -751,15 +746,15 @@ init_drawstate(struct DrawState* state, char* filename, char* prompt)
state->dirty_before_edit = 0;
state->fuzzy_before_edit = 0;
state->in_prompt = 0;
- state->show_help = 0;
state->show_edit = 0;
+ state->show_help = 0;
state->edit_info_focused = 0;
state->show_search = 0;
state->recalculate_size = 1;
state->maxx = 0;
state->maxy = 0;
- state->msgid_number = state->msgid_count > 0 ? 1 : 0;
state->msgid_count = 0;
+ state->msgid_number = state->msgid_count > 0 ? 1 : 0;
state->msgid_size = 0;
state->fuzzy_count = 0;
state->untranslated_count = 0;
@@ -778,9 +773,10 @@ ssize_t
input_length(uint32_t* buffer, const ssize_t max_index)
{
uint32_t* pbuf = buffer;
- ssize_t len = 0;
ssize_t i = 0;
+ ssize_t len = 0;
+ assert(buffer != NULL);
for (i = 0; *pbuf && len < max_index; i++)
{
pbuf = buffer + i;
@@ -796,9 +792,11 @@ input_length(uint32_t* buffer, const ssize_t max_index)
size_t
real_msgid_to_display_msgid(const struct DrawState* state)
{
- struct PoEntry* current = state->entries;
- size_t ret = 1;
+ struct PoEntry* current;
+ size_t ret = 1;
+ assert((state != NULL) && (state->entries != NULL));
+ current = state->entries;
if (!state->msgid_count)
return 0;
@@ -824,49 +822,6 @@ recalculate_size(struct DrawState* state)
state->search_width = calculate_search_width(state);
}
-struct DrawState*
-set_nplurals(struct DrawState* state, struct PoEntry* entry)
-{
- if (!entry || !entry->plural_forms)
- return NULL;
-
- int read_number = 0;
- uint32_t* ppf = entry->plural_forms;
- char token[LINE_DEFAULT];
- char* ptoken = token;
-
- *ptoken = 0;
- while (*ppf)
- {
- if (u32_starts_with(ppf, (uint32_t*)L"nplurals="))
- {
- ppf += strlen("nplurals=");
- read_number = 1;
- }
- else if (read_number && *ppf >= '0' && *ppf <= '9')
- {
- *ptoken++ = *ppf++;
- *ptoken = 0;
- }
- else if (read_number && *ppf == ';')
- {
- *ptoken = 0;
- ptoken = token;
- break;
- }
- else
- ppf++;
- }
- if (*ptoken)
- {
- state->nplurals = strtol(ptoken, NULL, 0);
- if (errno)
- return NULL;
- }
-
- return state;
-}
-
/* mc - (max cols) pack text and padding into this many columns
* fc - (fill cols) this many columns from the left/right/center will be
* filled
@@ -928,6 +883,8 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
* reaches zero the highlighting is turned
* off */
+ int j;
+
c = mc - p_l - p_r;
if (align == LEFT)
@@ -939,11 +896,11 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
/* fill */
if (fill)
- for (int j = 0; j < fc; j++)
+ for (j = 0; j < fc; j++)
tb_set_cell(x + j, y, ' ', fg, bg);
/* left padding */
- for (int j = 0; j < p_l; j++)
+ for (j = 0; j < p_l; j++)
tb_set_cell(x + d + j, y, ' ', fg, bg);
sc = 0;
@@ -983,7 +940,7 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
* */
if (ssc - (ssc % ts) + ts >= ds)
{
- for (int j = 0;
+ for (j = 0;
j < ssc - (ssc % ts) + ts - ds;
j++)
tb_set_cell(x + d + p_l + sc + j,
@@ -1016,7 +973,7 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
* */
if (ssc + (ts - (ssc % ts)) >= ds + c)
{
- for (int j = 0; j < ds + c - ssc; j++)
+ for (j = 0; j < ds + c - ssc; j++)
tb_set_cell(x + d + p_l + sc + j,
y, ' ', cfg, cbg);
sc = c;
@@ -1036,7 +993,7 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
* | ssc
* ds
* */
- for (int j = 0; j < ts - (ssc % ts); j++)
+ for (j = 0; j < ts - (ssc % ts); j++)
tb_set_cell(x + d + p_l + sc + j,
y, ' ', cfg, cbg);
sc += ts - (ssc % ts);
@@ -1070,6 +1027,6 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
}
/* right padding */
- for (int j = 0; j < p_r; j++)
+ for (j = 0; j < p_r; j++)
tb_set_cell(x + d + p_l + c + j, y, ' ', fg, bg);
}
diff --git a/draw.h b/draw.h
@@ -100,10 +100,6 @@ struct DrawState {
struct Coord coord; /* buffer coordinates */
struct Coord first_shown; /* display coordinates */
struct Coord input_first_shown; /* display coordinates */
- /*int input_column;
- int input_row;*/
- /*int input_first_shown_column;
- int input_first_shown_row;*/
ssize_t input_rows_count; /* buffer parameter */
int input_display_column; /* display coordinate */
FlagChange input_changed_fuzzy;
@@ -111,12 +107,10 @@ struct DrawState {
struct BufferLine* info_buffer; /* information pane above
* edit box */
struct Coord info_first_shown; /* display coordinates */
- /*int info_first_shown_column;
- int info_first_shown_row;*/
int info_rows_count;
int info_maxlen;
- int help_width; /* display parameter */
int edit_width; /* display parameter */
+ int help_width; /* display parameter */
int search_width; /* display parameter */
struct BufferLine* paste;
ssize_t paste_count;
@@ -132,15 +126,15 @@ struct DrawState {
int dirty_before_edit;
ssize_t fuzzy_before_edit;
int in_prompt;
- int show_help;
int show_edit;
+ int show_help;
int edit_info_focused;
int show_search;
int recalculate_size;
int maxx;
int maxy;
- ssize_t msgid_number; /* "real" msgid (inc. obsolete msgids) */
ssize_t msgid_count; /* without obsolete msgids */
+ ssize_t msgid_number; /* "real" msgid (inc. obsolete msgids) */
ssize_t msgid_size;
ssize_t fuzzy_count;
ssize_t untranslated_count;
@@ -198,7 +192,6 @@ void init_drawstate(struct DrawState* state, char* filename, char* prompt);
ssize_t input_length(uint32_t* buffer, const ssize_t max_index);
size_t real_msgid_to_display_msgid(const struct DrawState* state);
void recalculate_size(struct DrawState* state);
-struct DrawState* set_nplurals(struct DrawState* state, struct PoEntry* entry);
void u32_draw_string(const int x, const int y, const uint16_t fg,
const uint16_t bg, const uint32_t* s, const int max_cols,
const int fill_cols, const int padding_left, const int padding_right,
diff --git a/po.c b/po.c
@@ -17,12 +17,50 @@
#include "util.h"
#include "version.h"
+#define INC_COL() \
+ do \
+ { \
+ if (!dstate->error) \
+ (*col)++; \
+ } while (0)
+
extern const char* errors[];
extern const char* flag_strings[];
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);
+extern int redraw_status(struct DrawState* state);
+
+const uint32_t empty_string[] = {0};
+
+int
+add_ref_comment(struct PoEntry* entry, const char* comment)
+{
+ char** ref_comments = NULL;
+ char* new_line = NULL;
+ size_t len = 0;
+
+ assert((entry != NULL) && (comment != NULL));
+
+ entry->ref_comment_lines++;
+
+ if (!entry->ref_comments)
+ ref_comments = calloc(entry->ref_comment_lines, sizeof(char*));
+ else
+ ref_comments = realloc(entry->ref_comments,
+ entry->ref_comment_lines * sizeof(char*));
+ if (!ref_comments)
+ return 1;
+ entry->ref_comments = ref_comments;
+
+ len = strlen(comment) + 1;
+ new_line = calloc(len, 1);
+ if (!new_line)
+ return 1;
+ entry->ref_comments[entry->ref_comment_lines - 1] = new_line;
+ strncpy(new_line, comment, len);
+ return 0;
+}
char*
format_flags(char* buffer, const size_t max, const struct PoEntry* entry,
@@ -38,31 +76,6 @@ format_flags(char* buffer, const size_t max, const struct PoEntry* entry,
}
void
-init_po_entry(struct PoEntry* entry)
-{
- entry->flags = FL_NONE;
- entry->obsolete = 0;
- entry->warning = 0;
- entry->msgid = NULL;
- entry->msgid_size = 0;
- entry->msgid_len = 0;
- entry->msgid_plural = NULL;
- entry->msgid_plural_size = 0;
- entry->msgid_plural_len = 0;
- entry->plural_forms = NULL;
- entry->msgstr = NULL;
- entry->msgstr_count = 0;
- entry->msgstr_size = NULL;
- entry->msgstr_len = NULL;
- entry->comments = NULL;
- entry->comment_lines = 0;
- entry->extr_comments = NULL;
- entry->extr_comment_lines = 0;
- entry->ref_comments = NULL;
- entry->ref_comment_lines = 0;
-}
-
-void
free_po_entry(struct PoEntry* entry)
{
if (!entry)
@@ -107,453 +120,116 @@ free_po_entry(struct PoEntry* entry)
}
}
-struct PoEntry*
-set_flags(struct PoEntry* entry, const Flags flags)
+void
+init_po_entry(struct PoEntry* entry)
{
- if (!entry)
- return NULL;
- entry->flags = flags;
- return entry;
+ entry->flags = FL_NONE;
+ entry->obsolete = 0;
+ entry->warning = 0;
+ entry->msgid = NULL;
+ entry->msgid_size = 0;
+ entry->msgid_len = 0;
+ entry->msgid_plural = NULL;
+ entry->msgid_plural_size = 0;
+ entry->msgid_plural_len = 0;
+ entry->plural_forms = NULL;
+ entry->plural_forms_size = 0;
+ entry->plural_forms_len = 0;
+ entry->msgstr = NULL;
+ entry->msgstr_count = 0;
+ entry->msgstr_size = NULL;
+ entry->msgstr_len = NULL;
+ entry->comments = NULL;
+ entry->comment_lines = 0;
+ entry->extr_comments = NULL;
+ entry->extr_comment_lines = 0;
+ entry->ref_comments = NULL;
+ entry->ref_comment_lines = 0;
}
int
-set_msgid(struct DrawState* state, struct PoEntry* entry, const char* msgid,
- int append)
+load_file(struct DrawState* dstate, long* lineno, long* col)
{
- uint32_t umsgid[MAXMSGLINE];
- size_t msgid_len = 0;
- assert(entry != NULL);
- if (msgid)
- msgid_len = u8_string_to_unicode(umsgid, msgid, MAXMSGLINE);
- return u32_set_msgid(state, entry, umsgid, msgid_len, append);
-}
+ struct PoEntry* newchunk = NULL;
+ struct PoEntry* entry = NULL;
+ struct PoEntry* current = NULL;
+ FILE* input = NULL;
+ char* input_line = NULL;
+ ParseState pstate = PS_NONE;
+ int has_plural_msgid = 0;
+ ssize_t input_size;
+ ssize_t non_obsolete_sofar = 0;
+ /* lines to tolerate the lack of msgid */
+ int msgid_counter = PO_DETECTION_LINES;
+ int msgstr_index = -1;
+ int possible_nulbyte;
-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_len = 0;
- assert(entry != NULL);
- if (msgid_plural)
- msgid_plural_len = u8_string_to_unicode(umsgid_plural,
- msgid_plural, MAXMSGLINE);
- return u32_set_msgid_plural(state, entry, umsgid_plural,
- msgid_plural_len, append);
-}
+ assert((dstate != NULL) && (limits != NULL));
+ input_size = limits[L_LINE_MAX];
+ input_line = malloc(input_size);
+ if (!input_line)
+ goto load_file_alloc_error;
+ dstate->msgid_size = 0;
+ newchunk = calloc(ALLOC_DELTA, sizeof(struct PoEntry));
+ if (!newchunk)
+ goto load_file_alloc_error;
-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)
- 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);
-}
+ dstate->msgid_count = 0;
+ dstate->msgid_size = ALLOC_DELTA;
+ dstate->entries = newchunk;
+ entry = dstate->entries;
+ dstate->untranslated_count++;
-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(state, entry, umsgstr, msgstr_index, append);
-}
+ if (!(input = fopen(dstate->filename, "rt")))
+ return 1;
-int
-u32_set_msgid(struct DrawState* state, struct PoEntry* entry,
- const uint32_t* msgid, size_t msgid_len, int append)
-{
- uint32_t* temp = NULL;
+ dstate->action = ACT_READING;
+ if (redraw_status(dstate))
+ return 1;
- 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)
+ possible_nulbyte = 0;
+ *lineno = 1;
+ while (!feof(input))
{
- entry->msgid_size += MSGDELTA;
- 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 (append)
- U32_MEMCCPY(entry->msgid + entry->msgid_len - msgid_len, msgid,
- entry->msgid_size - msgid_len, temp);
- else
- U32_MEMCCPY(entry->msgid, msgid, entry->msgid_size, temp);
- return 0;
+ char* eol = NULL;
+ char* nulbyte = NULL;
-u32_set_msgid_alloc_error:
- state->error = ERR_CANT_ALLOC;
- return 1;
-}
+ if (!fgets(input_line, input_size, input))
+ {
+ if (ferror(input))
+ {
+ fclose(input);
+ return 1;
+ }
+ else
+ continue;
+ }
-int
-u32_set_msgid_plural(struct DrawState* state, struct PoEntry* entry,
- const uint32_t* msgid_plural, size_t msgid_plural_len, int append)
-{
- uint32_t* temp = NULL;
+ if (possible_nulbyte)
+ {
+ /* Definitely not EOF, NUL byte confirmed */
+ dstate->error = ERR_NOTPO_FILE;
+ fclose(input);
+ free(input_line);
+ return 1;
+ }
+ eol = strchr(input_line, '\n');
+ if (eol)
+ *eol = 0;
+ nulbyte = strchr(input_line, 0);
- assert((state != NULL) && (entry != NULL));
- if (msgid_plural)
- msgid_plural_len = u32_strlen(msgid_plural);
- if (!entry->msgid_plural)
- {
- entry->msgid_plural_size = MSGDELTA;
- 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;
- 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 (append)
- U32_MEMCCPY(entry->msgid_plural + entry->msgid_plural_len
- - msgid_plural_len,
- msgid_plural,
- entry->msgid_plural_size - msgid_plural_len, temp);
- else
- U32_MEMCCPY(entry->msgid_plural, msgid_plural,
- entry->msgid_plural_size, temp);
- return 0;
+ /* We don't know if the NUL byte not being equal to
+ * (possibly NULL) eol is the result of EOF or not
+ */
+ if (nulbyte && (nulbyte != eol))
+ possible_nulbyte = 1;
-u32_set_msgid_plural_alloc_error:
- state->error = ERR_CANT_ALLOC;
- return 1;
-}
+ if (parse_po_line(input_line, dstate, &entry, &pstate, col,
+ &msgstr_index))
+ goto load_file_cleanup;
-int
-u32_set_plural_forms(struct DrawState* state, struct PoEntry* entry,
- const uint32_t* plural_forms, const size_t plural_forms_len, int append)
-{
- uint32_t* temp = NULL;
-
- assert((state != NULL) && (entry != NULL));
- if (plural_forms_len >= MSGDELTA)
- return 1;
- if (!entry->plural_forms)
- {
- entry->plural_forms_size = MSGDELTA;
- entry->plural_forms_len = 0;
- entry->plural_forms = calloc(MAXMSGLINE, sizeof(uint32_t));
- if (!entry->plural_forms)
- 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_MEMCCPY(entry->plural_forms + entry->plural_forms_size
- - plural_forms_len,
- plural_forms,
- entry->plural_forms_size - plural_forms_len, temp);
- else
- 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;
-}
-
-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;
-
- assert((state != NULL) && (entry != NULL));
- if (msgstr)
- msgstr_len = u32_strlen(msgstr);
- if (entry->msgstr_count == 0 || msgstr_index + 1 > entry->msgstr_count)
- {
- uint32_t** newmsgstr = NULL;
- size_t* newmsgstr_size = NULL;
- size_t* newmsgstr_len = NULL;
- entry->msgstr_count = msgstr_index + 1;
- if (!entry->msgstr)
- {
- 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)
- state->untranslated_count--;
- }
- else
- {
- 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));
- 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;
- }
- if (!entry->msgstr[msgstr_index])
- {
- entry->msgstr_size[msgstr_index] = MSGDELTA;
- 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])
- {
- entry->msgstr_size[msgstr_index] += MSGDELTA;
- entry->msgstr[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 (append)
- U32_MEMCCPY(entry->msgstr[msgstr_index]
- + entry->msgstr_len[msgstr_index] - msgstr_len,
- msgstr, entry->msgstr_size[msgstr_index] - msgstr_len,
- temp);
- else
- 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*
-u32_add_comment(struct PoEntry* entry, const uint32_t* comment)
-{
- uint32_t** comments = NULL;
- uint32_t* new_line = NULL;
- size_t len = 0;
-
- if (!entry)
- return NULL;
-
- entry->comment_lines++;
- if (!entry->comments)
- comments = calloc(entry->comment_lines, sizeof(uint32_t*));
- else
- comments = realloc(entry->comments,
- entry->comment_lines * sizeof(uint32_t*));
- if (!comments)
- return NULL;
- entry->comments = comments;
-
- len = u32_strlen(comment) + 1;
- new_line = calloc(len, sizeof(uint32_t));
- if (!new_line)
- return NULL;
- entry->comments[entry->comment_lines - 1] = new_line;
- u32_strncpy(new_line, comment, len);
- return entry;
-}
-
-struct PoEntry*
-u32_add_extr_comment(struct PoEntry* entry, const uint32_t* extr_comment)
-{
- uint32_t** extr_comments = NULL;
- uint32_t* new_line = NULL;
- size_t len = 0;
-
- if (!entry)
- return NULL;
-
- entry->extr_comment_lines++;
- if (!entry->extr_comments)
- extr_comments
- = calloc(entry->extr_comment_lines, sizeof(uint32_t*));
- else
- extr_comments = realloc(entry->extr_comments,
- entry->extr_comment_lines * sizeof(uint32_t*));
- if (!extr_comments)
- return NULL;
- entry->extr_comments = extr_comments;
-
- len = u32_strlen(extr_comment) + 1;
- new_line = calloc(len, sizeof(uint32_t));
- if (!new_line)
- return NULL;
- entry->extr_comments[entry->extr_comment_lines - 1] = new_line;
- u32_strncpy(new_line, extr_comment, len);
- return entry;
-}
-
-struct PoEntry*
-add_ref_comment(struct PoEntry* entry, const char* comment)
-{
- char** ref_comments = NULL;
- char* new_line = NULL;
- size_t len = 0;
-
- if (!entry)
- return NULL;
-
- entry->ref_comment_lines++;
-
- if (!entry->ref_comments)
- ref_comments = calloc(entry->ref_comment_lines, sizeof(char*));
- else
- ref_comments = realloc(entry->ref_comments,
- entry->ref_comment_lines * sizeof(char*));
- if (!ref_comments)
- return NULL;
- entry->ref_comments = ref_comments;
-
- len = strlen(comment) + 1;
- new_line = calloc(len, 1);
- if (!new_line)
- return NULL;
- entry->ref_comments[entry->ref_comment_lines - 1] = new_line;
- strncpy(new_line, comment, len);
- return entry;
-}
-
-int
-load_file(struct DrawState* dstate, long* lineno, long* col)
-{
- struct PoEntry* newchunk = NULL;
- struct PoEntry* entry = NULL;
- struct PoEntry* current = NULL;
- FILE* input = NULL;
- char* input_line = NULL;
- ParseState pstate = PS_NONE;
- int has_plural_msgid = 0;
- ssize_t input_size = limits[L_LINE_MAX];
- ssize_t non_obsolete_sofar = 0;
- /* lines to tolerate the lack of msgid */
- int msgid_counter = PO_DETECTION_LINES;
- int msgstr_index = -1;
- int possible_nulbyte;
-
- assert(dstate != NULL);
- input_line = malloc(input_size);
- if (!input_line)
- goto load_file_alloc_error;
- dstate->msgid_size = 0;
- newchunk = calloc(ALLOC_DELTA, sizeof(struct PoEntry));
- if (!newchunk)
- goto load_file_alloc_error;
-
- dstate->msgid_count = 0;
- dstate->msgid_size = ALLOC_DELTA;
- dstate->entries = newchunk;
- entry = dstate->entries;
- dstate->untranslated_count++;
-
- if (!(input = fopen(dstate->filename, "rt")))
- return 1;
-
- dstate->action = ACT_READING;
- redraw_status(dstate);
-
- possible_nulbyte = 0;
- *lineno = 1;
- while (!feof(input))
- {
- char* eol = NULL;
- char* nulbyte = NULL;
-
- if (!fgets(input_line, input_size, input))
- {
- if (ferror(input))
- {
- fclose(input);
- return 1;
- }
- else
- continue;
- }
-
- if (possible_nulbyte)
- {
- /* Definitely not EOF, NUL byte confirmed */
- dstate->error = ERR_NOTPO_FILE;
- fclose(input);
- free(input_line);
- return 1;
- }
- eol = strchr(input_line, '\n');
- if (eol)
- *eol = 0;
- nulbyte = strchr(input_line, 0);
-
- /* We don't know if the NUL byte not being equal to
- * (possibly NULL) eol is the result of EOF or not
- */
- if (nulbyte && (nulbyte != eol))
- possible_nulbyte = 1;
-
- if (parse_po_line(input_line, dstate, &entry, &pstate, col,
- &msgstr_index))
- goto load_file_cleanup;
-
- if (entry && entry->msgid_plural)
- has_plural_msgid = 1;
+ if (entry && entry->msgid_plural)
+ has_plural_msgid = 1;
switch (dstate->error)
{
@@ -636,700 +312,159 @@ load_file_alloc_error:
}
int
-save_comment(FILE* output, struct DrawState* state,
- const struct PoEntry* current)
-{
- char* u8_comment = NULL;
- char* temp = NULL;
- size_t c, len, size;
-
- assert((output != NULL) && (state != NULL) && (current != NULL));
- for (c = 0; c < current->comment_lines; c++)
- {
- len = u32_strlen(current->comments[c]);
- size = len * UTF8REPMAX + 1;
- temp = realloc(u8_comment, size);
- if (!temp)
- {
- state->error = ERR_CANT_ALLOC;
- return 1;
- }
- u8_comment = temp;
- unicode_string_to_u8(u8_comment, current->comments[c], len);
- fprintf(output, "#%s%s\n", current->obsolete ? "~ " : "",
- u8_comment);
- }
- free(u8_comment);
- return 0;
-}
-
-int
-save_file(struct DrawState* state)
+parse_po_line(const char* line, struct DrawState* dstate,
+ struct PoEntry** current_entry, ParseState* pstate, long* col,
+ int* msgstr_index)
{
- FILE* output = NULL;
- const struct PoEntry* current = NULL;
- struct stat st;
- int result = 0;
- int saved_errno;
-
- assert(state != NULL);
-
- state->action = ACT_WRITING;
- redraw_status(state);
- errno = 0;
-
- current = state->entries;
- if (!create_backups)
- goto save_skip_backup_copy;
- if (!backup_fail && !state->backup_possible)
- goto save_skip_backup_copy;
+ char* ptoken = NULL;
+ const char* pline = line;
+ char* token = NULL;
+ size_t i = 0;
+ size_t len;
- if ((unlink(state->backup_filename) < 0) && (errno != ENOENT))
- {
- state->error = ERR_ERRNO_SET;
- result = 1;
- goto save_file_cleanup;
- }
+ assert((line != NULL) && (limits != NULL));
+ *col = 1;
+ token = malloc(limits[L_LINE_MAX]);
+ if (!token)
+ goto parse_po_line_alloc_error;
+ *token = 0;
+ ptoken = token;
- if (cp(state->rfn_len > 0 ? state->real_filename : state->filename,
- state->backup_filename))
+ if (starts_with(line, "msgid_plural "))
{
- if (backup_fail)
- {
- state->error = ERR_ERRNO_SET;
- result = 1;
- goto save_file_cleanup;
- }
- else
- errno = 0; /* ignore errors */
+ len = strlen("msgid_plural ");
+ *pstate &= ~PS_MSGID;
+ *pstate |= PS_MSGID_PLURAL;
+ pline += len;
+ *col += len;
}
-
-save_skip_backup_copy:
- if (!(output = fopen(state->rfn_len > 0 ? state->real_filename
- : state->filename,
- "wt")))
+ else if (starts_with(line, "msgid "))
{
- state->error = ERR_ERRNO_SET;
- result = 1;
- goto save_file_cleanup;
+ len = strlen("msgid ");
+ *pstate |= PS_MSGID;
+ pline += len;
+ *col += len;
}
-
- if (!create_backups)
- goto save_skip_backup_symlink;
-
- if (lstat(state->rfn_len > 0 ? state->real_filename : state->filename,
- &st)
- < 0)
+ else if (starts_with(line, "msgstr["))
{
- state->error = ERR_ERRNO_SET;
- result = 1;
- goto save_file_cleanup;
- }
+ len = strlen("msgstr[");
+ *pstate &= ~PS_MSGID;
+ *pstate &= ~PS_MSGID_PLURAL;
+ *pstate |= PS_MSGSTR_ARRAY;
+ (*msgstr_index)++;
+ pline += len;
+ *col += len;
- if (!backup_fail && !state->backup_possible)
- goto save_skip_backup_symlink;
+ while (*pline >= '0' && *pline <= '9')
+ {
+ pline++;
+ (*col)++;
+ }
- if (state->rfn_len > 0)
- {
- if (unlink(state->filename) == -1)
+ if (starts_with(pline, "] "))
{
- state->error = ERR_ERRNO_SET;
- result = 1;
- goto save_file_cleanup;
+ pline += 2;
+ (*col) += 2;
}
- if (symlink(state->orig_real_filename, state->filename) == -1)
+ else
{
- state->error = ERR_ERRNO_SET;
- result = 1;
- goto save_file_cleanup;
+ dstate->error = ERR_SYNTAX;
+ goto parse_po_cleanup;
}
}
- chmod(state->rfn_len > 0 ? state->real_filename : state->filename,
- st.st_mode);
-
-save_skip_backup_symlink:
- /*if (state->rows_count == 1 && state->buffer[0].length == 0)
- goto save_file_cleanup;*/
-
- ;
-
-save_loop_entries_start:
- if (current >= state->entries + state->real_msgid_count)
- goto save_loop_entries_done;
-
- if (!current->obsolete && current->comment_lines > 0)
- if (save_comment(output, state, current))
- goto save_file_error_cleanup;
- if (current->extr_comment_lines > 0)
- if (save_extr_comment(output, state, current))
- goto save_file_error_cleanup;
- if (current->ref_comment_lines > 0)
- if (save_ref_comment(output, state, current))
- goto save_file_error_cleanup;
- if (save_flags(output, state, current))
- goto save_file_error_cleanup;
- if (current->obsolete && current->comment_lines > 0)
- if (save_comment(output, state, current))
- goto save_file_error_cleanup;
-
- if (current->obsolete)
+ else if (starts_with(line, "msgstr "))
{
- if (current < state->entries + state->real_msgid_count - 1)
- fprintf(output, "\n");
- current++;
- goto save_loop_entries_start;
+ len = strlen("msgstr ");
+ *pstate &= ~PS_MSGID;
+ *pstate &= ~PS_MSGID_PLURAL;
+ *pstate |= PS_MSGSTR;
+ pline += len;
+ *col += len;
}
-
- save_msgid(output, state, current);
- if (current->msgid_plural)
- if (save_msgid_plural(output, state, current))
- goto save_file_error_cleanup;
-
- if (save_msgstrs(output, state, current))
- goto save_file_error_cleanup;
-
- if (current < state->entries + state->real_msgid_count - 1)
- fprintf(output, "\n");
- current++;
- goto save_loop_entries_start;
-
- /*save_file_alloc_error:
- if (output)
- fclose(output);
- return 1;*/
-
-save_file_error_cleanup:
- result = 1;
-
-save_loop_entries_done:
-save_file_cleanup:
- saved_errno = errno;
- if (output)
- fclose(output);
- state->action = ACT_IDLE;
- errno = saved_errno;
- return result;
-}
-
-int
-save_flags(FILE* output, struct DrawState* state, const struct PoEntry* current)
-{
- Flags flags;
-
- assert((output != NULL) && (state != NULL) && (current != NULL));
- flags = current->flags;
- if (flags != FL_NONE)
- fprintf(output, "#, ");
- while (flags != FL_NONE)
+ else if (*line == 0)
{
- if (flags & FL_C_FORMAT)
- {
- flags &= ~FL_C_FORMAT;
- fprintf(output, "%s", flag_strings[FL_C_FORMAT]);
- }
- else if (flags & FL_NO_C_FORMAT)
- {
- flags &= ~FL_NO_C_FORMAT;
- fprintf(output, "%s", flag_strings[FL_NO_C_FORMAT]);
- }
- else if (flags & FL_FUZZY)
- {
- flags &= ~FL_FUZZY;
- fprintf(output, "%s", flag_strings[FL_FUZZY]);
- }
- else
- flags = FL_NONE; /* see po.h */
-
- if (flags != FL_NONE)
- fprintf(output, ", ");
+ *pstate &= ~PS_MSGID;
+ *pstate &= ~PS_MSGID_PLURAL;
+ *pstate &= ~PS_MSGSTR;
+ *pstate &= ~PS_MSGSTR_ARRAY;
}
- if (current->flags != FL_NONE)
- fprintf(output, "\n");
- return 0;
-}
-
-int
-save_msgid(FILE* output, struct DrawState* state, const struct PoEntry* current)
-{
- const uint32_t* pumsgid = NULL;
- const uint32_t* old_pumsgid = NULL;
- char* u8_msgid = NULL;
- 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)
+ else if (*line != ' ' && *line != '\t' && *line != '"' && *line != '#')
{
- fprintf(output, "msgid \"\"\n");
- return 0;
+ dstate->error = ERR_SYNTAX;
+ goto parse_po_cleanup;
}
- num_lines = u32_lines_in_string(current->msgid, 1, wrap_width);
- if ((num_lines > 1)
- || u32_strlen(current->msgid) + strlen("msgid: \"") + 1
- > (size_t)literal_break_threshold)
- {
- pumsgid = current->msgid;
- fprintf(output, "msgid %s", break_literals ? "\"\"\n" : "");
- while (*pumsgid)
- {
- u8_msgid = NULL;
- old_pumsgid = pumsgid;
- len = u32_next_line(current->msgid, &pumsgid, 1,
- wrap_width);
- if (len == 0)
+ while (*pline && i < strlen(line))
+ {
+ switch (*pline)
+ {
+ case ' ':
+ case '\t':
+ if (*pstate & PS_COMMENT)
{
- first_line = 0;
- continue;
+ *ptoken++ = *pline++;
+ INC_COL();
}
-
- size = len * UTF8REPMAX + 1;
-
- u8_msgid = malloc(size);
- if (!u8_msgid)
+ else if (*pstate & PS_STRING)
{
- state->error = ERR_CANT_ALLOC;
- return 1;
+ *ptoken++ = *pline++;
+ INC_COL();
}
-
- memset(u8_msgid, 0, size);
-
- unicode_string_to_u8(u8_msgid, old_pumsgid, len);
- fprintf(output, "%s%s\"\n",
- break_literals && first_line ? "" : "\"",
- u8_msgid);
- free(u8_msgid);
- first_line = 0;
- }
- }
- else
- {
- size = current->msgid_size * UTF8REPMAX + 1;
- u8_msgid = malloc(size);
- if (!u8_msgid)
- {
- state->error = ERR_CANT_ALLOC;
- return 1;
- }
-
- memset(u8_msgid, 0, size);
-
- unicode_string_to_u8(u8_msgid, current->msgid,
- current->msgid_size);
- fprintf(output, "msgid \"%s\"\n", u8_msgid);
- free(u8_msgid);
- }
- return 0;
-}
-
-int
-save_msgid_plural(FILE* output, struct DrawState* state,
- const struct PoEntry* current)
-{
- const uint32_t* old_pumsgid = NULL;
- const uint32_t* pumsgid = NULL;
- 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)
- + strlen("msgid_plural: \"") + 1
- > (size_t)literal_break_threshold)
- {
- pumsgid = current->msgid_plural;
- fprintf(output, "msgid_plural %s",
- break_literals ? "\"\"\n" : "");
- while (*pumsgid)
- {
- u8_msgid = NULL;
- old_pumsgid = pumsgid;
- len = u32_next_line(current->msgid_plural, &pumsgid, 1,
- wrap_width);
- if (len == 0)
+ else
{
- first_line = 0;
- continue;
+ pline++;
+ INC_COL();
}
-
- size = len * UTF8REPMAX + 1;
- u8_msgid = malloc(size);
- if (!u8_msgid)
+ break;
+ case '#':
+ if (pline - line + 1 == 1)
{
- state->error = ERR_CANT_ALLOC;
- return 1;
+ *pstate |= PS_COMMENT_TRAN;
+ pline++;
+ INC_COL();
}
-
- memset(u8_msgid, 0, size);
-
- unicode_string_to_u8(u8_msgid, old_pumsgid, len);
- fprintf(output, "%s%s\"\n",
- break_literals && first_line ? "" : "\"",
- u8_msgid);
- first_line = 0;
- free(u8_msgid);
- }
- }
- else
- {
- size = current->msgid_plural_size * UTF8REPMAX + 1;
- u8_msgid = malloc(size);
- if (!u8_msgid)
- {
- state->error = ERR_CANT_ALLOC;
- return 1;
- }
-
- memset(u8_msgid, 9, size);
-
- msgid_plural_len = u32_strlen(current->msgid_plural);
- unicode_string_to_u8(u8_msgid, current->msgid_plural,
- msgid_plural_len);
- fprintf(output, "msgid_plural \"%s\"\n", u8_msgid);
- free(u8_msgid);
- }
- return 0;
-}
-
-int
-save_msgstrs(FILE* output, struct DrawState* state,
- const struct PoEntry* current)
-{
- const uint32_t* pumsgstr = NULL;
- const uint32_t* old_pumsgstr = NULL;
- char now[MAXDATEBUF];
- char* u8_msgstr = NULL;
- struct tm* now_tm = NULL;
- time_t t;
- ssize_t m, num_lines;
- size_t len, size, msgstr_len;
- int i;
- int seen_generator = 0;
- int seen_plural_forms = 0;
- int first_entry, first_line;
-
- assert((output != NULL) && (state != NULL) && (current != NULL));
- first_entry = (current == state->entries) && !current->msgid;
- if (!current->msgstr_count)
- {
- if (current->msgid_plural)
- for (i = 0; i < state->nplurals; i++)
- fprintf(output, "msgstr[%d] \"\"\n", i);
- else
- fprintf(output, "msgstr \"\"\n");
- return 0;
- }
- if (current->msgstr_count == 1)
- {
- t = time(NULL);
- now_tm = localtime(&t);
- strftime(now, MAXDATEBUF, "%F %H:%M%z", now_tm);
- }
- 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])
- + (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 %s",
- break_literals ? "\"\"\n" : "");
- else
- fprintf(output, "msgstr[%ld] %s", m,
- break_literals ? "\"\"\n" : "");
-
- save_msgstrs_pumsgstr_loop:
- old_pumsgstr = pumsgstr;
- len = u32_next_line(current->msgstr[m], &pumsgstr, 1,
- wrap_width);
- if (len == 0)
- goto save_msgstrs_pumsgstr_done;
- size = len * UTF8REPMAX + 1;
- u8_msgstr = malloc(size);
- if (!u8_msgstr)
+ else if (*pstate & (PS_STRING | PS_COMMENT))
{
- state->error = ERR_CANT_ALLOC;
- return 1;
+ *ptoken++ = *pline++;
+ INC_COL();
}
- memset(u8_msgstr, 0, size);
-
- unicode_string_to_u8(u8_msgstr, old_pumsgstr, len);
- if (first_entry
- && starts_with(u8_msgstr, "X-Generator: "))
+ else
{
- seen_generator = 1;
- fprintf(output, "\"X-Generator: poe %s\\n\"\n",
- VERSION);
+ dstate->error = ERR_SYNTAX;
+ goto parse_po_cleanup;
}
- else if (first_entry && plural_string
- && starts_with(u8_msgstr, "Plural-Forms: "))
+ break;
+ case '.':
+ if (pline - line + 1 == 2 && *pstate & PS_COMMENT_TRAN)
{
- seen_plural_forms = 1;
- fprintf(output, "\"Plural-Forms: %s\\n\"\n",
- plural_string);
+ *pstate &= ~PS_COMMENT_TRAN;
+ *pstate |= PS_COMMENT_EXTR;
+ pline++;
+ INC_COL();
+ while (*pline == ' ' || *pline == '\t')
+ {
+ pline++;
+ INC_COL();
+ }
}
else
- fprintf(output, "%s%s\"\n",
- break_literals && first_line ? "" : "\"",
- u8_msgstr);
- free(u8_msgstr);
- first_line = 0;
- if (*pumsgstr)
- goto save_msgstrs_pumsgstr_loop;
-
- save_msgstrs_pumsgstr_done:
- if (first_entry && !seen_generator)
- fprintf(output, "\"X-Generator: poe %s\\n\"\n",
- VERSION);
- if (first_entry && plural_string && !seen_plural_forms)
- fprintf(output, "\"Plural-Forms: %s\\n\"\n",
- plural_string);
- }
- else
- {
- size = MAXMSGLINE * UTF8REPMAX + 1;
- u8_msgstr = malloc(size);
- if (!u8_msgstr)
{
- state->error = ERR_CANT_ALLOC;
- return 1;
- }
- msgstr_len = u32_strlen(current->msgstr[m]);
- unicode_string_to_u8(u8_msgstr, current->msgstr[m],
- msgstr_len);
- if (current->msgstr_count == 1)
- fprintf(output, "msgstr \"%s\"\n", u8_msgstr);
- else
- fprintf(output, "msgstr[%ld] \"%s\"\n", m,
- u8_msgstr);
- free(u8_msgstr);
- }
- }
- return 0;
-}
-
-int
-save_ref_comment(FILE* output, struct DrawState* state,
- const struct PoEntry* current)
-{
- size_t rc;
- assert((output != NULL) && (state != NULL) && (current != NULL));
- for (rc = 0; rc < current->ref_comment_lines; rc++)
- fprintf(output, "#: %s\n", current->ref_comments[rc]);
- return 0;
-}
-
-int
-save_extr_comment(FILE* output, struct DrawState* state,
- const struct PoEntry* current)
-{
- char* u8_extr_comment = NULL;
- char* temp = NULL;
- size_t tc, len, size;
-
- assert((output != NULL) && (state != NULL) && (current != NULL));
- for (tc = 0; tc < current->extr_comment_lines; tc++)
- {
- len = u32_strlen(current->extr_comments[tc]);
- size = len * UTF8REPMAX + 1;
-
- temp = realloc(u8_extr_comment, size);
- if (!temp)
- {
- state->error = ERR_CANT_ALLOC;
- return 1;
- }
- u8_extr_comment = temp;
- unicode_string_to_u8(u8_extr_comment,
- current->extr_comments[tc], len);
- fprintf(output, "#.%s%s\n", u8_extr_comment[0] == 0 ? "" : " ",
- u8_extr_comment);
- }
- free(u8_extr_comment);
- return 0;
-}
-
-#define INC_COL() \
- do \
- { \
- if (!dstate->error) \
- (*col)++; \
- } while (0)
-
-int
-parse_po_line(const char* line, struct DrawState* dstate,
- struct PoEntry** current_entry, ParseState* pstate, long* col,
- int* msgstr_index)
-{
- const char* pline = line;
- char* token = NULL;
- char* ptoken = NULL;
- size_t i = 0;
- size_t len;
-
- assert(line != NULL);
-
- *col = 1;
-
- token = malloc(limits[L_LINE_MAX]);
- if (!token)
- goto parse_po_line_alloc_error;
- *token = 0;
- ptoken = token;
-
- if (starts_with(line, "msgid_plural "))
- {
- len = strlen("msgid_plural ");
- *pstate &= ~PS_MSGID;
- *pstate |= PS_MSGID_PLURAL;
- pline += len;
- *col += len;
- }
- else if (starts_with(line, "msgid "))
- {
- len = strlen("msgid ");
- *pstate |= PS_MSGID;
- pline += len;
- *col += len;
- }
- else if (starts_with(line, "msgstr["))
- {
- len = strlen("msgstr[");
- *pstate &= ~PS_MSGID;
- *pstate &= ~PS_MSGID_PLURAL;
- *pstate |= PS_MSGSTR_ARRAY;
- (*msgstr_index)++;
- pline += len;
- *col += len;
-
- while (*pline >= '0' && *pline <= '9')
- {
- pline++;
- (*col)++;
- }
-
- if (starts_with(pline, "] "))
- {
- pline += 2;
- (*col) += 2;
- }
- else
- {
- dstate->error = ERR_SYNTAX;
- goto parse_po_cleanup;
- }
- }
- else if (starts_with(line, "msgstr "))
- {
- len = strlen("msgstr ");
- *pstate &= ~PS_MSGID;
- *pstate &= ~PS_MSGID_PLURAL;
- *pstate |= PS_MSGSTR;
- pline += len;
- *col += len;
- }
- else if (*line == 0)
- {
- *pstate &= ~PS_MSGID;
- *pstate &= ~PS_MSGID_PLURAL;
- *pstate &= ~PS_MSGSTR;
- *pstate &= ~PS_MSGSTR_ARRAY;
- }
- else if (*line != ' ' && *line != '\t' && *line != '"' && *line != '#')
- {
- dstate->error = ERR_SYNTAX;
- goto parse_po_cleanup;
- }
-
- while (*pline && i < strlen(line))
- {
- switch (*pline)
- {
- case ' ':
- case '\t':
- if (*pstate & PS_COMMENT)
- {
- *ptoken++ = *pline++;
- INC_COL();
- }
- else if (*pstate & PS_STRING)
- {
- *ptoken++ = *pline++;
- INC_COL();
- }
- else
- {
- pline++;
- INC_COL();
- }
- break;
- case '#':
- if (pline - line + 1 == 1)
- {
- *pstate |= PS_COMMENT_TRAN;
- pline++;
- INC_COL();
- }
- else if (*pstate & (PS_STRING | PS_COMMENT))
- {
- *ptoken++ = *pline++;
- INC_COL();
- }
- else
- {
- dstate->error = ERR_SYNTAX;
- goto parse_po_cleanup;
- }
- break;
- case '.':
- if (pline - line + 1 == 2 && *pstate & PS_COMMENT_TRAN)
- {
- *pstate &= ~PS_COMMENT_TRAN;
- *pstate |= PS_COMMENT_EXTR;
- pline++;
- INC_COL();
- while (*pline == ' ' || *pline == '\t')
- {
- pline++;
- INC_COL();
- }
- }
- else
- {
- *ptoken++ = *pline++;
- INC_COL();
- }
- break;
- case ',':
- if (pline - line + 1 == 2 && *pstate & PS_COMMENT_TRAN)
- {
- *pstate &= ~PS_COMMENT_TRAN;
- *pstate |= PS_COMMENT_FLAG;
- pline++;
- INC_COL();
- while (*pline == ' ' || *pline == '\t')
- {
- pline++;
- INC_COL();
- }
+ *ptoken++ = *pline++;
+ INC_COL();
+ }
+ break;
+ case ',':
+ if (pline - line + 1 == 2 && *pstate & PS_COMMENT_TRAN)
+ {
+ *pstate &= ~PS_COMMENT_TRAN;
+ *pstate |= PS_COMMENT_FLAG;
+ pline++;
+ INC_COL();
+ while (*pline == ' ' || *pline == '\t')
+ {
+ pline++;
+ INC_COL();
+ }
}
else
{
@@ -1451,134 +586,1103 @@ parse_po_line(const char* line, struct DrawState* dstate,
*msgstr_index = -1;
}
- if (!*token)
- goto parse_po_empty_token;
+ if (!*token)
+ goto parse_po_empty_token;
+
+ if (*pstate & PS_MSGID)
+ {
+ 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)
+ {
+ if (starts_with(token, "Plural-Forms: "))
+ {
+ if (set_plural_forms(dstate, *current_entry,
+ token + strlen("Plural-Forms: "), 0))
+ goto parse_po_line_alloc_error;
+ if (set_nplurals(dstate, *current_entry))
+ goto parse_po_cleanup;
+ }
+ }
+
+ 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);
+ if (u32_add_comment(*current_entry, u32_token))
+ goto parse_po_line_alloc_error;
+ 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);
+ if (u32_add_extr_comment(*current_entry, u32_token))
+ goto parse_po_line_alloc_error;
+ free(u32_token);
+ }
+ else if (*pstate & PS_COMMENT_FLAG)
+ {
+ ptoken = token;
+ while (*ptoken)
+ {
+ 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 typedef Flags in po.h
+ * for rationale */
+ while (*ptoken)
+ ptoken++;
+ }
+ }
+ }
+ else if (*pstate & PS_COMMENT_REFN)
+ {
+ if (add_ref_comment(*current_entry, token))
+ goto parse_po_line_alloc_error;
+ }
+ 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))
+ goto parse_po_line_alloc_error;
+ else
+ (*current_entry)->obsolete = 1;
+ free(u32_token);
+ }
+ *token = 0;
+ goto parse_po_cleanup;
+
+parse_po_empty_token:
+ if (*pstate & PS_COMMENT_TRAN)
+ {
+ if (u32_add_comment(*current_entry, empty_string))
+ goto parse_po_line_alloc_error;
+ }
+ else if (*pstate & PS_COMMENT_EXTR)
+ {
+ if (u32_add_extr_comment(*current_entry, empty_string))
+ goto parse_po_line_alloc_error;
+ }
+
+parse_po_cleanup:
+ /* one-line states */
+ *pstate &= ~PS_COMMENT;
+ return !!dstate->error;
+
+parse_po_line_alloc_error:
+ dstate->error = ERR_CANT_ALLOC;
+ return 1;
+}
+
+int
+save_comment(FILE* output, struct DrawState* state,
+ const struct PoEntry* current)
+{
+ char* temp = NULL;
+ char* u8_comment = NULL;
+ ssize_t c, len, size;
+
+ assert((output != NULL) && (state != NULL) && (current != NULL));
+ for (c = 0; c < current->comment_lines; c++)
+ {
+ len = u32_strlen(current->comments[c]);
+ size = len * UTF8REPMAX + 1;
+ temp = realloc(u8_comment, size);
+ if (!temp)
+ {
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+ }
+ u8_comment = temp;
+ unicode_string_to_u8(u8_comment, current->comments[c], len);
+ fprintf(output, "#%s%s\n", current->obsolete ? "~ " : "",
+ u8_comment);
+ }
+ free(u8_comment);
+ return 0;
+}
+
+int
+save_extr_comment(FILE* output, struct DrawState* state,
+ const struct PoEntry* current)
+{
+ char* temp = NULL;
+ char* u8_extr_comment = NULL;
+ ssize_t tc, len, size;
+
+ assert((output != NULL) && (state != NULL) && (current != NULL));
+ for (tc = 0; tc < current->extr_comment_lines; tc++)
+ {
+ len = u32_strlen(current->extr_comments[tc]);
+ size = len * UTF8REPMAX + 1;
+
+ temp = realloc(u8_extr_comment, size);
+ if (!temp)
+ {
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+ }
+ u8_extr_comment = temp;
+ unicode_string_to_u8(u8_extr_comment,
+ current->extr_comments[tc], len);
+ fprintf(output, "#.%s%s\n", u8_extr_comment[0] == 0 ? "" : " ",
+ u8_extr_comment);
+ }
+ free(u8_extr_comment);
+ return 0;
+}
+
+int
+save_file(struct DrawState* state)
+{
+ FILE* output = NULL;
+ const struct PoEntry* current = NULL;
+ struct stat st;
+ int result = 0;
+ int saved_errno;
+
+ assert(state != NULL);
+ state->action = ACT_WRITING;
+ if (redraw_status(state))
+ return 1;
+ errno = 0;
+
+ current = state->entries;
+ if (!create_backups)
+ goto save_skip_backup_copy;
+ if (!backup_fail && !state->backup_possible)
+ goto save_skip_backup_copy;
+
+ if ((unlink(state->backup_filename) < 0) && (errno != ENOENT))
+ {
+ state->error = ERR_ERRNO_SET;
+ result = 1;
+ goto save_file_cleanup;
+ }
+
+ if (cp(state->rfn_len > 0 ? state->real_filename : state->filename,
+ state->backup_filename))
+ {
+ if (backup_fail)
+ {
+ state->error = ERR_ERRNO_SET;
+ result = 1;
+ goto save_file_cleanup;
+ }
+ else
+ errno = 0; /* ignore errors */
+ }
+
+save_skip_backup_copy:
+ if (!(output = fopen(state->rfn_len > 0 ? state->real_filename
+ : state->filename,
+ "wt")))
+ {
+ state->error = ERR_ERRNO_SET;
+ result = 1;
+ goto save_file_cleanup;
+ }
+
+ if (!create_backups)
+ goto save_skip_backup_symlink;
+
+ if (lstat(state->rfn_len > 0 ? state->real_filename : state->filename,
+ &st)
+ < 0)
+ {
+ state->error = ERR_ERRNO_SET;
+ result = 1;
+ goto save_file_cleanup;
+ }
+
+ if (!backup_fail && !state->backup_possible)
+ goto save_skip_backup_symlink;
+
+ if (state->rfn_len > 0)
+ {
+ if (unlink(state->filename) == -1)
+ {
+ state->error = ERR_ERRNO_SET;
+ result = 1;
+ goto save_file_cleanup;
+ }
+ if (symlink(state->orig_real_filename, state->filename) == -1)
+ {
+ state->error = ERR_ERRNO_SET;
+ result = 1;
+ goto save_file_cleanup;
+ }
+ }
+ chmod(state->rfn_len > 0 ? state->real_filename : state->filename,
+ st.st_mode);
+
+save_skip_backup_symlink:
+save_loop_entries_start:
+ if (current >= state->entries + state->real_msgid_count)
+ goto save_loop_entries_done;
+
+ if (!current->obsolete && current->comment_lines > 0)
+ if (save_comment(output, state, current))
+ goto save_file_error_cleanup;
+ if (current->extr_comment_lines > 0)
+ if (save_extr_comment(output, state, current))
+ goto save_file_error_cleanup;
+ if (current->ref_comment_lines > 0)
+ if (save_ref_comment(output, current))
+ goto save_file_error_cleanup;
+ if (save_flags(output, current))
+ goto save_file_error_cleanup;
+ if (current->obsolete && current->comment_lines > 0)
+ if (save_comment(output, state, current))
+ goto save_file_error_cleanup;
+
+ if (current->obsolete)
+ {
+ if (current < state->entries + state->real_msgid_count - 1)
+ fprintf(output, "\n");
+ current++;
+ goto save_loop_entries_start;
+ }
+
+ if (save_msgid(output, state, current))
+ goto save_file_error_cleanup;
+ if (current->msgid_plural)
+ if (save_msgid_plural(output, state, current))
+ goto save_file_error_cleanup;
+
+ if (save_msgstrs(output, state, current))
+ goto save_file_error_cleanup;
+
+ if (current < state->entries + state->real_msgid_count - 1)
+ fprintf(output, "\n");
+ current++;
+ goto save_loop_entries_start;
+
+save_file_error_cleanup:
+ result = 1;
+
+save_loop_entries_done:
+save_file_cleanup:
+ saved_errno = errno;
+ if (output)
+ fclose(output);
+ state->action = ACT_IDLE;
+ errno = saved_errno;
+ return result;
+}
+
+int
+save_flags(FILE* output, const struct PoEntry* current)
+{
+ Flags flags;
+
+ assert((output != NULL) && (current != NULL));
+ flags = current->flags;
+ if (flags != FL_NONE)
+ fprintf(output, "#, ");
+ while (flags != FL_NONE)
+ {
+ if (flags & FL_C_FORMAT)
+ {
+ flags &= ~FL_C_FORMAT;
+ fprintf(output, "%s", flag_strings[FL_C_FORMAT]);
+ }
+ else if (flags & FL_NO_C_FORMAT)
+ {
+ flags &= ~FL_NO_C_FORMAT;
+ fprintf(output, "%s", flag_strings[FL_NO_C_FORMAT]);
+ }
+ else if (flags & FL_FUZZY)
+ {
+ flags &= ~FL_FUZZY;
+ fprintf(output, "%s", flag_strings[FL_FUZZY]);
+ }
+ else
+ flags = FL_NONE; /* see po.h, typedef Flags */
+
+ if (flags != FL_NONE)
+ fprintf(output, ", ");
+ }
+ if (current->flags != FL_NONE)
+ fprintf(output, "\n");
+ return 0;
+}
+
+int
+save_msgid(FILE* output, struct DrawState* state, const struct PoEntry* current)
+{
+ const uint32_t* old_pumsgid = NULL;
+ const uint32_t* pumsgid = NULL;
+ char* u8_msgid = NULL;
+ size_t len = 0;
+ size_t num_lines;
+ size_t size;
+
+ assert((output != NULL) && (state != NULL) && (current != NULL));
+ if (!current->msgid)
+ {
+ fprintf(output, "msgid \"\"\n");
+ return 0;
+ }
+ num_lines = u32_lines_in_string(current->msgid, 1, wrap_width);
+ if ((num_lines > 1)
+ || u32_strlen(current->msgid) + strlen("msgid: \"") + 1
+ > (size_t)literal_break_threshold)
+ {
+ pumsgid = current->msgid;
+ fprintf(output, "msgid %s", break_literals ? "\"\"\n" : "");
+ while (*pumsgid)
+ {
+ u8_msgid = NULL;
+ old_pumsgid = pumsgid;
+
+ len = u32_next_line(current->msgid, &pumsgid, 1,
+ wrap_width);
+ if (len == 0)
+ continue;
+
+ size = len * UTF8REPMAX + 1;
+ u8_msgid = malloc(size);
+ if (!u8_msgid)
+ {
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+ }
+ memset(u8_msgid, 0, size);
+
+ unicode_string_to_u8(u8_msgid, old_pumsgid, len);
+ fprintf(output, "\"%s\"\n", u8_msgid);
+ free(u8_msgid);
+ }
+ }
+ else
+ {
+ size = current->msgid_size * UTF8REPMAX + 1;
+ u8_msgid = malloc(size);
+ if (!u8_msgid)
+ {
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+ }
+
+ memset(u8_msgid, 0, size);
+
+ unicode_string_to_u8(u8_msgid, current->msgid,
+ current->msgid_size);
+ fprintf(output, "msgid \"%s\"\n", u8_msgid);
+ free(u8_msgid);
+ }
+ return 0;
+}
+
+int
+save_msgid_plural(FILE* output, struct DrawState* state,
+ const struct PoEntry* current)
+{
+ const uint32_t* old_pumsgid = NULL;
+ const uint32_t* pumsgid = NULL;
+ char* u8_msgid = NULL;
+ size_t len = 0;
+ size_t msgid_plural_len, num_lines, size;
+
+ 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)
+ + strlen("msgid_plural: \"") + 1
+ > (size_t)literal_break_threshold)
+ {
+ pumsgid = current->msgid_plural;
+ fprintf(output, "msgid_plural %s",
+ break_literals ? "\"\"\n" : "");
+ while (*pumsgid)
+ {
+ u8_msgid = NULL;
+ old_pumsgid = pumsgid;
+ len = u32_next_line(current->msgid_plural, &pumsgid, 1,
+ wrap_width);
+ if (len == 0)
+ continue;
+
+ size = len * UTF8REPMAX + 1;
+ u8_msgid = malloc(size);
+ if (!u8_msgid)
+ {
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+ }
+
+ memset(u8_msgid, 0, size);
+
+ unicode_string_to_u8(u8_msgid, old_pumsgid, len);
+ fprintf(output, "\"%s\"\n", u8_msgid);
+ free(u8_msgid);
+ }
+ }
+ else
+ {
+ size = current->msgid_plural_size * UTF8REPMAX + 1;
+ u8_msgid = malloc(size);
+ if (!u8_msgid)
+ {
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+ }
+
+ memset(u8_msgid, 9, size);
+
+ msgid_plural_len = u32_strlen(current->msgid_plural);
+ unicode_string_to_u8(u8_msgid, current->msgid_plural,
+ msgid_plural_len);
+ fprintf(output, "msgid_plural \"%s\"\n", u8_msgid);
+ free(u8_msgid);
+ }
+ return 0;
+}
+
+int
+save_msgstrs(FILE* output, struct DrawState* state,
+ const struct PoEntry* current)
+{
+ struct tm* now_tm = NULL;
+ const uint32_t* old_pumsgstr = NULL;
+ const uint32_t* pumsgstr = NULL;
+ char now[MAXDATEBUF];
+ char* u8_msgstr = NULL;
+ time_t t;
+ ssize_t m, num_lines;
+ size_t len, size, msgstr_len, llen;
+ int i;
+ int seen_generator = 0;
+ int seen_plural_forms = 0;
+ int first_entry;
+
+ assert((output != NULL) && (state != NULL) && (current != NULL));
+ first_entry = (current == state->entries) && !current->msgid;
+ if (!current->msgstr_count)
+ {
+ if (current->msgid_plural)
+ for (i = 0; i < state->nplurals; i++)
+ fprintf(output, "msgstr[%d] \"\"\n", i);
+ else
+ fprintf(output, "msgstr \"\"\n");
+ return 0;
+ }
+ if (current->msgstr_count == 1)
+ {
+ t = time(NULL);
+ now_tm = localtime(&t);
+ strftime(now, MAXDATEBUF, "%F %H:%M%z", now_tm);
+ }
+ for (m = 0; m < current->msgstr_count; m++)
+ {
+ assert(current->msgstr);
+ num_lines = u32_lines_in_string(current->msgstr[m], 1,
+ wrap_width);
+
+ llen = (current->msgstr_count == 1 ? strlen("msgstr: \"")
+ : strlen("msgstr[ ]: \""))
+ + u32_strlen(current->msgstr[m]) + 1;
+ if ((num_lines > 1) || llen > (size_t)literal_break_threshold)
+ {
+ pumsgstr = current->msgstr[m];
+ if (current->msgstr_count == 1)
+ fprintf(output, "msgstr %s",
+ break_literals ? "\"\"\n" : "");
+ else
+ fprintf(output, "msgstr[%ld] %s", m,
+ break_literals ? "\"\"\n" : "");
+
+ save_msgstrs_pumsgstr_loop:
+ old_pumsgstr = pumsgstr;
+ len = u32_next_line(current->msgstr[m], &pumsgstr, 1,
+ wrap_width);
+ if (len == 0)
+ goto save_msgstrs_pumsgstr_done;
+ size = len * UTF8REPMAX + 1;
+ u8_msgstr = malloc(size);
+ if (!u8_msgstr)
+ {
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+ }
+ memset(u8_msgstr, 0, size);
+
+ unicode_string_to_u8(u8_msgstr, old_pumsgstr, len);
+ if (first_entry
+ && starts_with(u8_msgstr, "X-Generator: "))
+ {
+ seen_generator = 1;
+ fprintf(output, "\"X-Generator: poe %s\\n\"\n",
+ VERSION);
+ }
+ else if (first_entry && plural_string
+ && starts_with(u8_msgstr, "Plural-Forms: "))
+ {
+ seen_plural_forms = 1;
+ fprintf(output, "\"Plural-Forms: %s\\n\"\n",
+ plural_string);
+ }
+ else
+ fprintf(output, "\"%s\"\n", u8_msgstr);
+ free(u8_msgstr);
+ if (*pumsgstr)
+ goto save_msgstrs_pumsgstr_loop;
+
+ save_msgstrs_pumsgstr_done:
+ if (first_entry && !seen_generator)
+ fprintf(output, "\"X-Generator: poe %s\\n\"\n",
+ VERSION);
+ if (first_entry && plural_string && !seen_plural_forms)
+ fprintf(output, "\"Plural-Forms: %s\\n\"\n",
+ plural_string);
+ }
+ else
+ {
+ msgstr_len = u32_strlen(current->msgstr[m]);
+ size = (msgstr_len + 1) * UTF8REPMAX;
+ u8_msgstr = malloc(size);
+ if (!u8_msgstr)
+ {
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+ }
+ unicode_string_to_u8(u8_msgstr, current->msgstr[m],
+ msgstr_len);
+ if (current->msgstr_count == 1)
+ fprintf(output, "msgstr \"%s\"\n", u8_msgstr);
+ else
+ fprintf(output, "msgstr[%ld] \"%s\"\n", m,
+ u8_msgstr);
+ free(u8_msgstr);
+ }
+ }
+ return 0;
+}
+
+int
+save_ref_comment(FILE* output, const struct PoEntry* current)
+{
+ ssize_t rc;
+ assert((output != NULL) && (current != NULL));
+ for (rc = 0; rc < current->ref_comment_lines; rc++)
+ fprintf(output, "#: %s\n", current->ref_comments[rc]);
+ return 0;
+}
+
+int
+set_flags(struct PoEntry* entry, const Flags flags)
+{
+ assert(entry != NULL);
+ entry->flags = flags;
+ return 0;
+}
+
+int
+set_msgid(struct DrawState* state, struct PoEntry* entry, const char* msgid,
+ int append)
+{
+ uint32_t* umsgid = NULL;
+ size_t msgid_len = 0;
+ int result = 0;
+
+ assert(entry != NULL);
+ if (msgid)
+ msgid_len = strlen(msgid);
+ umsgid = calloc(msgid_len + 1, sizeof(uint32_t));
+ if (!umsgid)
+ goto set_msgid_alloc_error;
+ if (msgid)
+ (void)u8_string_to_unicode(umsgid, msgid, msgid_len);
+ result = u32_set_msgid(state, entry, umsgid, msgid_len, append);
+ free(umsgid);
+ return result;
+
+set_msgid_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+}
+
+int
+set_msgid_plural(struct DrawState* state, struct PoEntry* entry,
+ const char* msgid_plural, int append)
+{
+ uint32_t* umsgid_plural = NULL;
+ size_t msgid_plural_len = 0;
+ int result = 0;
+
+ assert(entry != NULL);
+ if (msgid_plural)
+ msgid_plural_len = strlen(msgid_plural);
+ umsgid_plural = calloc(msgid_plural_len + 1, sizeof(uint32_t));
+ if (!umsgid_plural)
+ goto set_msgid_plural_alloc_error;
+ if (msgid_plural)
+ (void)u8_string_to_unicode(umsgid_plural, msgid_plural,
+ msgid_plural_len);
+ result = u32_set_msgid_plural(state, entry, umsgid_plural,
+ msgid_plural_len, append);
+ free(umsgid_plural);
+ return result;
+
+set_msgid_plural_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+}
+
+int
+set_msgstr(struct DrawState* state, struct PoEntry* entry, const char* msgstr,
+ int msgstr_index, int append)
+{
+ uint32_t* umsgstr = NULL;
+ size_t msgstr_len = 0;
+ int result = 0;
+
+ assert(entry != NULL);
+ if (msgstr)
+ msgstr_len = strlen(msgstr);
+ umsgstr = calloc(msgstr_len + 1, sizeof(uint32_t));
+ if (!umsgstr)
+ goto set_msgstr_alloc_error;
+ if (msgstr)
+ (void)u8_string_to_unicode(umsgstr, msgstr, msgstr_len);
+ result = u32_set_msgstr(state, entry, umsgstr, msgstr_index, append);
+ free(umsgstr);
+ return result;
+
+set_msgstr_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+}
+
+int
+set_nplurals(struct DrawState* state, struct PoEntry* entry)
+{
+ char token[LINE_DEFAULT];
+ static uint32_t* unplurals = NULL;
+ uint32_t* ppf;
+ uint32_t* temp;
+ char* ptoken = token;
+ int read_number = 0;
+ int nplurals_len = 0;
+
+ assert(state != NULL);
+ if (!entry || !entry->plural_forms)
+ return 1;
+
+ nplurals_len = strlen("nplurals=");
+ ppf = entry->plural_forms;
+ *ptoken = 0;
+ while (*ppf)
+ {
+ if (!unplurals)
+ {
+ unplurals = calloc(nplurals_len + 1, sizeof(uint32_t));
+ if (!unplurals)
+ goto set_nplurals_alloc_error;
+ U32_U8_MEMCCPY(unplurals, "nplurals=", nplurals_len,
+ temp);
+ }
+ if (u32_starts_with(ppf, unplurals))
+ {
+ ppf += nplurals_len;
+ read_number = 1;
+ }
+ else if (read_number && *ppf >= ZERO && *ppf <= NINE)
+ {
+ *ptoken++ = *ppf++;
+ *ptoken = 0;
+ }
+ else if (read_number && *ppf == SEMICOL)
+ {
+ *ptoken = 0;
+ ptoken = token;
+ break;
+ }
+ else
+ ppf++;
+ }
+ if (*ptoken)
+ {
+ if (sscanf(ptoken, "%d", &state->nplurals) < 1)
+ {
+ state->error = ERR_BAD_NPLURALS;
+ return 1;
+ }
+ }
+ else
+ {
+ state->error = ERR_BAD_NPLURALS;
+ return 1;
+ }
+
+ return 0;
+
+set_nplurals_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+}
+
+int
+set_plural_forms(struct DrawState* state, struct PoEntry* entry,
+ const char* plural_forms, int append)
+{
+ uint32_t* uplural_forms = NULL;
+ size_t plural_forms_len = 0;
+ int result = 0;
+
+ assert(entry != NULL);
+ if (plural_forms)
+ plural_forms_len = strlen(plural_forms);
+ uplural_forms = calloc(plural_forms_len + 1, sizeof(uint32_t));
+ if (!uplural_forms)
+ goto set_plural_forms_alloc_error;
+ if (plural_forms)
+ (void)u8_string_to_unicode(uplural_forms, plural_forms,
+ plural_forms_len);
+ result = u32_set_plural_forms(state, entry, uplural_forms,
+ plural_forms_len, append);
+ free(uplural_forms);
+ return result;
+
+set_plural_forms_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+}
+
+int
+u32_add_comment(struct PoEntry* entry, const uint32_t* comment)
+{
+ uint32_t** comments = NULL;
+ uint32_t* new_line = NULL;
+ size_t len = 0;
+ size_t size;
+
+ assert((entry != NULL) && (comment != NULL));
+ entry->comment_lines++;
+ if (!entry->comments)
+ comments = calloc(entry->comment_lines, sizeof(uint32_t*));
+ else
+ comments = realloc(entry->comments,
+ entry->comment_lines * sizeof(uint32_t*));
+ if (!comments)
+ return 1;
+ entry->comments = comments;
+
+ len = u32_strlen(comment);
+ size = len + 1;
+ new_line = calloc(size, sizeof(uint32_t));
+ if (!new_line)
+ return 1;
+ entry->comments[entry->comment_lines - 1] = new_line;
+ u32_strncpy(new_line, comment, size);
+ return 0;
+}
+
+int
+u32_add_extr_comment(struct PoEntry* entry, const uint32_t* extr_comment)
+{
+ uint32_t** extr_comments = NULL;
+ uint32_t* new_line = NULL;
+ size_t len = 0;
+ size_t size;
+
+ assert((entry != NULL) && (extr_comment != NULL));
+ entry->extr_comment_lines++;
+ if (!entry->extr_comments)
+ extr_comments
+ = calloc(entry->extr_comment_lines, sizeof(uint32_t*));
+ else
+ extr_comments = realloc(entry->extr_comments,
+ entry->extr_comment_lines * sizeof(uint32_t*));
+ if (!extr_comments)
+ return 1;
+ entry->extr_comments = extr_comments;
+
+ len = u32_strlen(extr_comment);
+ size = len + 1;
+ new_line = calloc(size, sizeof(uint32_t));
+ if (!new_line)
+ return 1;
+ entry->extr_comments[entry->extr_comment_lines - 1] = new_line;
+ u32_strncpy(new_line, extr_comment, size);
+ return 0;
+}
+
+int
+u32_set_msgid(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgid, ssize_t msgid_len, int append)
+{
+ 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;
+ 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 (append)
+ U32_MEMCCPY(entry->msgid + entry->msgid_len - msgid_len, msgid,
+ entry->msgid_size - msgid_len, temp);
+ else
+ U32_MEMCCPY(entry->msgid, msgid, entry->msgid_size, temp);
+ return 0;
+
+u32_set_msgid_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
+}
- if (*pstate & PS_MSGID)
+int
+u32_set_msgid_plural(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgid_plural, ssize_t msgid_plural_len, int append)
+{
+ uint32_t* temp = NULL;
+
+ assert((state != NULL) && (entry != NULL));
+ if (msgid_plural)
+ msgid_plural_len = u32_strlen(msgid_plural);
+ if (!entry->msgid_plural)
{
- if (set_msgid(dstate, *current_entry, token, 1))
- goto parse_po_line_alloc_error;
+ entry->msgid_plural_size = MSGDELTA;
+ 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 (*pstate & PS_MSGID_PLURAL)
+ else if (entry->msgid_plural_size + msgid_plural_len
+ >= entry->msgid_plural_size)
{
- 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;
+ entry->msgid_plural_size += MSGDELTA;
+ 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;
}
- else if (*pstate & PS_MSGSTR)
+ entry->msgid_plural_len += msgid_plural_len;
+ if (append)
+ U32_MEMCCPY(entry->msgid_plural + entry->msgid_plural_len
+ - msgid_plural_len,
+ msgid_plural,
+ entry->msgid_plural_size - msgid_plural_len, temp);
+ else
+ 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;
+}
+
+int
+u32_set_msgstr(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgstr, int msgstr_index, int append)
+{
+ uint32_t** newmsgstr = NULL;
+ uint32_t* temp = NULL;
+ ssize_t* newmsgstr_len = NULL;
+ ssize_t* newmsgstr_size = NULL;
+ ssize_t msgstr_len = 0;
+
+ assert((state != NULL) && (entry != NULL));
+ if (msgstr)
+ msgstr_len = u32_strlen(msgstr);
+ if (entry->msgstr_count == 0 || msgstr_index + 1 > entry->msgstr_count)
{
- /* first entry */
- if (*current_entry == dstate->entries)
+ newmsgstr = NULL;
+ newmsgstr_size = NULL;
+ newmsgstr_len = NULL;
+ entry->msgstr_count = msgstr_index + 1;
+ if (!entry->msgstr)
{
- if (starts_with(token, "Plural-Forms: "))
- {
- if (set_plural_forms(dstate, *current_entry,
- token + strlen("Plural-Forms: "), 0))
- goto parse_po_line_alloc_error;
- set_nplurals(dstate, *current_entry);
- }
+ newmsgstr = calloc(entry->msgstr_count,
+ sizeof(uint32_t*));
+ if (!newmsgstr)
+ goto u32_set_msgstr_alloc_error;
+ newmsgstr_size
+ = calloc(entry->msgstr_count, sizeof(ssize_t));
+ if (!newmsgstr_size)
+ goto u32_set_msgstr_alloc_error;
+ newmsgstr_len
+ = calloc(entry->msgstr_count, sizeof(ssize_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)
+ state->untranslated_count--;
}
-
- 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
+ {
+ 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(ssize_t));
+ if (!newmsgstr_size)
+ goto u32_set_msgstr_alloc_error;
+ newmsgstr_len = realloc(entry->msgstr_len,
+ entry->msgstr_count * sizeof(ssize_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;
}
- else if (*pstate & PS_COMMENT_TRAN)
+ if (!entry->msgstr[msgstr_index])
{
- 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);
+ entry->msgstr_size[msgstr_index] = MSGDELTA;
+ 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 (*pstate & PS_COMMENT_EXTR)
+ else if (entry->msgstr_len[msgstr_index] + msgstr_len
+ >= entry->msgstr_size[msgstr_index])
{
- 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);
+ entry->msgstr_size[msgstr_index] += MSGDELTA;
+ entry->msgstr[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;
}
- else if (*pstate & PS_COMMENT_FLAG)
+ entry->msgstr_len[msgstr_index] += msgstr_len;
+ if (append)
+ U32_MEMCCPY(entry->msgstr[msgstr_index]
+ + entry->msgstr_len[msgstr_index] - msgstr_len,
+ msgstr, entry->msgstr_size[msgstr_index] - msgstr_len,
+ temp);
+ else
+ 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;
+}
+
+int
+u32_set_plural_forms(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* plural_forms, const ssize_t plural_forms_len,
+ int append)
+{
+ uint32_t* temp = NULL;
+
+ assert((state != NULL) && (entry != NULL));
+ if (plural_forms_len >= MSGDELTA)
+ return 1;
+ if (!entry->plural_forms)
{
- ptoken = token;
- while (*ptoken)
- {
- 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++;
- }
- }
+ entry->plural_forms_size = MSGDELTA;
+ entry->plural_forms_len = 0;
+ entry->plural_forms = calloc(MAXMSGLINE, sizeof(uint32_t));
+ if (!entry->plural_forms)
+ goto u32_set_plural_forms_alloc_error;
}
- else if (*pstate & PS_COMMENT_REFN)
- add_ref_comment(*current_entry, token);
- else if (*pstate & PS_COMMENT_OBSO)
+ else if (entry->plural_forms_size + plural_forms_len
+ >= entry->plural_forms_size)
{
- 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);
+ 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;
}
- *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;
- return !!dstate->error;
+ entry->plural_forms_len += plural_forms_len;
+ if (append)
+ U32_MEMCCPY(entry->plural_forms + entry->plural_forms_size
+ - plural_forms_len,
+ plural_forms,
+ entry->plural_forms_size - plural_forms_len, temp);
+ else
+ U32_MEMCCPY(entry->plural_forms, plural_forms,
+ entry->plural_forms_size, temp);
+ return 0;
-parse_po_line_alloc_error:
- dstate->error = ERR_CANT_ALLOC;
+u32_set_plural_forms_alloc_error:
+ state->error = ERR_CANT_ALLOC;
return 1;
}
@@ -1619,11 +1723,11 @@ update_warning(const uint32_t* msgid, const uint32_t* msgstr, int* warning)
{
if (!msgid || !msgstr || !warning)
return;
- if (u32_count_strings(msgid, (const uint32_t*)L"\\n")
- != u32_count_strings(msgstr, (const uint32_t*)L"\\n")
+ if (u32_count_strings(msgid, bslash_en)
+ != u32_count_strings(msgstr, bslash_en)
|| (warn_count_dots
- && u32_count_chars(msgid, '.')
- != u32_count_chars(msgstr, '.')))
+ && u32_count_chars(msgid, DOT)
+ != u32_count_chars(msgstr, DOT)))
*warning = 1;
else
*warning = 0;
diff --git a/po.h b/po.h
@@ -5,24 +5,11 @@
#include <stdint.h>
#include <stdlib.h>
-#define MSGSTR_MAX 4096
-// #define ALLOC_DELTA 10
/* lines to tolerate the lack of msgid */
#define PO_DETECTION_LINES 24
struct DrawState;
-enum {
- SAVE_ERR_NONE = 0,
- SAVE_ERR_CANT_ALLOC = 1,
- SAVE_ERR_CANT_OPEN_FILE = 2,
- SAVE_ERR_CANT_MOVE_FILE = 3,
- SAVE_ERR_CANT_STAT_FILE = 4,
- SAVE_ERR_CANT_READLINK = 5,
- SAVE_ERR_CANT_SYMLINK = 6,
- SAVE_ERR_CANT_UNLINK = 7
-};
-
typedef enum {
PS_NONE = 0,
PS_COMMENT_TRAN = 1, /* "translator-comments" : # */
@@ -62,70 +49,70 @@ struct PoEntry {
int obsolete;
int warning;
uint32_t* msgid;
- size_t msgid_size;
- size_t msgid_len;
+ ssize_t msgid_size;
+ ssize_t msgid_len;
uint32_t* msgid_plural;
size_t msgid_plural_size;
size_t msgid_plural_len;
uint32_t* plural_forms;
- size_t plural_forms_size;
- size_t plural_forms_len;
+ ssize_t plural_forms_size;
+ ssize_t plural_forms_len;
uint32_t** msgstr;
int msgstr_count;
- size_t* msgstr_size;
- size_t* msgstr_len;
+ ssize_t* msgstr_size;
+ ssize_t* msgstr_len;
uint32_t** comments;
- size_t comment_lines;
+ ssize_t comment_lines;
uint32_t** extr_comments;
- size_t extr_comment_lines;
+ ssize_t extr_comment_lines;
char** ref_comments;
- size_t ref_comment_lines;
+ ssize_t ref_comment_lines;
};
+int add_ref_comment(struct PoEntry* entry, const char* comment);
char* format_flags(char* buffer, const size_t max, const struct PoEntry* entry,
const int draw_box);
-void init_po_entry(struct PoEntry* entry);
void free_po_entry(struct PoEntry* entry);
-struct PoEntry* set_flags(struct PoEntry* entry, const Flags flags);
-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);
-int set_plural_forms(struct DrawState* state, struct PoEntry* entry,
- const char* plural_forms, int append);
-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);
-struct PoEntry* add_ref_comment(struct PoEntry* entry, const char* comment);
+void init_po_entry(struct PoEntry* entry);
int load_file(struct DrawState* state, long* lineno, long* col);
+int parse_po_line(const char* line, struct DrawState* dstate,
+ struct PoEntry** current_entry, ParseState* pstate, long* col,
+ int* msgstr_index);
int save_comment(FILE* output, struct DrawState* state,
const struct PoEntry* current);
-int save_file(struct DrawState* state);
-int save_flags(FILE* output, struct DrawState* state,
+int save_extr_comment(FILE* output, struct DrawState* state,
const struct PoEntry* current);
+int save_file(struct DrawState* state);
+int save_flags(FILE* output, const struct PoEntry* current);
int save_msgid(FILE* output, struct DrawState* state,
const struct PoEntry* current);
int save_msgid_plural(FILE* output, struct DrawState* state,
const struct PoEntry* current);
int save_msgstrs(FILE* output, struct DrawState* state,
const struct PoEntry* current);
-int save_ref_comment(FILE* output, struct DrawState* state,
- const struct PoEntry* current);
-int save_extr_comment(FILE* output, struct DrawState* state,
- const struct PoEntry* current);
-int parse_po_line(const char* line, struct DrawState* dstate,
- struct PoEntry** current_entry, ParseState* pstate, long* col,
- int* msgstr_index);
+int save_ref_comment(FILE* output, const struct PoEntry* current);
+int set_flags(struct PoEntry* entry, const Flags flags);
+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);
+int set_msgstr(struct DrawState* state, struct PoEntry* entry,
+ const char* msgstr, int msgstr_index, int append);
+int set_nplurals(struct DrawState* state, struct PoEntry* entry);
+int set_plural_forms(struct DrawState* state, struct PoEntry* entry,
+ const char* plural_forms, int append);
+int u32_add_comment(struct PoEntry* entry, const uint32_t* comment);
+int u32_add_extr_comment(struct PoEntry* entry,
+ const uint32_t* extr_comment);
+int u32_set_msgid(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgid, ssize_t msgid_size, int append);
+int u32_set_msgid_plural(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgid_plural, ssize_t msgid_plural_size, int append);
+int u32_set_msgstr(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* msgstr, int msgstr_index, int append);
+int u32_set_plural_forms(struct DrawState* state, struct PoEntry* entry,
+ const uint32_t* plural_forms, const ssize_t plural_forms_len,
+ int append);
void update_statistics(const struct PoEntry* entries, struct DrawState* state,
struct PoEntry* entry);
void update_warning(const uint32_t* msgid, const uint32_t* msgstr, int* warning);
diff --git a/poe.1.in b/poe.1.in
@@ -33,13 +33,15 @@ This option overrides the setting in
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
+By default (unless changed in
+.Pa config.h Ns ),
+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
+the closing quote) is greater than
.Va literal_break_threshold ,
a line of the form
.Bd -literal -offset indent
@@ -203,20 +205,22 @@ Bugs can be reported using the ticket tracker at:
.It
UTF-8 character set is assumed.
.It
-CJK characters are unsupported/problematic.
-This is a limitation of termbox library.
-See
-.Lk https://\:github.com/\:nsf/\:termbox
-for more details.
+RTL scripts are unsupported/problematic.
+CJK scripts should work better after v2.0, which introduced the use of
+.Xr wcwidth 3 .
.It
Only one file can be edited at a time, and no additional files can be loaded at
runtime.
This is a design decision.
.It
-Unless the define
-.Dv CREATE_BACKUPS
-is commented out before compilation, the directory of the edited file must be
-writable by the user in order to write the changes to the file.
+Unless the variable
+.Va create_backups
+is set to 0 before compilation, or the parameter
+.Fl B
+is used when invoking
+.Nm ,
+the directory of the edited file must be writable by the user in order to write
+the changes to the file.
This is due to creating backups in order to avoid the potential data loss under
specific circumstances (loss of power during write).
.It
diff --git a/poe.c b/poe.c
@@ -26,9 +26,6 @@
" 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"
@@ -39,6 +36,8 @@
#include "util.h"
#include "version.h"
+#define MAXCOPYBUF 8192
+
extern const char* errors[];
extern const char* actions[];
extern const char* prompt_dirty;
@@ -104,7 +103,7 @@ cancel_msgstr(struct DrawState* state)
state->input_rows_count = 0;
if (state->info_buffer)
for (i = 0; i < state->info_rows_count; i++)
- free_bufferline(state->info_buffer + i);
+ free_bufferline(&state->info_buffer[i]);
free(state->info_buffer);
state->info_buffer = NULL;
state->info_rows_count = 0;
@@ -145,8 +144,7 @@ copy_msgid_to_input(struct DrawState* state)
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;
+ ssize_t msgid_num_lines, lines_to_init, lines_to_free, i, len, newlen;
assert(state != NULL);
@@ -207,7 +205,7 @@ copy_msgid_to_input(struct DrawState* state)
len = u32_next_line(current->msgid, &pmsgid, 0, 0);
u32_strncpy(pbuffer->text, old_pmsgid,
MIN(len + 1, LINE_DEFAULT));
- newlen = u32_decode_tabs(pbuffer->text, LINE_DEFAULT);
+ newlen = u32_decode_tabs(state, pbuffer->text, LINE_DEFAULT);
pbuffer->length = newlen;
pbuffer++;
}
@@ -219,8 +217,6 @@ copy_msgid_to_input(struct DrawState* state)
return 0;
}
-#define MAXCOPYBUF 8192
-
int
cp(const char* from, const char* to)
{
@@ -362,7 +358,6 @@ edit_page_up(struct DrawState* state)
static int
erase_backwards(struct DrawState* state)
{
- const struct BufferLine* current_line;
struct BufferLine* buffer_line;
assert((state != NULL) && (state->input_buffer != NULL));
@@ -384,23 +379,7 @@ erase_backwards(struct DrawState* state)
}
buffer_line->text[i - 1] = 0;
buffer_line->length--;
- /* TODO: position_to */
- state->coord.col--;
- if (state->input_first_shown.col > 0)
- {
- current_line = &state->input_buffer[state->coord.row];
- if (display_length(current_line->text,
- current_line->length)
- >= state->edit_width - 4)
- state->input_first_shown.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->input_first_shown.col
- = state->input_display_column;
+ position_to(state, state->coord.row, state->coord.col - 1);
state->dirty = 1;
}
else if (state->coord.row > 0)
@@ -850,7 +829,6 @@ insert_char(struct DrawState* state, uint32_t ch)
len = buffer_line->length;
size = buffer_line->size;
- // TODO: realloc
if (len + 1 > size)
{
size += LINE_ALLOC_DELTA;
@@ -871,20 +849,7 @@ insert_char(struct DrawState* state, uint32_t ch)
}
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);
- }
+ position_to(state, state->coord.row, state->coord.col + 1);
if (add_null)
buffer_line->text[state->coord.col] = 0;
state->dirty = 1;
@@ -1100,7 +1065,7 @@ load_info(struct DrawState* state)
{
num_lines += msgid_plural_num_lines + 1;
if (first->plural_forms)
- num_lines += 3;
+ num_lines += 2; /* title + plural_forms */
}
if (current->comments)
num_lines += current->comment_lines + 1;
@@ -1120,6 +1085,8 @@ load_info(struct DrawState* state)
if (!newtext)
goto load_info_alloc_error;
pnewbuf->text = newtext;
+ pnewbuf->size = LINE_DEFAULT;
+ pnewbuf->size = 0;
pnewbuf++;
}
@@ -1161,12 +1128,13 @@ 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;
+ ssize_t len, llen, size, 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;
+ (*lines)->length = llen
+ = ptext ? ptext - (*lines)->text : LINE_DEFAULT - 1;
+ (*lines)->size = LINE_DEFAULT;
if (llen > state->info_maxlen)
state->info_maxlen = llen;
(*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
@@ -1176,15 +1144,21 @@ load_info_comments(struct DrawState* state, struct BufferLine** lines)
{
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;
+ size = MAX(len + 2, LINE_DEFAULT); /* + NUL */
+ ENSURE_SIZE((*lines)->text, ptext, (*lines)->size, size, size,
+ load_info_comments_alloc_error, uint32_t);
+ U32_MEMCCPY((*lines)->text, comment, len + 1, ptext);
+ llen = ptext ? ptext - (*lines)->text : (*lines)->size - 1;
+ (*lines)->length = llen;
if (llen > state->info_maxlen)
state->info_maxlen = llen;
(*lines)++;
}
return 0;
+
+load_info_comments_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
static int
@@ -1193,13 +1167,13 @@ 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;
+ ssize_t len, llen, size, 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;
+ (*lines)->size = MAX(llen + 1, LINE_DEFAULT);
if (llen > state->info_maxlen)
state->info_maxlen = llen;
(*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
@@ -1209,15 +1183,21 @@ load_info_extr_comments(struct DrawState* state, struct BufferLine** lines)
{
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;
+ size = MAX(len + 2, LINE_DEFAULT); /* + NUL */
+ ENSURE_SIZE((*lines)->text, ptext, (*lines)->size, size, size,
+ load_info_extr_comments_alloc_error, uint32_t);
+ U32_MEMCCPY((*lines)->text, extr_comment, len + 1, ptext);
+ len = ptext ? ptext - (*lines)->text : (*lines)->size - 1;
+ (*lines)->length = llen;
if (llen > state->info_maxlen)
state->info_maxlen = llen;
(*lines)++;
}
return 0;
+
+load_info_extr_comments_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
static int
@@ -1227,7 +1207,7 @@ load_info_msgid(struct DrawState* state, struct BufferLine** lines)
const uint32_t* pumsgid = NULL;
const uint32_t* old_pumsgid = NULL;
uint32_t* ptext = NULL;
- ssize_t len, llen;
+ ssize_t len, llen, size;
current = &state->entries[state->msgid_number - 1];
ptext = u32_u8_memccpy((*lines)->text, "msgid:", 0, LINE_DEFAULT);
@@ -1242,15 +1222,21 @@ load_info_msgid(struct DrawState* state, struct BufferLine** lines)
{
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);
+ size = MAX(len + 2, LINE_DEFAULT); /* + NUL */
+ ENSURE_SIZE((*lines)->text, ptext, (*lines)->size, size, size,
+ load_info_msgid_alloc_error, uint32_t);
+ U32_MEMCCPY((*lines)->text, old_pumsgid, len + 1, ptext);
+ llen = u32_decode_tabs(state, (*lines)->text, len + 1);
(*lines)->length = llen;
if (llen > state->info_maxlen)
state->info_maxlen = llen;
(*lines)++;
}
return 0;
+
+load_info_msgid_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
static int
@@ -1258,10 +1244,10 @@ 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;
+ const uint32_t* pumsgid = NULL;
uint32_t* ptext = NULL;
- ssize_t len, llen;
+ ssize_t len, llen, size;
first = &state->entries[0];
current = &state->entries[state->msgid_number - 1];
@@ -1276,10 +1262,12 @@ load_info_msgid_plural(struct DrawState* state, struct BufferLine** lines)
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);
+ len = u32_next_line(current->msgid_plural, &pumsgid, 0, 0);
+ size = MAX(len + 2, LINE_DEFAULT);
+ ENSURE_SIZE((*lines)->text, ptext, (*lines)->size, size, size,
+ load_info_msgid_plural_alloc_error, uint32_t);
+ U32_MEMCCPY((*lines)->text, old_pumsgid, len + 1, ptext);
+ llen = u32_decode_tabs(state, (*lines)->text, size);
(*lines)->length = llen;
if (llen > state->info_maxlen)
state->info_maxlen = llen;
@@ -1290,35 +1278,42 @@ load_info_msgid_plural(struct DrawState* state, struct BufferLine** lines)
ptext = u32_u8_memccpy((*lines)->text, "Plural forms:", 0,
LINE_DEFAULT);
(*lines)->length = llen
- = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ = ptext ? ptext - (*lines)->text : LINE_DEFAULT - 1;
+ (*lines)->size = 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);
+ U32_SAFE_COPY((*lines)->text, ptext, (*lines)->size,
+ first->plural_forms, first->plural_forms_size,
+ load_info_msgid_plural_alloc_error);
(*lines)->length = llen
- = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ = ptext ? ptext - (*lines)->text : (*lines)->size - 1;
+ //(*lines)->size = MAX(llen + 1, LINE_DEFAULT);
if (llen > state->info_maxlen)
state->info_maxlen = llen;
(*lines)++;
}
return 0;
+
+load_info_msgid_plural_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
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;
+ char* ref_comment = NULL;
+ ssize_t len, llen, size, i;
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;
+ (*lines)->size = MAX(llen + 1, LINE_DEFAULT);
if (llen > state->info_maxlen)
state->info_maxlen = llen;
(*lines)->fg = colors[C_EDIT_MSGID_HEADING].fg;
@@ -1328,15 +1323,21 @@ load_info_ref_comments(struct DrawState* state, struct BufferLine** lines)
{
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;
+ size = MAX(len + 2, LINE_DEFAULT); /* + NUL */
+ ENSURE_SIZE((*lines)->text, ptext, (*lines)->size, size, size,
+ load_info_ref_comments_alloc_error, uint32_t);
+ U32_U8_MEMCCPY((*lines)->text, ref_comment, len + 1, ptext);
+ llen = ptext ? ptext - (*lines)->text : LINE_DEFAULT;
+ (*lines)->length = llen;
if (llen > state->info_maxlen)
state->info_maxlen = llen;
(*lines)++;
}
return 0;
+
+load_info_ref_comments_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
static int
@@ -1345,12 +1346,11 @@ load_msgstr(struct DrawState* state)
struct PoEntry* current;
struct BufferLine* newbuf;
struct BufferLine* pnewbuf;
- const uint32_t* pumsgstr = NULL;
const uint32_t* old_pumsgstr = NULL;
+ const uint32_t* pumsgstr = NULL;
uint32_t* newtext = NULL;
uint32_t* temp = NULL;
- size_t num_lines, i, len, newlen;
- ssize_t row;
+ ssize_t num_lines, i, len, newlen, size, row;
int msgstr_index;
assert((state != NULL) && (state->entries != NULL));
@@ -1360,10 +1360,10 @@ load_msgstr(struct DrawState* state)
msgstr_index = state->msgstr_index;
num_lines = current->msgstr_count == 0
? 1
- : u32_lines_in_string(*(current->msgstr + msgstr_index), 0, 0);
+ : u32_lines_in_string(current->msgstr[msgstr_index], 0, 0);
for (row = 0; row < state->input_rows_count; row++)
- free_bufferline(state->input_buffer + row);
+ free_bufferline(&state->input_buffer[row]);
free(state->input_buffer);
newbuf = calloc(num_lines, sizeof(struct BufferLine));
@@ -1374,43 +1374,44 @@ load_msgstr(struct DrawState* state)
for (i = 0; i < num_lines; i++)
{
init_bufferline(pnewbuf);
- newtext = calloc(LINE_DEFAULT, sizeof(uint32_t));
+ size = MAX(current->msgstr_size[msgstr_index], LINE_DEFAULT);
+ newtext = calloc(size, sizeof(uint32_t));
if (!newtext)
goto load_msgstr_alloc_error;
pnewbuf->text = newtext;
- pnewbuf->size = LINE_DEFAULT;
+ pnewbuf->size = size;
pnewbuf->length = 0;
pnewbuf++;
}
-
state->input_rows_count = num_lines;
if (current->msgstr_count > 0)
{
- pumsgstr = *(current->msgstr + msgstr_index);
- if (pumsgstr)
+ pumsgstr = current->msgstr[msgstr_index];
+ if (!pumsgstr)
{
- pnewbuf = newbuf;
- while (*pumsgstr)
- {
- old_pumsgstr = pumsgstr;
- len = u32_next_line(current->msgstr[msgstr_index],
- &pumsgstr, 0, 0);
- U32_MEMCCPY(pnewbuf->text, old_pumsgstr,
- MIN(len + 1, LINE_DEFAULT), temp);
- newlen = u32_decode_tabs(pnewbuf->text,
- LINE_DEFAULT); /* TODO: Check */
- pnewbuf->length = newlen;
- pnewbuf->size = LINE_DEFAULT;
- pnewbuf++;
- }
- }
- else
newbuf[0].length = 0;
+ goto load_msgstr_done;
+ }
+ pnewbuf = newbuf;
+ while (*pumsgstr)
+ {
+ old_pumsgstr = pumsgstr;
+ len = u32_next_line(current->msgstr[msgstr_index],
+ &pumsgstr, 0, 0);
+ size = MAX(len + 2, LINE_DEFAULT); /* + NUL */
+ ENSURE_SIZE(pnewbuf->text, temp, pnewbuf->size, size,
+ size, load_msgstr_alloc_error, uint32_t);
+ U32_MEMCCPY(pnewbuf->text, old_pumsgstr, len + 1, temp);
+ newlen = u32_decode_tabs(state, pnewbuf->text, len + 1);
+ pnewbuf->length = newlen;
+ pnewbuf++;
+ }
}
else
newbuf[0].length = 0;
+load_msgstr_done:
state->input_buffer = newbuf;
return 0;
@@ -1577,6 +1578,13 @@ static int
move_right(struct DrawState* state)
{
assert(state != NULL);
+ if (state->edit_info_focused)
+ {
+ if (state->info_first_shown.col + state->edit_width - 3
+ < state->info_maxlen + 1)
+ state->info_first_shown.col++;
+ return 0;
+ }
position_to(state, state->coord.row, state->coord.col + 1);
return 0;
}
@@ -2095,13 +2103,29 @@ prev_msgid(struct DrawState* state, const int delta)
return ret;
}
+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--;
+ show_edit(state);
+ return 0;
+}
+
int
print_error(const int code, const char* msg, ...)
{
char* buf = NULL;
va_list args;
long bufsize;
- assert(msg != NULL);
+ assert((msg != NULL) && (limits != NULL));
bufsize = limits[L_LINE_MAX] ? limits[L_LINE_MAX]
: PRINT_BUF_MAX_FALLBACK;
buf = malloc(bufsize);
@@ -2119,41 +2143,28 @@ print_error(const int code, const char* msg, ...)
static int
quit_callback(struct DrawState* state, struct tb_event* ev)
{
+ int result = 0;
assert((state != NULL) && (ev != NULL));
if (ev->ch == 'y')
- write_file(state);
+ result = write_file(state);
state->prompt_callback = NULL;
state->running = 0;
- return 0;
+ return result;
}
-void
+int
redraw_status(struct DrawState* state)
{
+ int result = 0;
assert(state != NULL);
if (state->recalculate_size)
{
recalculate_size(state);
state->recalculate_size = 0;
}
- (void)draw_status(state);
+ result = draw_status(state);
tb_present();
-}
-
-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--;
- show_edit(state);
- return 0;
+ return result;
}
static int
@@ -2196,10 +2207,6 @@ save_msgstr(struct DrawState* state)
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));*/
}
free_bufferline(pinput_buffer);
}
@@ -2207,24 +2214,35 @@ save_msgstr(struct DrawState* state)
free(state->input_buffer);
state->input_buffer = NULL;
state->input_rows_count = 0;
+ assert(state->info_buffer != NULL);
for (i = 0; i < state->info_rows_count; i++)
- free_bufferline(state->info_buffer + i);
+ free_bufferline(&state->info_buffer[i]);
free(state->info_buffer);
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));
+ if (u32_encode_tabs(state, to_save, to_save_size * sizeof(uint32_t)) <
+ 0)
+ goto save_msgstr_error;
current = &state->entries[state->msgid_number - 1];
- u32_match_msgid_ending(current->msgid, to_save,
- to_save_size * sizeof(uint32_t));
+ if (u32_match_msgid_ending(state, current->msgid, to_save,
+ to_save_size * sizeof(uint32_t)) < 0)
+ goto save_msgstr_error;
u32_set_msgstr(state, current, to_save, state->msgstr_index, 0);
update_warning(current->msgid, to_save, ¤t->warning);
state->input_changed_fuzzy = UNCHANGED;
+save_msgstr_error:
+ if (state->error == ERR_CANT_ALLOC)
+ goto save_msgstr_alloc_error;
+
tb_hide_cursor();
free(to_save);
- return 0;
+ return !!state->error;
+
+save_msgstr_alloc_error:
+ return 1;
}
static int
@@ -2252,6 +2270,7 @@ search_position_to(struct DrawState* state, const int column)
static int
show_edit(struct DrawState* state)
{
+ assert((state != NULL) && (state->entries != NULL));
if (state->msgstr_index + 1
> state->entries[state->msgid_number - 1].msgstr_count)
state->msgstr_index = 0;
@@ -2278,6 +2297,7 @@ show_edit(struct DrawState* state)
static int
show_help(struct DrawState* state)
{
+ assert(state != NULL);
state->show_help = 1;
state->error = ERR_NONE;
return 0;
@@ -2286,6 +2306,7 @@ show_help(struct DrawState* state)
static int
show_search(struct DrawState* state)
{
+ assert(state != NULL);
state->show_search = 1;
state->search_column = 0;
state->search_display_column = 0;
@@ -2301,6 +2322,7 @@ show_search(struct DrawState* state)
static int
toggle_fuzzy(struct DrawState* state)
{
+ assert((state != NULL) && (state->entries != NULL));
if (state->msgid_number == 1)
{
state->error = ERR_ILLEGAL_ON_FIRST;
@@ -2333,6 +2355,7 @@ toggle_fuzzy(struct DrawState* state)
static int
toggle_info_focused(struct DrawState* state)
{
+ assert(state != NULL);
state->edit_info_focused = !state->edit_info_focused;
return 0;
}
@@ -2343,9 +2366,13 @@ yank_input_to_paste_buffer(struct DrawState* state)
struct BufferLine* ppaste = NULL;
struct BufferLine* newbuf = NULL;
struct BufferLine* pinput = NULL;
+ uint32_t* newtext = NULL;
+ uint32_t* 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)
return 1;
@@ -2358,7 +2385,7 @@ yank_input_to_paste_buffer(struct DrawState* state)
if (!state->input_buffer || !(*state->input_buffer).text
|| !*(*state->input_buffer).text)
{
- for (ssize_t i = 0; i < state->paste_count; i++)
+ for (i = 0; i < state->paste_count; i++)
free_bufferline(state->paste + i);
free(state->paste);
state->paste = NULL;
@@ -2373,7 +2400,7 @@ yank_input_to_paste_buffer(struct DrawState* state)
? state->paste_count - state->input_rows_count
: 0;
- for (ssize_t i = 0; i < lines_to_free; i++)
+ for (i = 0; i < lines_to_free; i++)
free_bufferline(state->paste + state->paste_count - i - 1);
if (!state->paste)
newbuf = calloc(state->input_rows_count,
@@ -2381,68 +2408,52 @@ yank_input_to_paste_buffer(struct DrawState* state)
else
newbuf = realloc(state->paste,
state->input_rows_count * sizeof(struct BufferLine));
- pinput = state->input_buffer;
-
if (!newbuf)
- return 0;
+ goto yank_input_alloc_error;
- for (ssize_t i = 0; i < lines_to_init; i++)
+ pinput = state->input_buffer;
+ for (i = 0; i < lines_to_init; i++)
{
- uint32_t* newtext;
ppaste = newbuf + state->input_rows_count - 1 - i;
init_bufferline(ppaste);
newtext = calloc(LINE_DEFAULT, sizeof(uint32_t));
if (!newtext)
- return 0;
+ goto yank_input_alloc_error;
ppaste->text = newtext;
+ ppaste->size = LINE_DEFAULT;
}
if (pinput)
- for (ssize_t i = 0; i < state->input_rows_count; i++)
+ for (i = 0; i < state->input_rows_count; i++)
{
- ppaste = newbuf + i;
- u32_strncpy(ppaste->text, pinput->text,
- MIN(pinput->length + 1, LINE_DEFAULT));
+ ppaste = &newbuf[i];
+ U32_SAFE_COPY(ppaste->text, temp, ppaste->size,
+ pinput->text, pinput->size,
+ yank_input_alloc_error);
ppaste->length = pinput->length;
pinput++;
}
state->paste_count = state->input_rows_count;
state->paste = newbuf;
-
return 0;
+
+yank_input_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return 1;
}
static int
write_file(struct DrawState* state)
{
+ int result;
assert(state != NULL);
- if (save_file(state))
+ result = save_file(state);
+ if (result)
{
state->running = 0;
- return 1;
+ return result;
}
- /* TODO: Check
- int result = save_file(state->entries, state->real_msgid_count,
- state->filename, state->nplurals);
- switch (result)
- {
- case SAVE_ERR_CANT_ALLOC:
- state->error = ERR_CANT_ALLOC;
- state->running = 0;
- break;
- case SAVE_ERR_CANT_OPEN_FILE:
- state->error = ERR_CANT_SAVE;
- state->running = 0;
- break;
- case SAVE_ERR_CANT_MOVE_FILE:
- state->error = ERR_ERRNO_SET;
- state->running = 0;
- break;
- default:
- state->error = ERR_NONE;
- state->dirty = 0;
- }*/
state->error = ERR_NONE;
state->dirty = 0;
return 0;
@@ -2451,20 +2462,20 @@ write_file(struct DrawState* state)
int
main(int argc, char** argv)
{
- struct tb_event ev;
struct DrawState state;
+ struct tb_event ev;
struct stat st;
char prompt[LINE_DEFAULT];
char* dir = NULL;
char* filename = NULL;
char* pdir = NULL;
- char* temp = NULL;
char* rfn = NULL;
const char* saved_tb_error = NULL;
+ char* temp = NULL;
char* wd = NULL;
ssize_t filename_size = 0;
- long lineno = 1;
long col = 1;
+ long lineno = 1;
int dir_access;
int dir_access_errno;
int optind = 1;
@@ -2482,16 +2493,15 @@ main(int argc, char** argv)
}
#endif
+ /* Necessary in order for termbox to function properly
+ * See: https://github.com/termbox/termbox2/issues/73
+ */
setlocale(LC_ALL, "");
- if (argc == 1)
- return print_error(CUSTOM_ERROR_START + ERR_NO_CL_ARG,
- "No filename given");
-
main_options_loop:
if (optind >= argc)
return print_error(CUSTOM_ERROR_START + ERR_NO_CL_ARG,
- "No filename given");
+ errors[ERR_NO_CL_ARG]);
if (!strcmp(argv[optind], "-h") || !strcmp(argv[optind], "--help"))
{
@@ -2596,7 +2606,7 @@ main_options_loop:
* we need a dir, which needs to be allocated, and to allocate it we
* need to know the value returned by fpathconf(dirfd, _PC_PATH_MAX)...
*/
- /* argv[1] is the filename; BTW, "filename" is a misnomer */
+ /* argv[optind] is the filename; BTW, "filename" is a misnomer */
filename_size = strlen(argv[optind]) + 1;
if (!(dir = malloc(filename_size)))
{
@@ -2625,7 +2635,8 @@ main_options_loop:
{
free(filename);
free(dir);
- return print_error(EINVAL, "No filename given");
+ return print_error(CUSTOM_ERROR_START + ERR_NO_CL_ARG,
+ errors[ERR_NO_CL_ARG]);
}
init_drawstate(&state, filename, prompt);
@@ -2833,8 +2844,6 @@ main_skip_backups:
state.msgid_number = state.msgid_count > 0 ? 1 : 0;
state.first_shown_msgid = state.msgid_number;
- goto init_termbox;
-
init_termbox:
if ((tbires = tb_init()))
{
diff --git a/poe.h b/poe.h
@@ -34,7 +34,8 @@ static int insert_space(struct DrawState* state);
static int insert_tab(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_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);
@@ -80,7 +81,7 @@ static size_t prev_msgid(struct DrawState* state, const int delta);
static int prev_plural(struct DrawState* state);
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);
+int 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);
diff --git a/util.c b/util.c
@@ -8,30 +8,28 @@
#include <stdlib.h>
#include <string.h>
+#include "draw.h"
#include "termbox.h"
#include "po.h"
#include "util.h"
-/* Whitespace definition for determining word boundaries */
-#define B_WS " \v\t-"
-/* Full word boundary delimiter definition */
-#define B_FULL " \v\t-()[]{},.;:/\\"
+/* 32-bit string constants */
+const uint32_t bslash_en[] = {0x0000005c, 0x0000006e, 0};
+const uint32_t space_dot[] = {0x00000020, 0x0000002e, 0};
-enum { UTLERRNONE = 0, UTLERROVFL = 1 };
-
-int utlerrno = UTLERRNONE;
+extern int match_msgstr_ending;
/* max - max Unicode characters to convert from UTF-8
* Returns: number of processed Unicode characters */
size_t
u8_string_to_unicode(uint32_t* us, const char* s, const size_t max)
{
- uint32_t uch;
uint32_t* pus = us;
- int u8_len = 0;
- size_t added = 0;
+ uint32_t uch;
+ size_t added = 0;
+ int u8_len = 0;
- assert(s != NULL);
+ assert((s != NULL) && (us != NULL));
while (*s)
{
u8_len = tb_utf8_char_to_unicode(&uch, s);
@@ -54,16 +52,16 @@ size_t
unicode_string_to_u8(char* s, const uint32_t* us, const size_t max)
{
char ch[8];
- char* ps = NULL;
+ char* ps = NULL;
const uint32_t* pus = us;
+ size_t added = 0;
size_t len;
- size_t added = 0;
assert((s != NULL) && (us != NULL));
ps = s;
while (*pus)
{
- len = tb_utf8_unicode_to_char(ch, *pus);
+ len = tb_utf8_unicode_to_char(ch, *pus);
if (added + 1 > max)
return added;
memccpy(ps, ch, 0, len);
@@ -75,62 +73,70 @@ unicode_string_to_u8(char* s, const uint32_t* us, const size_t max)
return added;
}
-// TODO: Check
-size_t
-u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr, size_t max)
+/*
+ * Returns: -1 on error
+ */
+ssize_t
+u32_match_msgid_ending(struct DrawState* state, const uint32_t* msgid,
+ uint32_t* msgstr, size_t max)
{
- uint32_t* buf = NULL;
- size_t buf_len = 0;
- size_t msgid_len = 0;
+ uint32_t* buf = NULL;
+ ssize_t buf_len = 0;
+ ssize_t msgid_len = 0;
+ assert((state != NULL) && (msgstr != NULL));
buf = calloc(max + 1, sizeof(uint32_t));
- if (!buf || !msgid)
+ if (!buf)
+ goto u32_match_msgid_ending_alloc_error;
+
+ if (!msgid)
return 0;
buf_len = u32_strncpy(buf, msgstr, (max + 1) * sizeof(uint32_t));
msgid_len = u32_strlen(msgid);
- if (msgid_len > 1
- && u32_starts_with(msgid + msgid_len - 2, (uint32_t*)L"\\n"))
+ if (msgid_len > 1 && u32_starts_with(msgid + msgid_len - 2, bslash_en))
{
if (!(buf_len > 1
- && u32_starts_with(buf + buf_len - 2,
- (uint32_t*)L"\\n")))
+ && u32_starts_with(buf + buf_len - 2, bslash_en)))
{
buf_len += 2;
- buf[buf_len - 2] = '\\';
- buf[buf_len - 1] = 'n';
+ buf[buf_len - 2] = BSLASH;
+ buf[buf_len - 1] = EN;
buf[buf_len] = 0;
}
}
-#ifdef MATCH_MSGSTR_ENDING
- else if (msgid_len > 0
- && u32_strstr((uint32_t*)L" .", msgid + msgid_len - 1))
+ else if (match_msgstr_ending && msgid_len > 0
+ && u32_strstr(space_dot, msgid + msgid_len - 1))
{
if (!(buf_len > 0
- && u32_strstr((uint32_t*)L" .", buf + buf_len - 1)))
+ && u32_strstr(space_dot, buf + buf_len - 1)))
{
buf_len++;
buf[buf_len - 1] = msgid[msgid_len - 1];
buf[buf_len] = 0;
}
}
- else if (buf_len > 1
- && u32_starts_with(buf + buf_len - 2, (uint32_t*)L"\\n"))
+ else if (match_msgstr_ending && buf_len > 1
+ && u32_starts_with(buf + buf_len - 2, bslash_en))
{
buf_len -= 2;
buf[buf_len] = 0;
}
- else if (buf_len > 0 && u32_strstr((uint32_t*)L" .", buf + buf_len - 1))
+ else if (match_msgstr_ending && buf_len > 0
+ && u32_strstr(space_dot, buf + buf_len - 1))
{
buf_len--;
buf[buf_len] = 0;
}
-#endif
u32_strncpy(msgstr, buf, max);
return buf_len;
+
+u32_match_msgid_ending_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return -1;
}
uint32_t*
@@ -180,8 +186,8 @@ 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 result = 0;
const uint32_t* ps = s;
+ size_t result = 0;
assert(s != NULL);
while (*ps)
{
@@ -195,9 +201,9 @@ 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 result = 0;
const uint32_t* phaystack = haystack;
size_t needle_len = 0;
+ size_t result = 0;
assert((haystack != NULL) && (needle != NULL));
needle_len = u32_strlen(needle);
@@ -213,18 +219,21 @@ u32_count_strings(const uint32_t* haystack, const uint32_t* needle)
return result;
}
-size_t
-u32_encode_tabs(uint32_t* s, size_t max)
+/*
+ * Returns: -1 on error
+ */
+ssize_t
+u32_encode_tabs(struct DrawState* state, uint32_t* s, size_t max)
{
- uint32_t* buf = NULL;
+ uint32_t* buf = NULL;
uint32_t* pbuf = NULL;
uint32_t* ps = s;
size_t newlen = 0;
- assert(s != NULL);
+ assert((state != NULL) && (s != NULL));
buf = calloc(max + 1, sizeof(uint32_t));
if (!buf)
- return 0;
+ goto u32_encode_tabs_alloc_error;
pbuf = buf;
while (*ps)
{
@@ -245,22 +254,29 @@ u32_encode_tabs(uint32_t* s, size_t max)
u32_strncpy(s, buf, max);
free(buf);
return newlen;
+
+u32_encode_tabs_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return -1;
}
-size_t
-u32_decode_tabs(uint32_t* s, size_t max)
+/*
+ * Returns: -1 on error
+ */
+ssize_t
+u32_decode_tabs(struct DrawState* state, uint32_t* s, size_t max)
{
- uint32_t* buf = NULL;
+ uint32_t* buf = NULL;
uint32_t* pbuf = NULL;
uint32_t* ps = s;
size_t newlen = 0;
- assert(s != NULL);
+ assert((state != NULL) && (s != NULL));
buf = calloc(max + 1, sizeof(uint32_t));
if (!buf)
- return 0;
+ goto u32_decode_tabs_alloc_error;
pbuf = buf;
- while (*ps)
+ while (*ps && (size_t)(ps - s) < max)
{
if (*ps == '\\' && *(ps + 1) == 't')
{
@@ -278,6 +294,10 @@ u32_decode_tabs(uint32_t* s, size_t max)
u32_strncpy(s, buf, max);
free(buf);
return newlen;
+
+u32_decode_tabs_alloc_error:
+ state->error = ERR_CANT_ALLOC;
+ return -1;
}
size_t
@@ -326,6 +346,7 @@ const uint32_t*
u32_strchr(const uint32_t* haystack, const uint32_t needle)
{
const uint32_t* ph = haystack;
+ assert(haystack != NULL);
while (*ph)
{
if (*ph == needle)
@@ -340,6 +361,7 @@ u32_strncpy(uint32_t* to, const uint32_t* from, size_t max)
{
const uint32_t* pfrom = from;
size_t copied = 0;
+ assert((to != NULL) && (from != NULL));
/* pfrom - from < max - 1 ... except we can't reliably subtract with
* size_t */
while (*pfrom && pfrom + 1 < max + from)
@@ -360,6 +382,7 @@ u32_strncat(uint32_t* to, const uint32_t* from, size_t max)
{
const uint32_t* pfrom = from;
size_t copied = 0;
+ assert((to != NULL) && (from != NULL));
while (*to && copied + 1 < max)
{
to++;
@@ -379,6 +402,7 @@ u32_u8_strncpy(uint32_t* to, const char* from, size_t max)
{
uint32_t* ufrom = calloc(max + 1, sizeof(uint32_t));
size_t len;
+ assert(to != NULL);
if (!ufrom)
return 0;
u8_string_to_unicode(ufrom, from, max);
@@ -387,15 +411,18 @@ u32_u8_strncpy(uint32_t* to, const char* from, size_t max)
return len;
}
-// TODO: Check
-size_t
+/*
+ * Returns: -1 on error
+ */
+ssize_t
u8_u32_strncpy(char* to, const uint32_t* from, size_t max)
{
char* cfrom = NULL;
size_t len;
+ assert(to != NULL);
cfrom = calloc(max + 1, 1);
if (!cfrom)
- return 0;
+ return -1;
unicode_string_to_u8(cfrom, from, max);
len = strlen(cfrom);
strncpy(to, cfrom, max);
@@ -406,13 +433,13 @@ u8_u32_strncpy(char* to, const uint32_t* from, size_t max)
}
/* wrap - if >0, also wrap lines
- * */
+ */
size_t
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;
@@ -426,7 +453,7 @@ u32_lines_in_string(const uint32_t* s, const int include_eol, const size_t wrap)
}
/*if (ps > s + 1 && *(ps - 2) == '\\' && *(ps - 1) == 'n')
last_empty = 1;*/
- return result;// + last_empty;
+ return result; // + last_empty;
}
/*
diff --git a/util.h b/util.h
@@ -5,6 +5,25 @@
#include <stdint.h>
#include <sys/types.h>
+/* Whitespace definition for determining word boundaries */
+#define B_WS " \v\t-"
+/* Full word boundary delimiter definition */
+#define B_FULL " \v\t-()[]{},.;:/\\"
+
+/* 32-bit char constants */
+#define BSLASH ((uint32_t)0x0000005c)
+#define DOT ((uint32_t)0x0000002e)
+#define EN ((uint32_t)0x0000005c)
+#define NINE ((uint32_t)0x00000039)
+#define SPACE ((uint32_t)0x00000020)
+#define SEMICOL ((uint32_t)0x0000003b)
+#define TAB ((uint32_t)0x00000009)
+#define ZERO ((uint32_t)0x00000030)
+
+/* 32-bit string constants */
+extern const uint32_t bslash_en[];
+extern const uint32_t space_dot[];
+
#define ABS(a) ((a < 0) ? (-a) : (a))
#define LEN(x) (sizeof(x) / sizeof(x[0]))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
@@ -112,6 +131,7 @@ enum {
ERR_ILLEGAL_ON_FIRST,
ERR_SYNTAX,
ERR_NO_PLURAL_FORMS,
+ ERR_BAD_NPLURALS,
ERR_ERRNO_SET
};
@@ -127,19 +147,17 @@ enum { ACT_IDLE, ACT_WRITING, ACT_READING };
/* maximum chars for UTF-8 representations of Unicode chars, per Unicode char */
#define UTF8REPMAX 6
-extern int utlerrno;
-
size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max);
size_t unicode_string_to_u8(char* s, const uint32_t* us, const size_t max);
-size_t u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr,
- size_t max);
+ssize_t u32_match_msgid_ending(struct DrawState* state, 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);
-size_t u32_decode_tabs(uint32_t* s, size_t max);
+ssize_t u32_encode_tabs(struct DrawState* state, uint32_t* s, size_t max);
+ssize_t u32_decode_tabs(struct DrawState* state, uint32_t* s, size_t max);
size_t u8_strlen(const char* s);
size_t u32_strlen(const uint32_t* s);
const uint32_t* u32_strstr(const uint32_t* haystack, const uint32_t* needle);
@@ -147,7 +165,7 @@ const uint32_t* u32_strchr(const uint32_t* haystack, const uint32_t needle);
size_t u32_strncpy(uint32_t* to, const uint32_t* from, size_t max);
size_t u32_strncat(uint32_t* to, const uint32_t* from, size_t max);
size_t u32_u8_strncpy(uint32_t* to, const char* from, size_t max);
-size_t u8_u32_strncpy(char* to, const uint32_t* from, size_t max);
+ssize_t u8_u32_strncpy(char* to, const uint32_t* from, size_t max);
size_t u32_lines_in_string(const uint32_t* s, const int include_eol,
const size_t wrap);
size_t u32_next_line(const uint32_t* s, const uint32_t** sptr,