• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/src/
1/* Format strings.
2   Copyright (C) 2001-2007 Free Software Foundation, Inc.
3   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
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/* Specification.  */
23#include "format.h"
24
25#include <stdbool.h>
26#include <stdio.h>
27#include <stdlib.h>
28
29#include "message.h"
30#include "gettext.h"
31
32#define _(str) gettext (str)
33
34/* Table of all format string parsers.  */
35struct formatstring_parser *formatstring_parsers[NFORMATS] =
36{
37  /* format_c */		&formatstring_c,
38  /* format_objc */		&formatstring_objc,
39  /* format_sh */		&formatstring_sh,
40  /* format_python */		&formatstring_python,
41  /* format_lisp */		&formatstring_lisp,
42  /* format_elisp */		&formatstring_elisp,
43  /* format_librep */		&formatstring_librep,
44  /* format_scheme */		&formatstring_scheme,
45  /* format_smalltalk */	&formatstring_smalltalk,
46  /* format_java */		&formatstring_java,
47  /* format_csharp */		&formatstring_csharp,
48  /* format_awk */		&formatstring_awk,
49  /* format_pascal */		&formatstring_pascal,
50  /* format_ycp */		&formatstring_ycp,
51  /* format_tcl */		&formatstring_tcl,
52  /* format_perl */		&formatstring_perl,
53  /* format_perl_brace */	&formatstring_perl_brace,
54  /* format_php */		&formatstring_php,
55  /* format_gcc_internal */	&formatstring_gcc_internal,
56  /* format_qt */		&formatstring_qt,
57  /* format_kde */		&formatstring_kde,
58  /* format_boost */		&formatstring_boost
59};
60
61/* Check whether both formats strings contain compatible format
62   specifications for format type i (0 <= i < NFORMATS).
63   PLURAL_DISTRIBUTION is either NULL or an array of nplurals elements,
64   PLURAL_DISTRIBUTION[j] being true if the value j appears to be assumed
65   infinitely often by the plural formula.
66   PLURAL_DISTRIBUTION_LENGTH is the length of the PLURAL_DISTRIBUTION array.
67   Return the number of errors that were seen.  */
68int
69check_msgid_msgstr_format_i (const char *msgid, const char *msgid_plural,
70			     const char *msgstr, size_t msgstr_len,
71			     size_t i,
72			     const unsigned char *plural_distribution,
73			     unsigned long plural_distribution_length,
74			     formatstring_error_logger_t error_logger)
75{
76  int seen_errors = 0;
77
78  /* At runtime, we can assume the program passes arguments that fit well for
79     msgid.  We must signal an error if msgstr wants more arguments that msgid
80     accepts.
81     If msgstr wants fewer arguments than msgid, it wouldn't lead to a crash
82     at runtime, but we nevertheless give an error because
83     1) this situation occurs typically after the programmer has added some
84        arguments to msgid, so we must make the translator specially aware
85        of it (more than just "fuzzy"),
86     2) it is generally wrong if a translation wants to ignore arguments that
87        are used by other translations.  */
88
89  struct formatstring_parser *parser = formatstring_parsers[i];
90  char *invalid_reason = NULL;
91  void *msgid_descr =
92    parser->parse (msgid_plural != NULL ? msgid_plural : msgid, false, NULL,
93		   &invalid_reason);
94
95  if (msgid_descr != NULL)
96    {
97      char buf[18+1];
98      const char *pretty_msgstr = "msgstr";
99      bool has_plural_translations = (strlen (msgstr) + 1 < msgstr_len);
100      const char *p_end = msgstr + msgstr_len;
101      const char *p;
102      unsigned int j;
103
104      for (p = msgstr, j = 0; p < p_end; p += strlen (p) + 1, j++)
105	{
106	  void *msgstr_descr;
107
108	  if (msgid_plural != NULL)
109	    {
110	      sprintf (buf, "msgstr[%u]", j);
111	      pretty_msgstr = buf;
112	    }
113
114	  msgstr_descr = parser->parse (p, true, NULL, &invalid_reason);
115
116	  if (msgstr_descr != NULL)
117	    {
118	      /* Use strict checking (require same number of format
119		 directives on both sides) if the message has no plurals,
120		 or if msgid_plural exists but on the msgstr[] side
121		 there is only msgstr[0], or if plural_distribution[j]
122		 indicates that the variant applies to infinitely many
123		 values of N.
124		 Use relaxed checking when there are at least two
125		 msgstr[] forms and the plural_distribution array does
126		 not give more precise information.  */
127	      bool strict_checking =
128		(msgid_plural == NULL
129		 || !has_plural_translations
130		 || (plural_distribution != NULL
131		     && j < plural_distribution_length
132		     && plural_distribution[j]));
133
134	      if (parser->check (msgid_descr, msgstr_descr,
135				 strict_checking,
136				 error_logger, pretty_msgstr))
137		seen_errors++;
138
139	      parser->free (msgstr_descr);
140	    }
141	  else
142	    {
143	      error_logger (_("\
144'%s' is not a valid %s format string, unlike 'msgid'. Reason: %s"),
145			    pretty_msgstr, format_language_pretty[i],
146			    invalid_reason);
147	      seen_errors++;
148	      free (invalid_reason);
149	    }
150	}
151
152      parser->free (msgid_descr);
153    }
154  else
155    free (invalid_reason);
156
157  return seen_errors;
158}
159
160/* Check whether both formats strings contain compatible format
161   specifications.
162   PLURAL_DISTRIBUTION is either NULL or an array of nplurals elements,
163   PLURAL_DISTRIBUTION[j] being true if the value j appears to be assumed
164   infinitely often by the plural formula.
165   PLURAL_DISTRIBUTION_LENGTH is the length of the PLURAL_DISTRIBUTION array.
166   Return the number of errors that were seen.  */
167int
168check_msgid_msgstr_format (const char *msgid, const char *msgid_plural,
169			   const char *msgstr, size_t msgstr_len,
170			   const enum is_format is_format[NFORMATS],
171			   const unsigned char *plural_distribution,
172			   unsigned long plural_distribution_length,
173			   formatstring_error_logger_t error_logger)
174{
175  int seen_errors = 0;
176  size_t i;
177
178  /* We check only those messages for which the msgid's is_format flag
179     is one of 'yes' or 'possible'.  We don't check msgids with is_format
180     'no' or 'impossible', to obey the programmer's order.  We don't check
181     msgids with is_format 'undecided' because that would introduce too
182     many checks, thus forcing the programmer to add "xgettext: no-c-format"
183     anywhere where a translator wishes to use a percent sign.  */
184  for (i = 0; i < NFORMATS; i++)
185    if (possible_format_p (is_format[i]))
186      seen_errors += check_msgid_msgstr_format_i (msgid, msgid_plural,
187						  msgstr, msgstr_len, i,
188						  plural_distribution,
189						  plural_distribution_length,
190						  error_logger);
191
192  return seen_errors;
193}
194