2 Copyright (C) 2003-2004, 2006-2007, 2009, 2015 Free Software
4 Written by Bruno Haible <bruno@clisp.org>, 2003.
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/>. */
29 #include "xvasprintf.h"
32 #define _(str) gettext (str)
34 /* C# format strings are described in the description of the .NET System.String
35 class and implemented in
36 pnetlib-0.5.6/runtime/System/String.cs
38 mcs-0.28/class/corlib/System/String.cs
39 A format string consists of literal text (that is output verbatim), doubled
40 braces ('{{' and '}}', that lead to a single brace when output), and
44 - is followed by a nonnegative integer m,
45 - is optionally followed by ',' and an integer denoting a width,
46 - is optionally followed by ':' and a sequence of format specifiers.
47 (But the interpretation of the format specifiers is up to the IFormattable
48 implementation, depending on the argument's runtime value. New classes
49 implementing IFormattable can be defined by the user.)
50 - is finished with '}'.
55 unsigned int directives;
56 unsigned int numbered_arg_count;
60 format_parse (const char *format, bool translated, char *fdi,
61 char **invalid_reason)
63 const char *const format_start = format;
68 spec.numbered_arg_count = 0;
70 for (; *format != '\0';)
76 FDI_SET (format - 1, FMTDIR_START);
86 if (!c_isdigit (*format))
89 xasprintf (_("In the directive number %u, '{' is not followed by an argument number."), spec.directives);
90 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
96 number = 10 * number + (*format - '0');
99 while (c_isdigit (*format));
107 if (!c_isdigit (*format))
110 xasprintf (_("In the directive number %u, ',' is not followed by a number."), spec.directives);
111 FDI_SET (*format == '\0' ? format - 1 : format,
117 while (c_isdigit (*format));
122 /* Parse format specifiers. */
125 while (*format != '\0' && *format != '}');
131 xstrdup (_("The string ends in the middle of a directive: found '{' without matching '}'."));
132 FDI_SET (format - 1, FMTDIR_ERROR);
140 ? xasprintf (_("The directive number %u ends with an invalid character '%c' instead of '}'."), spec.directives, *format)
141 : xasprintf (_("The directive number %u ends with an invalid character instead of '}'."), spec.directives));
142 FDI_SET (format, FMTDIR_ERROR);
148 if (spec.numbered_arg_count <= number)
149 spec.numbered_arg_count = number + 1;
151 FDI_SET (format - 1, FMTDIR_END);
155 FDI_SET (format - 1, FMTDIR_START);
161 (spec.directives == 0
162 ? xstrdup (_("The string starts in the middle of a directive: found '}' without matching '{'."))
163 : xasprintf (_("The string contains a lone '}' after directive number %u."), spec.directives));
164 FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
167 FDI_SET (format - 1, FMTDIR_END);
171 result = XMALLOC (struct spec);
177 format_free (void *descr)
179 struct spec *spec = (struct spec *) descr;
185 format_get_number_of_directives (void *descr)
187 struct spec *spec = (struct spec *) descr;
189 return spec->directives;
193 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
194 formatstring_error_logger_t error_logger,
195 const char *pretty_msgid, const char *pretty_msgstr)
197 struct spec *spec1 = (struct spec *) msgid_descr;
198 struct spec *spec2 = (struct spec *) msgstr_descr;
201 /* Check that the argument counts are the same. */
203 ? spec1->numbered_arg_count != spec2->numbered_arg_count
204 : spec1->numbered_arg_count < spec2->numbered_arg_count)
207 error_logger (_("number of format specifications in '%s' and '%s' does not match"),
208 pretty_msgid, pretty_msgstr);
216 struct formatstring_parser formatstring_csharp =
220 format_get_number_of_directives,
228 /* Test program: Print the argument list specification returned by
229 format_parse for strings read from standard input. */
234 format_print (void *descr)
236 struct spec *spec = (struct spec *) descr;
246 for (i = 0; i < spec->numbered_arg_count; i++)
261 size_t line_size = 0;
263 char *invalid_reason;
266 line_len = getline (&line, &line_size, stdin);
269 if (line_len > 0 && line[line_len - 1] == '\n')
270 line[--line_len] = '\0';
272 invalid_reason = NULL;
273 descr = format_parse (line, false, NULL, &invalid_reason);
275 format_print (descr);
278 printf ("%s\n", invalid_reason);
280 free (invalid_reason);
288 * For Emacs M-x compile
290 * 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"