diff options
Diffstat (limited to 'gettext-tools/src/msgl-check.c')
-rw-r--r-- | gettext-tools/src/msgl-check.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/gettext-tools/src/msgl-check.c b/gettext-tools/src/msgl-check.c index d6f4a3d..b5f2537 100644 --- a/gettext-tools/src/msgl-check.c +++ b/gettext-tools/src/msgl-check.c @@ -40,6 +40,10 @@ #include "plural-table.h" #include "c-strstr.h" #include "message.h" +#include "quote.h" +#include "sentence.h" +#include "unictype.h" +#include "unistr.h" #include "gettext.h" #define _(str) gettext (str) @@ -912,3 +916,204 @@ check_message_list (message_list_ty *mlp, return seen_errors; } + + +static int +syntax_check_ellipsis_unicode (const message_ty *mp, const char *msgid) +{ + const char *str = msgid; + const char *str_limit = str + strlen (msgid); + int seen_errors = 0; + + while (str < str_limit) + { + const char *end, *cp; + ucs4_t ending_char; + + end = sentence_end (str, &ending_char); + + /* sentence_end doesn't treat '...' specially. */ + cp = end - (ending_char == '.' ? 2 : 3); + if (cp >= str && memcmp (cp, "...", 3) == 0) + { + po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0, false, + _("ASCII ellipsis ('...') instead of Unicode")); + seen_errors++; + } + + str = end + 1; + } + + return seen_errors; +} + + +static int +syntax_check_space_ellipsis (const message_ty *mp, const char *msgid) +{ + const char *str = msgid; + const char *str_limit = str + strlen (msgid); + int seen_errors = 0; + + while (str < str_limit) + { + const char *end, *ellipsis = NULL; + ucs4_t ending_char; + + end = sentence_end (str, &ending_char); + + if (ending_char == 0x2026) + ellipsis = end; + else if (ending_char == '.') + { + /* sentence_end doesn't treat '...' specially. */ + const char *cp = end - 2; + if (cp >= str && memcmp (cp, "...", 3) == 0) + ellipsis = cp; + } + else + { + /* Look for a '...'. */ + const char *cp = end - 3; + if (cp >= str && memcmp (cp, "...", 3) == 0) + ellipsis = cp; + else + { + ucs4_t uc = 0xfffd; + + /* Look for a U+2026. */ + for (cp = end - 1; cp >= str; cp--) + { + u8_mbtouc (&uc, (const unsigned char *) cp, ellipsis - cp); + if (uc != 0xfffd) + break; + } + + if (uc == 0x2026) + ellipsis = cp; + } + } + + if (ellipsis) + { + const char *cp; + ucs4_t uc = 0xfffd; + + /* Look at the character before ellipsis. */ + for (cp = ellipsis - 1; cp >= str; cp--) + { + u8_mbtouc (&uc, (const unsigned char *) cp, ellipsis - cp); + if (uc != 0xfffd) + break; + } + + if (uc != 0xfffd && uc_is_space (uc)) + { + po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0, false, + _("\ +space before ellipsis found in user visible strings")); + seen_errors++; + } + } + + str = end + 1; + } + + return seen_errors; +} + + +struct callback_arg +{ + const message_ty *mp; + int seen_errors; +}; + +static void +syntax_check_quote_unicode_callback (char quote, const char *quoted, + size_t quoted_length, void *data) +{ + struct callback_arg *arg = data; + + switch (quote) + { + case '"': + po_xerror (PO_SEVERITY_ERROR, arg->mp, NULL, 0, 0, false, + _("ASCII double quote used instead of Unicode")); + arg->seen_errors++; + break; + + case '\'': + po_xerror (PO_SEVERITY_ERROR, arg->mp, NULL, 0, 0, false, + _("ASCII single quote used instead of Unicode")); + arg->seen_errors++; + break; + + default: + break; + } +} + +static int +syntax_check_quote_unicode (const message_ty *mp, const char *msgid) +{ + struct callback_arg arg; + + arg.mp = mp; + arg.seen_errors = 0; + + scan_quoted (msgid, strlen (msgid), + syntax_check_quote_unicode_callback, &arg); + + return arg.seen_errors; +} + + +typedef int (* syntax_check_function) (const message_ty *mp, const char *msgid); +static const syntax_check_function sc_funcs[NSYNTAXCHECKS] = +{ + syntax_check_ellipsis_unicode, + syntax_check_space_ellipsis, + syntax_check_quote_unicode +}; + +/* Perform all syntax checks on a non-obsolete message. + Return the number of errors that were seen. */ +static int +syntax_check_message (const message_ty *mp) +{ + int seen_errors = 0; + int i; + + for (i = 0; i < NSYNTAXCHECKS; i++) + { + if (mp->do_syntax_check[i] == yes) + { + seen_errors += sc_funcs[i] (mp, mp->msgid); + if (mp->msgid_plural) + seen_errors += sc_funcs[i] (mp, mp->msgid_plural); + } + } + + return seen_errors; +} + + +/* Perform all syntax checks on a message list. + Return the number of errors that were seen. */ +int +syntax_check_message_list (message_list_ty *mlp) +{ + int seen_errors = 0; + size_t j; + + for (j = 0; j < mlp->nitems; j++) + { + message_ty *mp = mlp->item[j]; + + if (!is_header (mp)) + seen_errors += syntax_check_message (mp); + } + + return seen_errors; +} |