• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/ap/gpl/timemachine/gettext-0.17/gettext-tools/src/
1/* Qt format strings.
2   Copyright (C) 2003-2004, 2006-2007 Free Software Foundation, Inc.
3   Written by Bruno Haible <bruno@clisp.org>, 2003.
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <stdbool.h>
23#include <stdlib.h>
24
25#include "format.h"
26#include "xalloc.h"
27#include "xvasprintf.h"
28#include "gettext.h"
29
30#define _(str) gettext (str)
31
32/* Qt format strings are processed by QString::arg and are documented in
33   qt-4.3.0/doc/html/qstring.html.
34   A directive
35     - starts with '%',
36     - is optionally followed by 'L' (indicates locale-dependent processing),
37     - is followed by one or two digits ('0' to '9'). %0n is equivalent to %n.
38   An unterminated directive ('%' or '%L' not followed by a digit or at the
39   end) is not an error.
40   The first .arg() invocation replaces the %n with the lowest numbered n,
41   the next .arg() invocation then replaces the %n with the second-lowest
42   numbered n, and so on.
43   This is inherently buggy because a '%' in the first replacement confuses
44   the second .arg() invocation.
45   To reduce this problem and introduce another one, there are also .arg()
46   methods that take up to 9 strings and perform the replacements in one swoop.
47   But this method works only on strings that contain no 'L' flags and only
48   single-digit argument designators.
49   Although %0 is supported, usually %1 denotes the first argument, %2 the
50   second argument etc.  */
51
52struct spec
53{
54  /* Number of format directives.  */
55  unsigned int directives;
56
57  /* True if the string supports the multi-argument .arg() methods, i.e. if it
58     contains no 'L' flags and only single-digit argument designators.  */
59  bool simple;
60
61  /* Booleans telling which %nn was seen.  */
62  unsigned int arg_count;
63  bool args_used[100];
64};
65
66
67static void *
68format_parse (const char *format, bool translated, char *fdi,
69	      char **invalid_reason)
70{
71  const char *const format_start = format;
72  struct spec spec;
73  struct spec *result;
74
75  spec.directives = 0;
76  spec.simple = true;
77  spec.arg_count = 0;
78
79  for (; *format != '\0';)
80    if (*format++ == '%')
81      {
82	const char *dir_start = format - 1;
83	bool locale_flag = false;
84
85	if (*format == 'L')
86	  {
87	    locale_flag = true;
88	    format++;
89	  }
90	if (*format >= '0' && *format <= '9')
91	  {
92	    /* A directive.  */
93	    unsigned int number;
94
95	    FDI_SET (dir_start, FMTDIR_START);
96	    spec.directives++;
97	    if (locale_flag)
98	      spec.simple = false;
99
100	    number = *format - '0';
101	    if (format[1] >= '0' && format[1] <= '9')
102	      {
103		number = 10 * number + (format[1] - '0');
104		spec.simple = false;
105		format++;
106	      }
107
108	    while (spec.arg_count <= number)
109	      spec.args_used[spec.arg_count++] = false;
110	    spec.args_used[number] = true;
111
112	    FDI_SET (format, FMTDIR_END);
113
114	    format++;
115	  }
116      }
117
118  result = XMALLOC (struct spec);
119  *result = spec;
120  return result;
121}
122
123static void
124format_free (void *descr)
125{
126  struct spec *spec = (struct spec *) descr;
127
128  free (spec);
129}
130
131static int
132format_get_number_of_directives (void *descr)
133{
134  struct spec *spec = (struct spec *) descr;
135
136  return spec->directives;
137}
138
139static bool
140format_check (void *msgid_descr, void *msgstr_descr, bool equality,
141	      formatstring_error_logger_t error_logger,
142	      const char *pretty_msgstr)
143{
144  struct spec *spec1 = (struct spec *) msgid_descr;
145  struct spec *spec2 = (struct spec *) msgstr_descr;
146  bool err = false;
147  unsigned int i;
148
149  if (spec1->simple && !spec2->simple)
150    {
151      if (error_logger)
152	error_logger (_("'msgid' is a simple format string, but '%s' is not: it contains an 'L' flag or a double-digit argument number"),
153		      pretty_msgstr);
154      err = true;
155    }
156
157  if (!err)
158    for (i = 0; i < spec1->arg_count || i < spec2->arg_count; i++)
159      {
160	bool arg_used1 = (i < spec1->arg_count && spec1->args_used[i]);
161	bool arg_used2 = (i < spec2->arg_count && spec2->args_used[i]);
162
163	/* The translator cannot omit a %n from the msgstr because that would
164	   yield a "Argument missing" warning at runtime.  */
165	if (arg_used1 != arg_used2)
166	  {
167	    if (error_logger)
168	      error_logger (arg_used1
169			    ? _("a format specification for argument %u doesn't exist in '%s'")
170			    : _("a format specification for argument %u, as in '%s', doesn't exist in 'msgid'"),
171			    i, pretty_msgstr);
172	    err = true;
173	    break;
174	  }
175      }
176
177  return err;
178}
179
180
181struct formatstring_parser formatstring_qt =
182{
183  format_parse,
184  format_free,
185  format_get_number_of_directives,
186  NULL,
187  format_check
188};
189
190
191#ifdef TEST
192
193/* Test program: Print the argument list specification returned by
194   format_parse for strings read from standard input.  */
195
196#include <stdio.h>
197
198static void
199format_print (void *descr)
200{
201  struct spec *spec = (struct spec *) descr;
202  unsigned int i;
203
204  if (spec == NULL)
205    {
206      printf ("INVALID");
207      return;
208    }
209
210  printf ("(");
211  for (i = 0; i < spec->arg_count; i++)
212    {
213      if (i > 0)
214	printf (" ");
215      if (spec->args_used[i])
216	printf ("*");
217      else
218	printf ("_");
219    }
220  printf (")");
221}
222
223int
224main ()
225{
226  for (;;)
227    {
228      char *line = NULL;
229      size_t line_size = 0;
230      int line_len;
231      char *invalid_reason;
232      void *descr;
233
234      line_len = getline (&line, &line_size, stdin);
235      if (line_len < 0)
236	break;
237      if (line_len > 0 && line[line_len - 1] == '\n')
238	line[--line_len] = '\0';
239
240      invalid_reason = NULL;
241      descr = format_parse (line, false, NULL, &invalid_reason);
242
243      format_print (descr);
244      printf ("\n");
245      if (descr == NULL)
246	printf ("%s\n", invalid_reason);
247
248      free (invalid_reason);
249      free (line);
250    }
251
252  return 0;
253}
254
255/*
256 * For Emacs M-x compile
257 * Local Variables:
258 * 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.c ../gnulib-lib/libgettextlib.la"
259 * End:
260 */
261
262#endif /* TEST */
263