2 Copyright (C) 2003-2004, 2006-2007, 2009 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
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.
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.
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/>. */
28 #include "xvasprintf.h"
31 #define _(str) gettext (str)
33 /* C# format strings are described in the description of the .NET System.String
34 class and implemented in
35 pnetlib-0.5.6/runtime/System/String.cs
37 mcs-0.28/class/corlib/System/String.cs
38 A format string consists of literal text (that is output verbatim), doubled
39 braces ('{{' and '}}', that lead to a single brace when output), and
43 - is followed by a nonnegative integer m,
44 - is optionally followed by ',' and an integer denoting a width,
45 - is optionally followed by ':' and a sequence of format specifiers.
46 (But the interpretation of the format specifiers is up to the IFormattable
47 implementation, depending on the argument's runtime value. New classes
48 implementing IFormattable can be defined by the user.)
49 - is finished with '}'.
54 unsigned int directives;
55 unsigned int numbered_arg_count;
59 format_parse (const char *format, bool translated, char *fdi,
60 char **invalid_reason)
62 const char *const format_start = format;
67 spec.numbered_arg_count = 0;
69 for (; *format != '\0';)
75 FDI_SET (format - 1, FMTDIR_START);
85 if (!c_isdigit (*format))
88 xasprintf (_("In the directive number %u, '{' is not followed by an argument number."), spec.directives);
89 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
95 number = 10 * number + (*format - '0');
98 while (c_isdigit (*format));
106 if (!c_isdigit (*format))
109 xasprintf (_("In the directive number %u, ',' is not followed by a number."), spec.directives);
110 FDI_SET (*format == '\0' ? format - 1 : format,
116 while (c_isdigit (*format));
121 /* Parse format specifiers. */
124 while (*format != '\0' && *format != '}');
130 xstrdup (_("The string ends in the middle of a directive: found '{' without matching '}'."));
131 FDI_SET (format - 1, FMTDIR_ERROR);
139 ? xasprintf (_("The directive number %u ends with an invalid character '%c' instead of '}'."), spec.directives, *format)
140 : xasprintf (_("The directive number %u ends with an invalid character instead of '}'."), spec.directives));
141 FDI_SET (format, FMTDIR_ERROR);
147 if (spec.numbered_arg_count <= number)
148 spec.numbered_arg_count = number + 1;
150 FDI_SET (format - 1, FMTDIR_END);
154 FDI_SET (format - 1, FMTDIR_START);
160 (spec.directives == 0
161 ? xstrdup (_("The string starts in the middle of a directive: found '}' without matching '{'."))
162 : xasprintf (_("The string contains a lone '}' after directive number %u."), spec.directives));
163 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
166 FDI_SET (format - 1, FMTDIR_END);
170 result = XMALLOC (struct spec);
176 format_free (void *descr)
178 struct spec *spec = (struct spec *) descr;
184 format_get_number_of_directives (void *descr)
186 struct spec *spec = (struct spec *) descr;
188 return spec->directives;
192 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
193 formatstring_error_logger_t error_logger,
194 const char *pretty_msgid, const char *pretty_msgstr)
196 struct spec *spec1 = (struct spec *) msgid_descr;
197 struct spec *spec2 = (struct spec *) msgstr_descr;
200 /* Check that the argument counts are the same. */
202 ? spec1->numbered_arg_count != spec2->numbered_arg_count
203 : spec1->numbered_arg_count < spec2->numbered_arg_count)
206 error_logger (_("number of format specifications in '%s' and '%s' does not match"),
207 pretty_msgid, pretty_msgstr);
215 struct formatstring_parser formatstring_csharp =
219 format_get_number_of_directives,
227 /* Test program: Print the argument list specification returned by
228 format_parse for strings read from standard input. */
233 format_print (void *descr)
235 struct spec *spec = (struct spec *) descr;
245 for (i = 0; i < spec->numbered_arg_count; i++)
260 size_t line_size = 0;
262 char *invalid_reason;
265 line_len = getline (&line, &line_size, stdin);
268 if (line_len > 0 && line[line_len - 1] == '\n')
269 line[--line_len] = '\0';
271 invalid_reason = NULL;
272 descr = format_parse (line, false, NULL, &invalid_reason);
274 format_print (descr);
277 printf ("%s\n", invalid_reason);
279 free (invalid_reason);
287 * For Emacs M-x compile
289 * 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-csharp.c ../gnulib-lib/libgettextlib.la"