summaryrefslogtreecommitdiffstats
path: root/gettext-tools/src/msgl-check.c
diff options
context:
space:
mode:
Diffstat (limited to 'gettext-tools/src/msgl-check.c')
-rw-r--r--gettext-tools/src/msgl-check.c205
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;
+}