]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Avoid breaking line in the middle of a format directive.
authorBruno Haible <bruno@clisp.org>
Wed, 26 Dec 2007 15:44:50 +0000 (15:44 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:15:34 +0000 (12:15 +0200)
gettext-tools/src/ChangeLog
gettext-tools/src/write-po.c
gettext-tools/tests/ChangeLog
gettext-tools/tests/Makefile.am
gettext-tools/tests/msgcat-17 [new file with mode: 0755]

index 500e65cedc437b087260e80e96730fa72ddd38da..a7aac4093988a04da794b424cfe1fe68e230b9e3 100644 (file)
@@ -1,3 +1,9 @@
+2007-12-22  Bruno Haible  <bruno@clisp.org>
+
+       * write-po.c (wrap): Avoid breaking line in the middle of a format
+       directive.
+       Reported by Dwayne Bailey <dwayne@translate.org.za>.
+
 2007-11-07  Jim Meyering  <meyering@redhat.com>
             Bruno Haible  <bruno@clisp.org>
 
index 105d062cd320c59543dbf1712e8fbd1558196231..5961fa92c6750cd0c0f8178206dbfce3c0a3a7cb 100644 (file)
@@ -522,6 +522,7 @@ wrap (const message_ty *mp, ostream_t stream,
 {
   const char *canon_charset;
   char *fmtdir;
+  char *fmtdirattr;
   const char *s;
   bool first_line;
 #if HAVE_ICONV
@@ -583,7 +584,8 @@ wrap (const message_ty *mp, ostream_t stream,
 
   /* Determine the extent of format string directives.  */
   fmtdir = NULL;
-  if (is_stylable (stream) && value[0] != '\0')
+  fmtdirattr = NULL;
+  if (value[0] != '\0')
     {
       bool is_msgstr =
        (strlen (name) >= 6 && memcmp (name, "msgstr", 6) == 0);
@@ -597,8 +599,9 @@ wrap (const message_ty *mp, ostream_t stream,
            struct formatstring_parser *parser = formatstring_parsers[i];
            char *invalid_reason = NULL;
            void *descr;
-           char *fdp;
-           char *fd_end;
+           const char *fdp;
+           const char *fd_end;
+           char *fdap;
 
            fmtdir = XCALLOC (len, char);
            descr = parser->parse (value, is_msgstr, fmtdir, &invalid_reason);
@@ -607,11 +610,13 @@ wrap (const message_ty *mp, ostream_t stream,
 
            /* Locate the FMTDIR_* bits and transform the array to an array
               of attributes.  */
+           fmtdirattr = XCALLOC (len, char);
+           fdap = fmtdirattr;
            fd_end = fmtdir + len;
-           for (fdp = fmtdir; fdp < fd_end; fdp++)
+           for (fdp = fmtdir, fdap = fmtdirattr; fdp < fd_end; fdp++, fdap++)
              if (*fdp & FMTDIR_START)
                {
-                 char *fdq;
+                 const char *fdq;
                  for (fdq = fdp; fdq < fd_end; fdq++)
                    if (*fdq & (FMTDIR_END | FMTDIR_ERROR))
                      break;
@@ -621,13 +626,14 @@ wrap (const message_ty *mp, ostream_t stream,
                       its end. It is a bug in the ->parse method.  */
                    abort ();
                  if (*fdq & FMTDIR_ERROR)
-                   memset (fdp, ATTR_INVALID_FORMAT_DIRECTIVE, fdq - fdp + 1);
+                   memset (fdap, ATTR_INVALID_FORMAT_DIRECTIVE, fdq - fdp + 1);
                  else
-                   memset (fdp, ATTR_FORMAT_DIRECTIVE, fdq - fdp + 1);
+                   memset (fdap, ATTR_FORMAT_DIRECTIVE, fdq - fdp + 1);
+                 fdap += fdq - fdp;
                  fdp = fdq;
                }
              else
-               *fdp = 0;
+               *fdap = 0;
 
            break;
          }
@@ -733,12 +739,16 @@ wrap (const message_ty *mp, ostream_t stream,
        }
       portion = XNMALLOC (portion_len, char);
       overrides = XNMALLOC (portion_len, char);
-      memset (overrides, UC_BREAK_UNDEFINED, portion_len);
       attributes = XNMALLOC (portion_len, char);
       for (ep = s, pp = portion, op = overrides, ap = attributes; ep < es; ep++)
        {
          char c = *ep;
-         char attr = (fmtdir != NULL ? fmtdir[ep - value] : 0);
+         char attr = (fmtdirattr != NULL ? fmtdirattr[ep - value] : 0);
+         char brk = UC_BREAK_UNDEFINED;
+         /* Don't break inside format directives.  */
+         if (attr == ATTR_FORMAT_DIRECTIVE
+             && (fmtdir[ep - value] & FMTDIR_START) == 0)
+           brk = UC_BREAK_PROHIBITED;
          if (is_escape (c))
            {
              switch (c)
@@ -754,7 +764,7 @@ wrap (const message_ty *mp, ostream_t stream,
                }
              *pp++ = '\\';
              *pp++ = c;
-             op++;
+             *op++ = brk;
              *op++ = UC_BREAK_PROHIBITED;
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
@@ -777,7 +787,7 @@ internationalized messages should not contain the `\\%c' escape sequence"),
              *pp++ = '0' + (((unsigned char) c >> 6) & 7);
              *pp++ = '0' + (((unsigned char) c >> 3) & 7);
              *pp++ = '0' + ((unsigned char) c & 7);
-             op++;
+             *op++ = brk;
              *op++ = UC_BREAK_PROHIBITED;
              *op++ = UC_BREAK_PROHIBITED;
              *op++ = UC_BREAK_PROHIBITED;
@@ -790,7 +800,7 @@ internationalized messages should not contain the `\\%c' escape sequence"),
            {
              *pp++ = '\\';
              *pp++ = c;
-             op++;
+             *op++ = brk;
              *op++ = UC_BREAK_PROHIBITED;
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
@@ -838,6 +848,8 @@ internationalized messages should not contain the `\\%c' escape sequence"),
                  insize = inptr - ep;
                  memcpy_small (pp, ep, insize);
                  pp += insize;
+                 *op = brk;
+                 memset_small (op + 1, UC_BREAK_PROHIBITED, insize - 1);
                  op += insize;
                  memset_small (ap, attr, insize);
                  ap += insize;
@@ -855,14 +867,15 @@ internationalized messages should not contain the `\\%c' escape sequence"),
                      *pp++ = c;
                      ep += 1;
                      *pp++ = *ep;
-                     op += 2;
+                     *op++ = brk;
+                     *op++ = UC_BREAK_PROHIBITED;
                      *ap++ = attr;
                      *ap++ = attr;
                    }
                  else
                    {
                      *pp++ = c;
-                     op++;
+                     *op++ = brk;
                      *ap++ = attr;
                    }
                }
@@ -1118,6 +1131,8 @@ internationalized messages should not contain the `\\%c' escape sequence"),
     }
   while (*s);
 
+  if (fmtdirattr != NULL)
+    free (fmtdirattr);
   if (fmtdir != NULL)
     free (fmtdir);
 
index d048b214d4d8405a8ac973c901c98dc464663130..7386cfabc3fe6ed5638868747a933975f0dc7977 100644 (file)
@@ -1,3 +1,8 @@
+2007-12-22  Bruno Haible  <bruno@clisp.org>
+
+       * msgcat-17: New file.
+       * Makefile.am (TESTS): Add it.
+
 2007-11-15  Bruno Haible  <bruno@clisp.org>
 
        * gettext-8-prg.c: New file.
index ebd03f9cb1458d6264cefc6ff83c17223ceb3efe..a88d13830ad2c7ae655faab8d993ce72227a6bf7 100644 (file)
@@ -29,7 +29,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \
        msgattrib-properties-1 \
        msgcat-1 msgcat-2 msgcat-3 msgcat-4 msgcat-5 msgcat-6 msgcat-7 \
        msgcat-8 msgcat-9 msgcat-10 msgcat-11 msgcat-12 msgcat-13 msgcat-14 \
-       msgcat-15 msgcat-16 \
+       msgcat-15 msgcat-16 msgcat-17 \
        msgcat-properties-1 msgcat-properties-2 \
        msgcat-stringtable-1 \
        msgcmp-1 msgcmp-2 msgcmp-3 msgcmp-4 \
diff --git a/gettext-tools/tests/msgcat-17 b/gettext-tools/tests/msgcat-17
new file mode 100755 (executable)
index 0000000..1bc47b3
--- /dev/null
@@ -0,0 +1,60 @@
+#! /bin/sh
+
+# Test msgcat with --width option. Check that format strings are not broken.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="$tmpfiles mcat-test17.in"
+cat <<\EOF > mcat-test17.in
+msgid ""
+msgstr ""
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "write error of a large result on a too small disk%s%s"
+msgstr "Fehler beim Schreiben eines großen Ergebnisses auf eine zu kleine Platte%s%smit der jederzeitigen Möglichkeit eines Fehlers in jedem Moment und an jeder Stelle"
+
+#, c-format
+msgid "write error of a big result on a too small disk%s%s"
+msgstr "Fehler beim Schreiben eines großen Ergebnisses auf eine zu kleine Platte%s%smit der jederzeitigen Möglichkeit eines Fehlers in jedem Moment und an jeder Stelle"
+EOF
+
+tmpfiles="$tmpfiles mcat-test17.tmp mcat-test17.out"
+rm -f mcat-test17.tmp
+: ${MSGCAT=msgcat}
+${MSGCAT} -o mcat-test17.tmp --width=80 mcat-test17.in
+test $? = 0 || { rm -fr $tmpfiles; exit 1; }
+tr -d '\r' < mcat-test17.tmp > mcat-test17.out
+test $? = 0 || { rm -fr $tmpfiles; exit 1; }
+
+tmpfiles="$tmpfiles mcat-test17.ok"
+cat <<\EOF > mcat-test17.ok
+msgid ""
+msgstr ""
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "write error of a large result on a too small disk%s%s"
+msgstr ""
+"Fehler beim Schreiben eines großen Ergebnisses auf eine zu kleine Platte%s%"
+"smit der jederzeitigen Möglichkeit eines Fehlers in jedem Moment und an jeder "
+"Stelle"
+
+#, c-format
+msgid "write error of a big result on a too small disk%s%s"
+msgstr ""
+"Fehler beim Schreiben eines großen Ergebnisses auf eine zu kleine Platte%s"
+"%smit der jederzeitigen Möglichkeit eines Fehlers in jedem Moment und an "
+"jeder Stelle"
+EOF
+
+: ${DIFF=diff}
+${DIFF} mcat-test17.ok mcat-test17.out
+result=$?
+
+rm -fr $tmpfiles
+
+exit $result