Imported Upstream version 0.19.7
[platform/upstream/gettext.git] / gettext-tools / src / format-qt-plural.c
1 /* Qt plural format strings.
2    Copyright (C) 2003-2004, 2006-2007, 2009, 2015 Free Software
3    Foundation, Inc.
4    Written by Bruno Haible <bruno@clisp.org>, 2009.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdbool.h>
24 #include <stdlib.h>
25
26 #include "format.h"
27 #include "xalloc.h"
28 #include "gettext.h"
29
30 #define _(str) gettext (str)
31
32 /* Qt plural format strings are processed by QObject::tr and are documented in
33    qt-x11-opensource-src-4.3.1/doc/html/qobject.html#tr.
34    A directive
35      - starts with '%',
36      - is optionally followed by 'L' (a no-op),
37      - is followed by 'n'.
38    Every directive is replaced by the numeric argument N passed to QObject::tr.
39  */
40
41 struct spec
42 {
43   /* Number of format directives.  */
44   unsigned int directives;
45 };
46
47
48 static void *
49 format_parse (const char *format, bool translated, char *fdi,
50               char **invalid_reason)
51 {
52   const char *const format_start = format;
53   struct spec spec;
54   struct spec *result;
55
56   spec.directives = 0;
57
58   for (; *format != '\0';)
59     if (*format++ == '%')
60       {
61         const char *dir_start = format - 1;
62
63         if (*format == 'L')
64           format++;
65         if (*format == 'n')
66           {
67             /* A directive.  */
68             FDI_SET (dir_start, FMTDIR_START);
69             spec.directives++;
70             FDI_SET (format, FMTDIR_END);
71
72             format++;
73           }
74       }
75
76   result = XMALLOC (struct spec);
77   *result = spec;
78   return result;
79 }
80
81 static void
82 format_free (void *descr)
83 {
84   struct spec *spec = (struct spec *) descr;
85
86   free (spec);
87 }
88
89 static int
90 format_get_number_of_directives (void *descr)
91 {
92   struct spec *spec = (struct spec *) descr;
93
94   return spec->directives;
95 }
96
97 static bool
98 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
99               formatstring_error_logger_t error_logger,
100               const char *pretty_msgid, const char *pretty_msgstr)
101 {
102   struct spec *spec1 = (struct spec *) msgid_descr;
103   struct spec *spec2 = (struct spec *) msgstr_descr;
104   bool err = false;
105
106   /* Check the argument is used.  */
107   if ((spec1->directives == 0 && spec2->directives > 0)
108       || (equality && spec1->directives > 0 && spec2->directives == 0))
109     {
110       if (error_logger)
111         error_logger (_("number of format specifications in '%s' and '%s' does not match"),
112                       pretty_msgid, pretty_msgstr);
113       err = true;
114     }
115
116   return err;
117 }
118
119
120 struct formatstring_parser formatstring_qt_plural =
121 {
122   format_parse,
123   format_free,
124   format_get_number_of_directives,
125   NULL,
126   format_check
127 };
128
129
130 #ifdef TEST
131
132 /* Test program: Print the argument list specification returned by
133    format_parse for strings read from standard input.  */
134
135 #include <stdio.h>
136
137 static void
138 format_print (void *descr)
139 {
140   struct spec *spec = (struct spec *) descr;
141
142   if (spec == NULL)
143     {
144       printf ("INVALID");
145       return;
146     }
147
148   printf ("(");
149   if (spec->directives > 0)
150     printf ("*");
151   else
152     printf ("_");
153   printf (")");
154 }
155
156 int
157 main ()
158 {
159   for (;;)
160     {
161       char *line = NULL;
162       size_t line_size = 0;
163       int line_len;
164       char *invalid_reason;
165       void *descr;
166
167       line_len = getline (&line, &line_size, stdin);
168       if (line_len < 0)
169         break;
170       if (line_len > 0 && line[line_len - 1] == '\n')
171         line[--line_len] = '\0';
172
173       invalid_reason = NULL;
174       descr = format_parse (line, false, NULL, &invalid_reason);
175
176       format_print (descr);
177       printf ("\n");
178       if (descr == NULL)
179         printf ("%s\n", invalid_reason);
180
181       free (invalid_reason);
182       free (line);
183     }
184
185   return 0;
186 }
187
188 /*
189  * For Emacs M-x compile
190  * Local Variables:
191  * compile-command: "/bin/sh ../libtool --tag=CC --mode=link gcc -o a.out -static -O -g -Wall -I.. -I../gnulib-lib -I../intl -DHAVE_CONFIG_H -DTEST format-qt-plural.c ../gnulib-lib/libgettextlib.la"
192  * End:
193  */
194
195 #endif /* TEST */