чување c40777e5210834012214e707bdd78bd45de743a9
родитељ 5b21322848c163934256ec0962cbb5dbf1d81f7b
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Thu, 10 Feb 2022 13:52:30 +0100
Finish WIP: add PoEntry.warning and draw logic
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | TODO | | | 6 | +++--- |
| M | config.def.h | | | 133 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
| M | config.h | | | 133 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
| M | draw.c | | | 27 | +++++++++++++++------------ |
| M | po.c | | | 26 | ++++++++++++++++++++++++++ |
| M | po.h | | | 2 | ++ |
| M | poe.1.in | | | 17 | +++++++++++++++++ |
| M | poe.c | | | 14 | ++++++++------ |
| M | util.c | | | 35 | ++++++++++++++++++++++++++++------- |
| M | util.h | | | 3 | ++- |
измењених датотека: 10, додавања: 247(+), брисања: 149(-)
diff --git a/TODO b/TODO
@@ -1,11 +1,11 @@
TODO
====
- [~] Investigate newlines loading and saving
+ [x] Investigate newlines loading and saving
[x] Fix line counting when \n at end of string
[x] Add heuristics to match the ending newline or dot
- [ ] Soft-warn when the number of newlines doesn't match
- (different color?)
+ [x] Soft-warn when the number of newlines doesn't match
+ (Different color? Yes.)
< > Wrap long lines? Not if it would complicate the code too much.
diff --git a/config.def.h b/config.def.h
@@ -1,70 +1,83 @@
/* See the file LICENSE for copyright and license details. */
-#define SAVE_WRAP_WIDTH 70
+#define SAVE_WRAP_WIDTH 70
#define WRAP_FIRST_MSGSTR 0
+#define WARN_COUNT_DOTS 0
-#define DLG_FG TB_BLACK
-#define DLG_BG TB_WHITE
-#define EDIT_MSGID_FG TB_BLACK | TB_BOLD
-#define EDIT_MSGID_BG TB_WHITE
-#define EDIT_MSGID_FOCUS_FG TB_BLACK
-#define EDIT_MSGID_FOCUS_BG TB_WHITE
-#define EDIT_MSGID_HEADING_FG TB_WHITE | TB_BOLD
-#define EDIT_MSGID_HEADING_BG TB_WHITE
-#define EDIT_MSGSTR_FG TB_BLACK | TB_BOLD
-#define EDIT_MSGSTR_BG TB_BLACK
-#define EDIT_MSGSTR_FOCUS_FG TB_YELLOW | TB_BOLD
-#define EDIT_MSGSTR_FOCUS_BG TB_BLACK
-#define ERROR_FG TB_WHITE | TB_BOLD
-#define ERROR_BG TB_RED
-#define FLAG_FG TB_YELLOW | TB_BOLD
-#define FLAG_BG TB_DEFAULT
-#define LIST_FLAGS_FG TB_YELLOW | TB_BOLD
-#define LIST_FLAGS_BG TB_DEFAULT
-#define LIST_FLAGS_SEL_FG TB_WHITE | TB_BOLD
-#define LIST_FLAGS_SEL_BG TB_BLUE
-#define LIST_MSGID_FG TB_WHITE
-#define LIST_MSGID_BG TB_DEFAULT
-#define LIST_MSGID_SEL_FG TB_WHITE
-#define LIST_MSGID_SEL_BG TB_BLUE
-#define LIST_MSGID_SPECIAL_FG TB_YELLOW | TB_BOLD
-#define LIST_MSGID_SPECIAL_BG TB_DEFAULT
-#define LIST_MSGID_SPECIAL_SEL_FG TB_WHITE | TB_BOLD
-#define LIST_MSGID_SPECIAL_SEL_BG TB_BLUE
-#define LIST_MSGSTR_FG TB_GREEN
-#define LIST_MSGSTR_BG TB_DEFAULT
-#define LIST_MSGSTR_SEL_FG TB_WHITE | TB_BOLD
-#define LIST_MSGSTR_SEL_BG TB_BLUE
-#define LIST_SEL_FG TB_WHITE
-#define LIST_SEL_BG TB_BLUE
-#define MSGID_FG TB_GREEN
-#define MSGID_BG TB_DEFAULT
-#define MSGSTR_FG TB_WHITE
-#define MSGSTR_BG TB_DEFAULT
-#define PROMPT_FG TB_YELLOW | TB_BOLD
-#define PROMPT_BG TB_MAGENTA
-#define SEARCH_FG TB_BLACK
-#define SEARCH_BG TB_WHITE
-#define SEARCH_EDIT_FG TB_WHITE | TB_BOLD
-#define SEARCH_EDIT_BG TB_BLACK
-#define SEARCH_HL_FG TB_WHITE | TB_BOLD
-#define SEARCH_HL_BG TB_GREEN
-#define SHADOW_FG TB_BLACK
-#define SHADOW_BG TB_BLACK | TB_BOLD
-#define TITLE_FG TB_BLACK
-#define TITLE_BG TB_WHITE
+#define DLG_FG TB_BLACK
+#define DLG_BG TB_WHITE
+#define EDIT_MSGID_FG TB_BLACK | TB_BOLD
+#define EDIT_MSGID_BG TB_WHITE
+#define EDIT_MSGID_FOCUS_FG TB_BLACK
+#define EDIT_MSGID_FOCUS_BG TB_WHITE
+#define EDIT_MSGID_HEADING_FG TB_WHITE | TB_BOLD
+#define EDIT_MSGID_HEADING_BG TB_WHITE
+#define EDIT_MSGSTR_FG TB_BLACK | TB_BOLD
+#define EDIT_MSGSTR_BG TB_BLACK
+#define EDIT_MSGSTR_FOCUS_FG TB_YELLOW | TB_BOLD
+#define EDIT_MSGSTR_FOCUS_BG TB_BLACK
+#define ERROR_FG TB_WHITE | TB_BOLD
+#define ERROR_BG TB_RED
+#define FLAG_FG TB_YELLOW | TB_BOLD
+#define FLAG_BG TB_DEFAULT
+#define LIST_FLAGS_FG TB_YELLOW | TB_BOLD
+#define LIST_FLAGS_BG TB_DEFAULT
+#define LIST_FLAGS_SEL_FG TB_WHITE | TB_BOLD
+#define LIST_FLAGS_SEL_BG TB_BLUE
+#define LIST_MSGID_FG TB_WHITE
+#define LIST_MSGID_BG TB_DEFAULT
+#define LIST_MSGID_SEL_FG TB_WHITE
+#define LIST_MSGID_SEL_BG TB_BLUE
+#define LIST_MSGID_SPECIAL_FG TB_YELLOW | TB_BOLD
+#define LIST_MSGID_SPECIAL_BG TB_DEFAULT
+#define LIST_MSGID_SPECIAL_SEL_FG TB_WHITE | TB_BOLD
+#define LIST_MSGID_SPECIAL_SEL_BG TB_BLUE
+#define LIST_MSGSTR_FG TB_GREEN
+#define LIST_MSGSTR_BG TB_DEFAULT
+#define LIST_MSGSTR_SEL_FG TB_WHITE | TB_BOLD
+#define LIST_MSGSTR_SEL_BG TB_BLUE
+#define LIST_MSGSTR_WARN_FG TB_RED | TB_BOLD
+#define LIST_MSGSTR_WARN_BG TB_DEFAULT
+#define LIST_MSGSTR_SEL_WARN_FG TB_RED | TB_BOLD
+#define LIST_MSGSTR_SEL_WARN_BG TB_BLUE
+#define LIST_SEL_FG TB_WHITE
+#define LIST_SEL_BG TB_BLUE
+#define MSGID_FG TB_GREEN
+#define MSGID_BG TB_DEFAULT
+#define MSGSTR_FG TB_WHITE
+#define MSGSTR_BG TB_DEFAULT
+#define PROMPT_FG TB_YELLOW | TB_BOLD
+#define PROMPT_BG TB_MAGENTA
+#define SEARCH_FG TB_BLACK
+#define SEARCH_BG TB_WHITE
+#define SEARCH_EDIT_FG TB_WHITE | TB_BOLD
+#define SEARCH_EDIT_BG TB_BLACK
+#define SEARCH_HL_FG TB_WHITE | TB_BOLD
+#define SEARCH_HL_BG TB_GREEN
+#define SHADOW_FG TB_BLACK
+#define SHADOW_BG TB_BLACK | TB_BOLD
+#define TITLE_FG TB_BLACK
+#define TITLE_BG TB_WHITE
void format_filename(char* result, size_t result_size, const char* format,
- const struct DrawState* state);
+ const struct DrawState* state);
void format_msgs(char* result, size_t result_size, const char* format,
- const struct DrawState* state);
+ const struct DrawState* state);
static const struct StatusSegment status_segments[] = {
- { .format = "%s%s", .callback = format_filename,
- .fg = TB_BLACK, .bg = TB_WHITE, .alignment = LEFT },
- { .format = "%ld/%ld (%ldu/%ldf/%ldo)",
- .callback = format_msgs,
- .fg = TB_WHITE | TB_BOLD, .bg = TB_BLUE, .alignment = CENTER },
- { .format = "H=HELP, q=QUIT", .callback = NULL,
- .fg = TB_BLACK, .bg = TB_WHITE, .alignment = RIGHT },
+ {.format = "%s%s",
+ .callback = format_filename,
+ .fg = TB_BLACK,
+ .bg = TB_WHITE,
+ .alignment = LEFT},
+ {.format = "%ld/%ld (%ldu/%ldf/%ldo)",
+ .callback = format_msgs,
+ .fg = TB_WHITE | TB_BOLD,
+ .bg = TB_BLUE,
+ .alignment = CENTER},
+ {.format = "H=HELP, q=QUIT",
+ .callback = NULL,
+ .fg = TB_BLACK,
+ .bg = TB_WHITE,
+ .alignment = RIGHT},
};
diff --git a/config.h b/config.h
@@ -1,70 +1,83 @@
/* See the file LICENSE for copyright and license details. */
-#define SAVE_WRAP_WIDTH 70
+#define SAVE_WRAP_WIDTH 70
#define WRAP_FIRST_MSGSTR 0
+#define WARN_COUNT_DOTS 0
-#define DLG_FG TB_BLACK
-#define DLG_BG TB_WHITE
-#define EDIT_MSGID_FG TB_BLACK | TB_BOLD
-#define EDIT_MSGID_BG TB_WHITE
-#define EDIT_MSGID_FOCUS_FG TB_BLACK
-#define EDIT_MSGID_FOCUS_BG TB_WHITE
-#define EDIT_MSGID_HEADING_FG TB_WHITE | TB_BOLD
-#define EDIT_MSGID_HEADING_BG TB_WHITE
-#define EDIT_MSGSTR_FG TB_BLACK | TB_BOLD
-#define EDIT_MSGSTR_BG TB_BLACK
-#define EDIT_MSGSTR_FOCUS_FG TB_YELLOW | TB_BOLD
-#define EDIT_MSGSTR_FOCUS_BG TB_BLACK
-#define ERROR_FG TB_WHITE | TB_BOLD
-#define ERROR_BG TB_RED
-#define FLAG_FG TB_YELLOW | TB_BOLD
-#define FLAG_BG TB_DEFAULT
-#define LIST_FLAGS_FG TB_YELLOW | TB_BOLD
-#define LIST_FLAGS_BG TB_DEFAULT
-#define LIST_FLAGS_SEL_FG TB_WHITE | TB_BOLD
-#define LIST_FLAGS_SEL_BG TB_BLUE
-#define LIST_MSGID_FG TB_WHITE
-#define LIST_MSGID_BG TB_DEFAULT
-#define LIST_MSGID_SEL_FG TB_WHITE
-#define LIST_MSGID_SEL_BG TB_BLUE
-#define LIST_MSGID_SPECIAL_FG TB_YELLOW | TB_BOLD
-#define LIST_MSGID_SPECIAL_BG TB_DEFAULT
-#define LIST_MSGID_SPECIAL_SEL_FG TB_WHITE | TB_BOLD
-#define LIST_MSGID_SPECIAL_SEL_BG TB_BLUE
-#define LIST_MSGSTR_FG TB_GREEN
-#define LIST_MSGSTR_BG TB_DEFAULT
-#define LIST_MSGSTR_SEL_FG TB_WHITE | TB_BOLD
-#define LIST_MSGSTR_SEL_BG TB_BLUE
-#define LIST_SEL_FG TB_WHITE
-#define LIST_SEL_BG TB_BLUE
-#define MSGID_FG TB_GREEN
-#define MSGID_BG TB_DEFAULT
-#define MSGSTR_FG TB_WHITE
-#define MSGSTR_BG TB_DEFAULT
-#define PROMPT_FG TB_YELLOW | TB_BOLD
-#define PROMPT_BG TB_MAGENTA
-#define SEARCH_FG TB_BLACK
-#define SEARCH_BG TB_WHITE
-#define SEARCH_EDIT_FG TB_WHITE | TB_BOLD
-#define SEARCH_EDIT_BG TB_BLACK
-#define SEARCH_HL_FG TB_WHITE | TB_BOLD
-#define SEARCH_HL_BG TB_GREEN
-#define SHADOW_FG TB_BLACK
-#define SHADOW_BG TB_BLACK | TB_BOLD
-#define TITLE_FG TB_BLACK
-#define TITLE_BG TB_WHITE
+#define DLG_FG TB_BLACK
+#define DLG_BG TB_WHITE
+#define EDIT_MSGID_FG TB_BLACK | TB_BOLD
+#define EDIT_MSGID_BG TB_WHITE
+#define EDIT_MSGID_FOCUS_FG TB_BLACK
+#define EDIT_MSGID_FOCUS_BG TB_WHITE
+#define EDIT_MSGID_HEADING_FG TB_WHITE | TB_BOLD
+#define EDIT_MSGID_HEADING_BG TB_WHITE
+#define EDIT_MSGSTR_FG TB_BLACK | TB_BOLD
+#define EDIT_MSGSTR_BG TB_BLACK
+#define EDIT_MSGSTR_FOCUS_FG TB_YELLOW | TB_BOLD
+#define EDIT_MSGSTR_FOCUS_BG TB_BLACK
+#define ERROR_FG TB_WHITE | TB_BOLD
+#define ERROR_BG TB_RED
+#define FLAG_FG TB_YELLOW | TB_BOLD
+#define FLAG_BG TB_DEFAULT
+#define LIST_FLAGS_FG TB_YELLOW | TB_BOLD
+#define LIST_FLAGS_BG TB_DEFAULT
+#define LIST_FLAGS_SEL_FG TB_WHITE | TB_BOLD
+#define LIST_FLAGS_SEL_BG TB_BLUE
+#define LIST_MSGID_FG TB_WHITE
+#define LIST_MSGID_BG TB_DEFAULT
+#define LIST_MSGID_SEL_FG TB_WHITE
+#define LIST_MSGID_SEL_BG TB_BLUE
+#define LIST_MSGID_SPECIAL_FG TB_YELLOW | TB_BOLD
+#define LIST_MSGID_SPECIAL_BG TB_DEFAULT
+#define LIST_MSGID_SPECIAL_SEL_FG TB_WHITE | TB_BOLD
+#define LIST_MSGID_SPECIAL_SEL_BG TB_BLUE
+#define LIST_MSGSTR_FG TB_GREEN
+#define LIST_MSGSTR_BG TB_DEFAULT
+#define LIST_MSGSTR_SEL_FG TB_WHITE | TB_BOLD
+#define LIST_MSGSTR_SEL_BG TB_BLUE
+#define LIST_MSGSTR_WARN_FG TB_RED | TB_BOLD
+#define LIST_MSGSTR_WARN_BG TB_DEFAULT
+#define LIST_MSGSTR_SEL_WARN_FG TB_RED | TB_BOLD
+#define LIST_MSGSTR_SEL_WARN_BG TB_BLUE
+#define LIST_SEL_FG TB_WHITE
+#define LIST_SEL_BG TB_BLUE
+#define MSGID_FG TB_GREEN
+#define MSGID_BG TB_DEFAULT
+#define MSGSTR_FG TB_WHITE
+#define MSGSTR_BG TB_DEFAULT
+#define PROMPT_FG TB_YELLOW | TB_BOLD
+#define PROMPT_BG TB_MAGENTA
+#define SEARCH_FG TB_BLACK
+#define SEARCH_BG TB_WHITE
+#define SEARCH_EDIT_FG TB_WHITE | TB_BOLD
+#define SEARCH_EDIT_BG TB_BLACK
+#define SEARCH_HL_FG TB_WHITE | TB_BOLD
+#define SEARCH_HL_BG TB_GREEN
+#define SHADOW_FG TB_BLACK
+#define SHADOW_BG TB_BLACK | TB_BOLD
+#define TITLE_FG TB_BLACK
+#define TITLE_BG TB_WHITE
void format_filename(char* result, size_t result_size, const char* format,
- const struct DrawState* state);
+ const struct DrawState* state);
void format_msgs(char* result, size_t result_size, const char* format,
- const struct DrawState* state);
+ const struct DrawState* state);
static const struct StatusSegment status_segments[] = {
- { .format = "%s%s", .callback = format_filename,
- .fg = TB_BLACK, .bg = TB_WHITE, .alignment = LEFT },
- { .format = "%ld/%ld (%ldu/%ldf/%ldo)",
- .callback = format_msgs,
- .fg = TB_WHITE | TB_BOLD, .bg = TB_BLUE, .alignment = CENTER },
- { .format = "H=HELP, q=QUIT", .callback = NULL,
- .fg = TB_BLACK, .bg = TB_WHITE, .alignment = RIGHT },
+ {.format = "%s%s",
+ .callback = format_filename,
+ .fg = TB_BLACK,
+ .bg = TB_WHITE,
+ .alignment = LEFT},
+ {.format = "%ld/%ld (%ldu/%ldf/%ldo)",
+ .callback = format_msgs,
+ .fg = TB_WHITE | TB_BOLD,
+ .bg = TB_BLUE,
+ .alignment = CENTER},
+ {.format = "H=HELP, q=QUIT",
+ .callback = NULL,
+ .fg = TB_BLACK,
+ .bg = TB_WHITE,
+ .alignment = RIGHT},
};
diff --git a/draw.c b/draw.c
@@ -826,18 +826,21 @@ draw_list_visible(const struct DrawState* state)
/* don't use msgstr_index as then the entire list will shift
* when changing currently displayed plural form msgstr in an
* edit box */
- if (current->msgstr && current->msgstr_count > 0
- && current->msgstr + state->msgstr_index)
- u32_draw_string(state->maxx/2, cy,
- sel ? LIST_MSGSTR_SEL_FG
- : LIST_MSGSTR_FG,
- sel ? LIST_MSGSTR_SEL_BG
- : LIST_MSGSTR_BG,
- *(current->msgstr /*+
- state->msgstr_index*/),
- state->maxx/2, state->maxx/2, 2, 2,
- LEFT, 0, 1, state->search, SEARCH_HL_FG,
- SEARCH_HL_BG);
+ if (current->msgstr && current->msgstr_count > 0)
+ u32_draw_string(state->maxx / 2, cy,
+ current->warning
+ ? (sel ? LIST_MSGSTR_SEL_WARN_FG
+ : LIST_MSGSTR_WARN_FG)
+ : (sel ? LIST_MSGSTR_SEL_FG
+ : LIST_MSGSTR_FG),
+ current->warning
+ ? (sel ? LIST_MSGSTR_SEL_WARN_BG
+ : LIST_MSGSTR_WARN_BG)
+ : (sel ? LIST_MSGSTR_SEL_BG
+ : LIST_MSGSTR_BG),
+ *(current->msgstr), state->maxx / 2,
+ state->maxx / 2, 2, 2, LEFT, 0, 1,
+ state->search, SEARCH_HL_FG, SEARCH_HL_BG);
i++;
cy++;
}
diff --git a/po.c b/po.c
@@ -29,6 +29,7 @@ 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;
@@ -399,6 +400,7 @@ load_file(struct DrawState* dstate, long* lineno, long* col)
{
struct PoEntry* newchunk = calloc(ALLOC_DELTA, sizeof(struct PoEntry));
struct PoEntry* entry = NULL;
+ struct PoEntry* current = NULL;
ParseState pstate = PS_NONE;
int has_plural_msgid = 0;
@@ -479,6 +481,15 @@ load_file(struct DrawState* dstate, long* lineno, long* col)
update_statistics(dstate->entries, dstate, entry);
dstate->real_msgid_count = dstate->msgid_count + dstate->obsolete_count;
+ current = dstate->entries;
+ while (current != dstate->entries + dstate->real_msgid_count)
+ {
+ if (!current->obsolete)
+ update_warning(current->msgid, *current->msgstr,
+ ¤t->warning);
+ current++;
+ }
+
return LOAD_ERR_NONE;
}
@@ -1194,3 +1205,18 @@ update_statistics(const struct PoEntry* entries, struct DrawState* state,
current++;
}
}
+
+void
+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")
+ || (WARN_COUNT_DOTS
+ && u32_count_chars(msgid, '.')
+ != u32_count_chars(msgstr, '.')))
+ *warning = 1;
+ else
+ *warning = 0;
+}
diff --git a/po.h b/po.h
@@ -69,6 +69,7 @@ typedef enum {
struct PoEntry {
Flags flags;
int obsolete;
+ int warning;
uint32_t* msgid;
size_t msgid_size;
size_t msgid_len;
@@ -119,3 +120,4 @@ int parse_po_line(const char* line, struct DrawState* dstate,
int* msgstr_index);
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
@@ -167,6 +167,23 @@ _
.
.sp 1
.
+.SH "ERROR CHECKING"
+.
+.LP
+.B poe
+has some rudimentary checks of the translated messages built in. First, when
+saving changes in the edit box, if the msgid has a newline character
+(\fC\\n\fP), a dot (\fC.\fP) or a space (\fC\~\fP) at the end, and the
+corresponding msgstr doesn't, msgstr being saved will have its ending character
+made to match the one from the msgid.
+.
+.PP
+Second, if the numbers of newline characters (\fC\\n\fP) in msgid and msgstr
+don't match, msgstr will be shown in a different color on the main screen. If
+the number of newlines was intended, you can simply ignore this warning.
+Otherwise, it can be useful to detect unwanted discrepancies in formatting
+between the original message and the translation.
+.
.SH AUTHOR
.
Strahinya Radich,
diff --git a/poe.c b/poe.c
@@ -468,8 +468,9 @@ load_msgstr(struct DrawState* state)
void
save_msgstr(struct DrawState* state)
{
- uint32_t* to_save = NULL;
- size_t to_save_size = 0;
+ uint32_t* to_save = NULL;
+ size_t to_save_size = 0;
+ struct PoEntry* current = NULL;
state->show_edit = 0;
state->edit_info_focused = 0;
@@ -510,10 +511,11 @@ save_msgstr(struct DrawState* state)
state->info_rows_count = 0;
state->info_buffer = NULL;
u32_encode_tabs(to_save, to_save_size * sizeof(uint32_t));
- u32_match_msgid_ending(state->entries[state->msgid_number - 1].msgid,
- to_save, to_save_size * sizeof(uint32_t));
- u32_set_msgstr(&state->entries[state->msgid_number - 1], to_save,
- state->msgstr_index, 0, state);
+ current = &state->entries[state->msgid_number - 1];
+ u32_match_msgid_ending(current->msgid, to_save,
+ to_save_size * sizeof(uint32_t));
+ u32_set_msgstr(current, to_save, state->msgstr_index, 0, state);
+ update_warning(current->msgid, to_save, ¤t->warning);
state->input_changed_fuzzy = UNCHANGED;
tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR);
diff --git a/util.c b/util.c
@@ -94,14 +94,12 @@ u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr, size_t max)
}
}
else if (buf_len > 1
- && u32_starts_with(buf + buf_len - 2,
- (uint32_t*)L"\\n"))
+ && u32_starts_with(buf + buf_len - 2, (uint32_t*)L"\\n"))
{
buf_len -= 2;
buf[buf_len] = 0;
}
- else if (buf_len > 0
- && u32_strstr((uint32_t*)L" .", buf + buf_len - 1))
+ else if (buf_len > 0 && u32_strstr((uint32_t*)L" .", buf + buf_len - 1))
{
buf_len--;
buf[buf_len] = 0;
@@ -113,10 +111,10 @@ u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr, size_t max)
}
size_t
-u32_num_chars(uint32_t* s, uint32_t ch)
+u32_count_chars(const uint32_t* s, const uint32_t ch)
{
- size_t result = 0;
- uint32_t* ps = s;
+ size_t result = 0;
+ const uint32_t* ps = s;
while (*ps)
{
if (*ps == ch)
@@ -127,6 +125,29 @@ u32_num_chars(uint32_t* s, 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;
+
+ if (!haystack || !needle)
+ return 0;
+
+ needle_len = u32_strlen(needle);
+ if (!needle_len)
+ return 0;
+
+ while (*phaystack)
+ {
+ if (u32_starts_with(phaystack, needle))
+ result++;
+ phaystack++;
+ }
+ return result;
+}
+
+size_t
u32_encode_tabs(uint32_t* s, size_t max)
{
uint32_t* buf = calloc(max + 1, sizeof(uint32_t));
diff --git a/util.h b/util.h
@@ -31,7 +31,8 @@ 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);
-size_t u32_num_chars(uint32_t* s, uint32_t ch);
+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);
size_t u32_strlen(const uint32_t* s);