From: Bruno Haible Date: Sat, 20 Oct 2001 12:59:54 +0000 (+0000) Subject: Add support for Object Pascal format strings. X-Git-Tag: v0.11~448 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb40f35ce9d16dcc798efc84688c324735cb38de;p=thirdparty%2Fgettext.git Add support for Object Pascal format strings. --- diff --git a/src/ChangeLog b/src/ChangeLog index 9b6f680d4..871082c9d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,13 @@ +2001-09-20 Bruno Haible + + * format-pascal.c: New file. + * format.h (formatstring_pascal): New declaration. + * message.h (enum format_type): Add format_pascal. + * message.c (format_language): Add format_pascal entry. + (format_language_pretty): Likewise. + * format.c (formatstring_parsers): Add formatstring_pascal. + * Makefile.am (FORMAT_SOURCES): Add format-pascal.c. + 2001-09-16 Bruno Haible * x-ycp.h: New file. diff --git a/src/Makefile.am b/src/Makefile.am index b93a77917..73846cd51 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,7 +59,8 @@ open-po.c dir-list.c str-list.c # xgettext and msgfmt deal with format strings. FORMAT_SOURCES = format.c \ -format-c.c format-java.c format-lisp.c format-python.c format-ycp.c +format-c.c format-java.c format-lisp.c format-python.c format-pascal.c \ +format-ycp.c # Source dependencies. gettext_SOURCES = gettext.c diff --git a/src/format-pascal.c b/src/format-pascal.c new file mode 100644 index 000000000..b7ece5768 --- /dev/null +++ b/src/format-pascal.c @@ -0,0 +1,530 @@ +/* Object Pascal format strings. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 2001. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "format.h" +#include "c-ctype.h" +#include "xmalloc.h" +#include "system.h" +#include "error.h" +#include "progname.h" +#include "libgettext.h" + +#define _(str) gettext (str) + +/* Object Pascal format strings are usable with the "format" function in the + "sysutils" unit. They are implemented in fpc-1.0.4/rtl/objpas/sysstr.inc. + Another implementation exists in Borland Delphi. The GNU Pascal's + "sysutils" doesn't (yet?) have the "format" function. + + A directive + - starts with '%', + - either + - is finished with '%', or + - - is optionally followed by an index specification: '*' (reads an + argument, must be of type integer) or a nonempty digit sequence, + followed by ':', + - is optionally followed by '-', which acts as a flag, + - is optionally followed by a width specification: '*' (reads an + argument, must be of type integer) or a nonempty digit sequence, + - is optionally followed by '.' and a precision specification: '*' + (reads an argument, must be of type integer) or a nonempty digit + sequence, + - is finished by a case-insensitive specifier. If no index was + specified, it reads an argument; otherwise is uses the index-th + argument, 0-based. + - 'd', needs an 'integer' or 'int64' argument, + - 'e', 'f', 'g', 'n', 'm', need an 'extended' floating-point argument, + - 's', needs a 'string', 'char', 'pchar' or 'ansistring' argument, + - 'p', needs a 'pointer' argument, + - 'x', needs an integer argument. + Numbered and unnumbered argument specifications can be used in the same + string. Numbered argument specifications have no influence on the + "current argument index", that is incremented each time an argument is read. + */ + +enum format_arg_type +{ + FAT_INTEGER, /* integer */ + FAT_INTEGER64, /* integer, int64 */ + FAT_FLOAT, /* extended */ + FAT_STRING, /* string, char, pchar, ansistring */ + FAT_POINTER +}; + +struct numbered_arg +{ + unsigned int number; + enum format_arg_type type; +}; + +struct spec +{ + unsigned int directives; + unsigned int numbered_arg_count; + unsigned int allocated; + struct numbered_arg *numbered; +}; + +/* Locale independent test for a decimal digit. + Argument can be 'char' or 'unsigned char'. (Whereas the argument of + isdigit must be an 'unsigned char'.) */ +#undef isdigit +#define isdigit(c) ((unsigned int) ((c) - '0') < 10) + + +/* Prototypes for local functions. Needed to ensure compiler checking of + function argument counts despite of K&R C function definition syntax. */ +static int numbered_arg_compare PARAMS ((const void *p1, const void *p2)); +static void *format_parse PARAMS ((const char *format)); +static void format_free PARAMS ((void *descr)); +static int format_get_number_of_directives PARAMS ((void *descr)); +static bool format_check PARAMS ((const lex_pos_ty *pos, + void *msgid_descr, void *msgstr_descr)); + + +static int +numbered_arg_compare (p1, p2) + const void *p1; + const void *p2; +{ + unsigned int n1 = ((const struct numbered_arg *) p1)->number; + unsigned int n2 = ((const struct numbered_arg *) p2)->number; + + return (n1 > n2 ? 1 : n1 < n2 ? -1 : 0); +} + +static void * +format_parse (format) + const char *format; +{ + unsigned int directives; + unsigned int numbered_arg_count; + unsigned int allocated; + struct numbered_arg *numbered; + unsigned int unnumbered_arg_count; + struct spec *result; + + enum arg_index + { + index_numbered, /* index given by a fixed integer */ + index_unnumbered, /* index given by unnumbered_arg_count++ */ + index_unknown /* index is only known at run time */ + }; + + directives = 0; + numbered_arg_count = 0; + allocated = 0; + numbered = NULL; + unnumbered_arg_count = 0; + + for (; *format != '\0';) + if (*format++ == '%') + { + /* A directive. */ + directives++; + + if (*format != '%') + { + /* A complex directive. */ + enum arg_index main_arg = index_unnumbered; + unsigned int main_number = 0; + enum format_arg_type type; + + if (isdigit (*format)) + { + const char *f = format; + unsigned int m = 0; + + do + { + m = 10 * m + (*f - '0'); + f++; + } + while (isdigit (*f)); + + if (*f == ':') + { + main_number = m; + main_arg = index_numbered; + format = ++f; + } + } + else if (*format == '*') + { + if (format[1] == ':') + { + main_arg = index_unknown; + format += 2; + } + } + + /* Parse flags. */ + if (*format == '-') + format++; + + /* Parse width. */ + if (isdigit (*format)) + { + do + format++; + while (isdigit (*format)); + } + else if (*format == '*') + { + /* Unnumbered argument of type FAT_INTEGER. */ + if (allocated == numbered_arg_count) + { + allocated = 2 * allocated + 1; + numbered = (struct numbered_arg *) xrealloc (numbered, allocated * sizeof (struct numbered_arg)); + } + numbered[numbered_arg_count].number = unnumbered_arg_count; + numbered[numbered_arg_count].type = FAT_INTEGER; + numbered_arg_count++; + unnumbered_arg_count++; + + format++; + } + + /* Parse precision. */ + if (*format == '.') + { + format++; + + if (isdigit (*format)) + { + do + format++; + while (isdigit (*format)); + } + else if (*format == '*') + { + /* Unnumbered argument of type FAT_INTEGER. */ + if (allocated == unnumbered_arg_count) + { + allocated = 2 * allocated + 1; + numbered = (struct numbered_arg *) xrealloc (numbered, allocated * sizeof (struct numbered_arg)); + } + numbered[numbered_arg_count].number = unnumbered_arg_count; + numbered[numbered_arg_count].type = FAT_INTEGER; + numbered_arg_count++; + unnumbered_arg_count++; + + format++; + } + else + --format; /* will jump to bad_format */ + } + + switch (c_tolower (*format)) + { + case 'd': + type = FAT_INTEGER64; + break; + case 'e': case 'f': case 'g': case 'n': case 'm': + type = FAT_FLOAT; + break; + case 's': + type = FAT_STRING; + break; + case 'p': + type = FAT_POINTER; + break; + case 'x': + type = FAT_INTEGER; + break; + default: + goto bad_format; + } + + if (allocated == numbered_arg_count) + { + allocated = 2 * allocated + 1; + numbered = (struct numbered_arg *) xrealloc (numbered, allocated * sizeof (struct numbered_arg)); + } + switch (main_arg) + { + case index_unnumbered: + numbered[numbered_arg_count].number = unnumbered_arg_count; + numbered[numbered_arg_count].type = type; + unnumbered_arg_count++; + break; + case index_numbered: + numbered[numbered_arg_count].number = main_number; + numbered[numbered_arg_count].type = type; + break; + case index_unknown: + numbered[numbered_arg_count].number = unnumbered_arg_count; + numbered[numbered_arg_count].type = FAT_INTEGER; + unnumbered_arg_count++; + break; + default: + abort (); + } + numbered_arg_count++; + } + + format++; + } + + /* Sort the numbered argument array, and eliminate duplicates. */ + if (numbered_arg_count > 1) + { + unsigned int i, j; + bool err; + + qsort (numbered, numbered_arg_count, + sizeof (struct numbered_arg), numbered_arg_compare); + + /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i. */ + err = false; + for (i = j = 0; i < numbered_arg_count; i++) + if (j > 0 && numbered[i].number == numbered[j-1].number) + { + enum format_arg_type type1 = numbered[i].type; + enum format_arg_type type2 = numbered[j-1].type; + enum format_arg_type type_both; + + if (type1 == type2) + type_both = type1; + else if ((type1 == FAT_INTEGER && type2 == FAT_INTEGER64) + || (type1 == FAT_INTEGER64 && type2 == FAT_INTEGER)) + type_both = FAT_INTEGER; + else + /* Incompatible types. */ + type_both = type1, err = true; + + numbered[j-1].type = type_both; + } + else + { + if (j < i) + { + numbered[j].number = numbered[i].number; + numbered[j].type = numbered[i].type; + } + j++; + } + numbered_arg_count = j; + if (err) + goto bad_format; + } + + result = (struct spec *) xmalloc (sizeof (struct spec)); + result->directives = directives; + result->numbered_arg_count = numbered_arg_count; + result->allocated = allocated; + result->numbered = numbered; + return result; + + bad_format: + if (numbered != NULL) + free (numbered); + return NULL; +} + +static void +format_free (descr) + void *descr; +{ + struct spec *spec = (struct spec *) descr; + + if (spec->numbered != NULL) + free (spec->numbered); + free (spec); +} + +static int +format_get_number_of_directives (descr) + void *descr; +{ + struct spec *spec = (struct spec *) descr; + + return spec->directives; +} + +static bool +format_check (pos, msgid_descr, msgstr_descr) + const lex_pos_ty *pos; + void *msgid_descr; + void *msgstr_descr; +{ + struct spec *spec1 = (struct spec *) msgid_descr; + struct spec *spec2 = (struct spec *) msgstr_descr; + bool err = false; + + if (spec1->numbered_arg_count + spec2->numbered_arg_count > 0) + { + unsigned int i; + unsigned int n = MAX (spec1->numbered_arg_count, spec2->numbered_arg_count); + + /* Check the argument names are the same. + Both arrays are sorted. We search for the first difference. */ + for (i = 0; i < n; i++) + { + int cmp = (i >= spec1->numbered_arg_count ? 1 : + i >= spec2->numbered_arg_count ? -1 : + spec1->numbered[i].number > spec2->numbered[i].number ? 1 : + spec1->numbered[i].number < spec2->numbered[i].number ? -1 : + 0); + + if (cmp > 0) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("a format specification for argument {%u} doesn't exist in 'msgid'"), + spec2->numbered[i].number); + error_with_progname = true; + err = true; + break; + } + else if (cmp < 0) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("a format specification for argument {%u} doesn't exist in 'msgstr'"), + spec1->numbered[i].number); + error_with_progname = true; + err = true; + break; + } + } + /* Check the argument types are the same. */ + if (!err) + for (i = 0; i < spec2->numbered_arg_count; i++) + if (spec1->numbered[i].type != spec2->numbered[i].type) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("format specifications in 'msgid' and 'msgstr' for argument {%u} are not the same"), + spec2->numbered[i].number); + error_with_progname = true; + err = true; + break; + } + } + + return err; +} + + +struct formatstring_parser formatstring_pascal = +{ + format_parse, + format_free, + format_get_number_of_directives, + format_check +}; + + +#ifdef TEST + +/* Test program: Print the argument list specification returned by + format_parse for strings read from standard input. */ + +#include +#include "getline.h" + +static void +format_print (descr) + void *descr; +{ + struct spec *spec = (struct spec *) descr; + unsigned int last; + unsigned int i; + + if (spec == NULL) + { + printf ("INVALID"); + return; + } + + printf ("("); + last = 0; + for (i = 0; i < spec->numbered_arg_count; i++) + { + unsigned int number = spec->numbered[i].number; + + if (i > 0) + printf (" "); + if (number < last) + abort (); + for (; last < number; last++) + printf ("_ "); + switch (spec->numbered[i].type) + { + case FAT_INTEGER: + printf ("i"); + break; + case FAT_INTEGER64: + printf ("I"); + break; + case FAT_FLOAT: + printf ("f"); + break; + case FAT_STRING: + printf ("s"); + break; + case FAT_POINTER: + printf ("p"); + break; + default: + abort (); + } + last = number + 1; + } + printf (")"); +} + +int +main () +{ + for (;;) + { + char *line = NULL; + size_t line_len = 0; + void *descr; + + if (getline (&line, &line_len, stdin) < 0) + break; + + descr = format_parse (line); + + format_print (descr); + printf ("\n"); + + free (line); + } + + return 0; +} + +/* + * For Emacs M-x compile + * Local Variables: + * compile-command: "gcc -O -g -Wall -I.. -I../lib -I../intl -DHAVE_CONFIG_H -DTEST format-pascal.c ../lib/libnlsut.a" + * End: + */ + +#endif /* TEST */ diff --git a/src/format.c b/src/format.c index 38419d960..30b54f8c2 100644 --- a/src/format.c +++ b/src/format.c @@ -30,5 +30,6 @@ struct formatstring_parser *formatstring_parsers[NFORMATS] = /* format_python */ &formatstring_python, /* format_lisp */ &formatstring_lisp, /* format_java */ &formatstring_java, + /* format_pascal */ &formatstring_pascal, /* format_ycp */ &formatstring_ycp }; diff --git a/src/format.h b/src/format.h index 5c6424eff..9b013976f 100644 --- a/src/format.h +++ b/src/format.h @@ -53,6 +53,7 @@ extern struct formatstring_parser formatstring_c; extern struct formatstring_parser formatstring_python; extern struct formatstring_parser formatstring_lisp; extern struct formatstring_parser formatstring_java; +extern struct formatstring_parser formatstring_pascal; extern struct formatstring_parser formatstring_ycp; /* Table of all format string parsers. */ diff --git a/src/message.c b/src/message.c index 1a3cf466c..e9fe122d8 100644 --- a/src/message.c +++ b/src/message.c @@ -45,6 +45,7 @@ const char *const format_language[NFORMATS] = /* format_python */ "python", /* format_lisp */ "lisp", /* format_java */ "java", + /* format_pascal */ "object-pascal", /* format_ycp */ "ycp" }; @@ -54,6 +55,7 @@ const char *const format_language_pretty[NFORMATS] = /* format_python */ "Python", /* format_lisp */ "Lisp", /* format_java */ "Java", + /* format_pascal */ "Object Pascal", /* format_ycp */ "YCP" }; diff --git a/src/message.h b/src/message.h index faa0154a3..9a63bc344 100644 --- a/src/message.h +++ b/src/message.h @@ -37,6 +37,7 @@ enum format_type format_python, format_lisp, format_java, + format_pascal, format_ycp, NFORMATS }; diff --git a/tests/ChangeLog b/tests/ChangeLog index 8e488d5fa..66049c19d 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2001-09-20 Bruno Haible + + * format-pascal-1: New file. + * format-pascal-2: New file. + * Makefile.am (TESTS): Add them. + 2001-09-16 Bruno Haible * format-ycp-1: Use real YCP syntax. diff --git a/tests/Makefile.am b/tests/Makefile.am index ca0ac72a4..c261cf600 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -38,6 +38,7 @@ TESTS = gettext-1 gettext-2 \ format-java-1 format-java-2 \ format-lisp-1 format-lisp-2 \ format-python-1 format-python-2 \ + format-pascal-1 format-pascal-2 \ format-ycp-1 format-ycp-2 \ plural-1 plural-2 diff --git a/tests/format-pascal-1 b/tests/format-pascal-1 new file mode 100755 index 000000000..6dad327fa --- /dev/null +++ b/tests/format-pascal-1 @@ -0,0 +1,126 @@ +#! /bin/sh + +# Test recognition of Object Pascal format strings. + +tmpfiles="" +trap 'rm -fr $tmpfiles' 1 2 3 15 + +tmpfiles="$tmpfiles f-op-1.data" +cat <<\EOF > f-op-1.data +# Valid: no argument +"abc%%" +# Valid: one string argument +"abc%s" +# Valid: one integer argument +"abc%d" +# Valid: one integer argument +"abc%X" +# Valid: one floating-point argument +"abc%e" +# Valid: one floating-point argument +"abc%f" +# Valid: one floating-point argument +"abc%g" +# Valid: one floating-point argument +"abc%n" +# Valid: one floating-point argument +"abc%m" +# Valid: one pointer argument +"abc%p" +# Valid: one argument with flags +"abc%-g" +# Valid: one argument with width +"abc%2g" +# Valid: one argument with width +"abc%*g" +# Valid: one argument with precision +"abc%.4g" +# Valid: one argument with precision +"abc%.*g" +# Valid: one argument with width and precision +"abc%14.4g" +# Valid: one argument with width and precision +"abc%14.*g" +# Valid: one argument with width and precision +"abc%*.4g" +# Valid: one argument with width and precision +"abc%*.*g" +# Invalid: unterminated +"abc%" +# Invalid: unknown format specifier +"abc%y" +# Invalid: flags after width +"abc%*-g" +# Invalid: twice precision +"abc%.4.2g" +# Valid: three arguments +"abc%d%x%x" +# Valid: a numbered argument +"abc%0:d" +# Valid: two-digit numbered arguments +"abc%10:def%9:dgh%8:dij%7:dkl%6:dmn%5:dop%4:dqr%3:dst%2:duv%1:dwx%0:dyz" +# Invalid: unterminated number +"abc%1" +# Invalid: flags before number +"abc%-0:d" +# Valid: three arguments, two with same number +"abc%0:4e,%1:p,%0:g" +# Invalid: argument with conflicting types +"abc%0:4x,%1:p,%0:s" +# Invalid: argument with conflicting types +"abc%0:4e,%1:p,%0:d" +# Valid: argument with different but not conflicting types +"abc%0:4x,%1:p,%0:d" +# Valid: mixing of numbered and unnumbered arguments +"abc%d%1:x" +# Valid: numbered argument with constant precision +"abc%0:.9x" +# Valid: mixing of numbered and unnumbered arguments +"abc%3:.*x" +# Valid: missing non-final argument +"abc%1:x%3:s" +# Valid: permutation +"abc%1:ddef%0:d" +# Valid: multiple uses of same argument +"abc%2:xdef%1:pghi%2:x" +# Valid: one argument with width +"abc%1:*g" +# Valid: one argument with width and precision +"abc%2:*.*g" +EOF + +: ${XGETTEXT=xgettext} +n=0 +while read comment; do + read string + n=`expr $n + 1` + tmpfiles="$tmpfiles f-op-1-$n.in f-op-1-$n.po" + echo "x.y=${string}" | sed -e "s/\"/'/g" > f-op-1-$n.in + ${XGETTEXT} -L RST -o f-op-1-$n.po f-op-1-$n.in || exit 1 + test -f f-op-1-$n.po || exit 1 + fail= + if echo "$comment" | grep 'Valid:' > /dev/null; then + if grep object-pascal-format f-op-1-$n.po > /dev/null; then + : + else + fail=yes + fi + else + if grep object-pascal-format f-op-1-$n.po > /dev/null; then + fail=yes + else + : + fi + fi + if test -n "$fail"; then + echo "Format string recognition error:" 1>&2 + cat f-op-1-$n.in 1>&2 + echo "Got:" 1>&2 + cat f-op-1-$n.po 1>&2 + exit 1 + fi +done < f-op-1.data + +rm -fr $tmpfiles + +exit 0 diff --git a/tests/format-pascal-2 b/tests/format-pascal-2 new file mode 100755 index 000000000..c03491d00 --- /dev/null +++ b/tests/format-pascal-2 @@ -0,0 +1,132 @@ +#! /bin/sh + +# Test checking of Object Pascal format strings. + +tmpfiles="" +trap 'rm -fr $tmpfiles' 1 2 3 15 + +tmpfiles="$tmpfiles f-op-2.data" +cat <<\EOF > f-op-2.data +# Valid: %% doesn't count +msgid "abc%%def" +msgstr "xyz" +# Invalid: invalid msgstr +msgid "abc%%def" +msgstr "xyz%" +# Valid: same arguments +msgid "abc%s%gdef" +msgstr "xyz%s%g" +# Valid: same arguments, with different widths +msgid "abc%2sdef" +msgstr "xyz%3s" +# Valid: same arguments but in numbered syntax +msgid "abc%s%gdef" +msgstr "xyz%0:s%1:g" +# Valid: permutation +msgid "abc%s%g%cdef" +msgstr "xyz%2:c%1:g%0:s" +# Invalid: too few arguments +msgid "abc%1:xdef%0:s" +msgstr "xyz%0:s" +# Invalid: too few arguments +msgid "abc%sdef%x" +msgstr "xyz%s" +# Invalid: too many arguments +msgid "abc%xdef" +msgstr "xyz%xvw%p" +# Valid: same numbered arguments, with different widths +msgid "abc%1:5s%0:4s" +msgstr "xyz%1:4s%0:5s" +# Invalid: missing argument +msgid "abc%1:sdef%0:x" +msgstr "xyz%0:x" +# Invalid: missing argument +msgid "abc%0:sdef%1:x" +msgstr "xyz%1:x" +# Invalid: added argument +msgid "abc%0:xdef" +msgstr "xyz%0:xvw%1:p" +# Valid: type compatibility +msgid "abc%e" +msgstr "xyz%f" +# Valid: type compatibility +msgid "abc%e" +msgstr "xyz%g" +# Valid: type compatibility +msgid "abc%e" +msgstr "xyz%n" +# Valid: type compatibility +msgid "abc%e" +msgstr "xyz%m" +# Invalid: type incompatibility +msgid "abc%d" +msgstr "xyz%e" +# Invalid: type incompatibility +msgid "abc%d" +msgstr "xyz%s" +# Invalid: type incompatibility +msgid "abc%d" +msgstr "xyz%p" +# Invalid: type incompatibility +msgid "abc%d" +msgstr "xyz%x" +# Invalid: type incompatibility +msgid "abc%e" +msgstr "xyz%s" +# Invalid: type incompatibility +msgid "abc%e" +msgstr "xyz%p" +# Invalid: type incompatibility +msgid "abc%e" +msgstr "xyz%x" +# Invalid: type incompatibility +msgid "abc%s" +msgstr "xyz%p" +# Invalid: type incompatibility +msgid "abc%s" +msgstr "xyz%x" +# Invalid: type incompatibility +msgid "abc%p" +msgstr "xyz%x" +# Invalid: type incompatibility for width +msgid "abc%g%*g" +msgstr "xyz%*g%g" +EOF + +: ${MSGFMT=msgfmt} +n=0 +while read comment; do + read msgid_line + read msgstr_line + n=`expr $n + 1` + tmpfiles="$tmpfiles f-op-2-$n.po f-op-2-$n.mo" + cat < f-op-2-$n.po +#, object-pascal-format +${msgid_line} +${msgstr_line} +EOF + fail= + if echo "$comment" | grep 'Valid:' > /dev/null; then + if ${MSGFMT} --check-format -o f-op-2-$n.mo f-op-2-$n.po; then + : + else + fail=yes + fi + else + ${MSGFMT} --check-format -o f-op-2-$n.mo f-op-2-$n.po 2> /dev/null + if test $? = 1; then + : + else + fail=yes + fi + fi + if test -n "$fail"; then + echo "Format string checking error:" 1>&2 + cat f-op-2-$n.po 1>&2 + exit 1 + fi +done < f-op-2.data + +rm -fr $tmpfiles + +exit 0