1 /* JavaScript format strings.
2 Copyright (C) 2001-2004, 2006-2009, 2013, 2015 Free Software
4 Written by Andreas Stricker <andy@knitter.ch>, 2010.
5 It's based on python format module from Bruno Haible.
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
31 #include "xvasprintf.h"
32 #include "format-invalid.h"
35 #define _(str) gettext (str)
37 /* Although JavaScript specification itself does not define any format
38 strings, many implementations provide printf-like functions.
39 We provide a permissive parser which accepts commonly used format
44 - is optionally followed by any of the characters '0', '-', ' ',
45 or, each of which acts as a flag,
46 - is optionally followed by a width specification: a nonempty digit
48 - is optionally followed by '.' and a precision specification: a nonempty
50 - is finished by a specifier
51 - 's', that needs a string argument,
52 - 'b', 'd', 'u', 'o', 'x', 'X', that need an integer argument,
53 - 'f', that need a floating-point argument,
54 - 'c', that needs a character argument.
55 - 'j', that needs an argument of any type.
56 Additionally there is the directive '%%', which takes no argument. */
70 unsigned int directives;
71 unsigned int format_args_count;
72 unsigned int allocated;
73 enum format_arg_type *format_args;
76 /* Locale independent test for a decimal digit.
77 Argument can be 'char' or 'unsigned char'. (Whereas the argument of
78 <ctype.h> isdigit must be an 'unsigned char'.) */
80 #define isdigit(c) ((unsigned int) ((c) - '0') < 10)
84 format_parse (const char *format, bool translated, char *fdi,
85 char **invalid_reason)
87 const char *const format_start = format;
92 spec.format_args_count = 0;
94 spec.format_args = NULL;
96 for (; *format != '\0';)
100 enum format_arg_type type;
102 FDI_SET (format - 1, FMTDIR_START);
105 while (*format == '-' || *format == '+' || *format == ' '
106 || *format == '0' || *format == 'I')
109 while (isdigit (*format))
116 while (isdigit (*format))
126 type = FAT_CHARACTER;
131 case 'b': case 'd': case 'o': case 'x': case 'X':
143 *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
144 FDI_SET (format - 1, FMTDIR_ERROR);
149 INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
150 FDI_SET (format, FMTDIR_ERROR);
157 if (spec.allocated == spec.format_args_count)
159 spec.allocated = 2 * spec.allocated + 1;
160 spec.format_args = (enum format_arg_type *) xrealloc (spec.format_args, spec.allocated * sizeof (enum format_arg_type));
162 spec.format_args[spec.format_args_count] = type;
163 spec.format_args_count++;
166 FDI_SET (format, FMTDIR_END);
171 result = XMALLOC (struct spec);
176 if (spec.format_args != NULL)
177 free (spec.format_args);
182 format_free (void *descr)
184 struct spec *spec = (struct spec *) descr;
186 if (spec->format_args != NULL)
187 free (spec->format_args);
192 format_get_number_of_directives (void *descr)
194 struct spec *spec = (struct spec *) descr;
196 return spec->directives;
200 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
201 formatstring_error_logger_t error_logger,
202 const char *pretty_msgid, const char *pretty_msgstr)
204 struct spec *spec1 = (struct spec *) msgid_descr;
205 struct spec *spec2 = (struct spec *) msgstr_descr;
208 if (spec1->format_args_count + spec2->format_args_count > 0)
212 /* Check the argument types are the same. */
213 if (spec1->format_args_count != spec2->format_args_count)
216 error_logger (_("number of format specifications in '%s' and '%s' does not match"),
217 pretty_msgid, pretty_msgstr);
221 for (i = 0; i < spec2->format_args_count; i++)
222 if (!(spec1->format_args[i] == spec2->format_args[i]
224 && (spec1->format_args[i] == FAT_ANY
225 || spec2->format_args[i] == FAT_ANY))))
228 error_logger (_("format specifications in '%s' and '%s' for argument %u are not the same"),
229 pretty_msgid, pretty_msgstr, i + 1);
238 struct formatstring_parser formatstring_javascript =
242 format_get_number_of_directives,
250 /* Test program: Print the argument list specification returned by
251 format_parse for strings read from standard input. */
256 format_print (void *descr)
258 struct spec *spec = (struct spec *) descr;
268 for (i = 0; i < spec->format_args_count; i++)
272 switch (spec->format_args[i])
302 size_t line_size = 0;
304 char *invalid_reason;
307 line_len = getline (&line, &line_size, stdin);
310 if (line_len > 0 && line[line_len - 1] == '\n')
311 line[--line_len] = '\0';
313 invalid_reason = NULL;
314 descr = format_parse (line, false, NULL, &invalid_reason);
316 format_print (descr);
319 printf ("%s\n", invalid_reason);
321 free (invalid_reason);
329 * For Emacs M-x compile
331 * 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"