1 /* JavaScript format strings.
2 Copyright (C) 2001-2004, 2006-2009, 2013 Free Software Foundation, Inc.
3 Written by Andreas Stricker <andy@knitter.ch>, 2010.
4 It's based on python format module from Bruno Haible.
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.
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.
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/>. */
30 #include "xvasprintf.h"
31 #include "format-invalid.h"
34 #define _(str) gettext (str)
36 /* Although JavaScript specification itself does not define any format
37 strings, many implementations provide printf-like functions.
38 We provide a permissive parser which accepts commonly used format
43 - is optionally followed by any of the characters '0', '-', ' ',
44 or, each of which acts as a flag,
45 - is optionally followed by a width specification: a nonempty digit
47 - is optionally followed by '.' and a precision specification: a nonempty
49 - is finished by a specifier
50 - 's', that needs a string argument,
51 - 'b', 'd', 'u', 'o', 'x', 'X', that need an integer argument,
52 - 'f', that need a floating-point argument,
53 - 'c', that needs a character argument.
54 - 'j', that needs an argument of any type.
55 Additionally there is the directive '%%', which takes no argument. */
69 unsigned int directives;
70 unsigned int format_args_count;
71 unsigned int allocated;
72 enum format_arg_type *format_args;
75 /* Locale independent test for a decimal digit.
76 Argument can be 'char' or 'unsigned char'. (Whereas the argument of
77 <ctype.h> isdigit must be an 'unsigned char'.) */
79 #define isdigit(c) ((unsigned int) ((c) - '0') < 10)
83 format_parse (const char *format, bool translated, char *fdi,
84 char **invalid_reason)
86 const char *const format_start = format;
91 spec.format_args_count = 0;
93 spec.format_args = NULL;
95 for (; *format != '\0';)
99 enum format_arg_type type;
101 FDI_SET (format - 1, FMTDIR_START);
104 while (*format == '-' || *format == '+' || *format == ' '
105 || *format == '0' || *format == 'I')
108 while (isdigit (*format))
115 while (isdigit (*format))
125 type = FAT_CHARACTER;
130 case 'b': case 'd': case 'o': case 'x': case 'X':
142 *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
143 FDI_SET (format - 1, FMTDIR_ERROR);
148 INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
149 FDI_SET (format, FMTDIR_ERROR);
156 if (spec.allocated == spec.format_args_count)
158 spec.allocated = 2 * spec.allocated + 1;
159 spec.format_args = (enum format_arg_type *) xrealloc (spec.format_args, spec.allocated * sizeof (enum format_arg_type));
161 spec.format_args[spec.format_args_count] = type;
162 spec.format_args_count++;
165 FDI_SET (format, FMTDIR_END);
170 result = XMALLOC (struct spec);
175 if (spec.format_args != NULL)
176 free (spec.format_args);
181 format_free (void *descr)
183 struct spec *spec = (struct spec *) descr;
185 if (spec->format_args != NULL)
186 free (spec->format_args);
191 format_get_number_of_directives (void *descr)
193 struct spec *spec = (struct spec *) descr;
195 return spec->directives;
199 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
200 formatstring_error_logger_t error_logger,
201 const char *pretty_msgid, const char *pretty_msgstr)
203 struct spec *spec1 = (struct spec *) msgid_descr;
204 struct spec *spec2 = (struct spec *) msgstr_descr;
207 if (spec1->format_args_count + spec2->format_args_count > 0)
211 /* Check the argument types are the same. */
212 if (spec1->format_args_count != spec2->format_args_count)
215 error_logger (_("number of format specifications in '%s' and '%s' does not match"),
216 pretty_msgid, pretty_msgstr);
220 for (i = 0; i < spec2->format_args_count; i++)
221 if (!(spec1->format_args[i] == spec2->format_args[i]
223 && (spec1->format_args[i] == FAT_ANY
224 || spec2->format_args[i] == FAT_ANY))))
227 error_logger (_("format specifications in '%s' and '%s' for argument %u are not the same"),
228 pretty_msgid, pretty_msgstr, i + 1);
237 struct formatstring_parser formatstring_javascript =
241 format_get_number_of_directives,
249 /* Test program: Print the argument list specification returned by
250 format_parse for strings read from standard input. */
255 format_print (void *descr)
257 struct spec *spec = (struct spec *) descr;
267 for (i = 0; i < spec->format_args_count; i++)
271 switch (spec->format_args[i])
301 size_t line_size = 0;
303 char *invalid_reason;
306 line_len = getline (&line, &line_size, stdin);
309 if (line_len > 0 && line[line_len - 1] == '\n')
310 line[--line_len] = '\0';
312 invalid_reason = NULL;
313 descr = format_parse (line, false, NULL, &invalid_reason);
315 format_print (descr);
318 printf ("%s\n", invalid_reason);
320 free (invalid_reason);
328 * For Emacs M-x compile
330 * 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-javascript.c ../gnulib-lib/libgettextlib.la"