No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / gettext / gettext-tools / src / format-perl-brace.c
blob5604c4831a7fe9e7fcb9115907fb5acd15c91a65
1 /* Perl brace format strings.
2 Copyright (C) 2004 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 2, or (at your option)
8 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, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "format.h"
28 #include "xalloc.h"
29 #include "gettext.h"
31 #define _(str) gettext (str)
33 /* Perl brace format strings are supported by Guido Flohr's libintl-perl
34 package, more precisely by the __expand and __x functions therein.
35 A format string directive here consists of
36 - an opening brace '{',
37 - an identifier [_A-Za-z][_0-9A-Za-z]*,
38 - a closing brace '}'.
41 struct named_arg
43 char *name;
46 struct spec
48 unsigned int directives;
49 unsigned int named_arg_count;
50 unsigned int allocated;
51 struct named_arg *named;
55 static int
56 named_arg_compare (const void *p1, const void *p2)
58 return strcmp (((const struct named_arg *) p1)->name,
59 ((const struct named_arg *) p2)->name);
62 static void *
63 format_parse (const char *format, bool translated, char **invalid_reason)
65 struct spec spec;
66 struct spec *result;
68 spec.directives = 0;
69 spec.named_arg_count = 0;
70 spec.allocated = 0;
71 spec.named = NULL;
73 for (; *format != '\0';)
74 if (*format++ == '{')
76 const char *f = format;
77 char c;
79 c = *f;
80 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
83 c = *++f;
84 while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'
85 || (c >= '0' && c <= '9'));
86 if (c == '}')
88 /* A directive. */
89 char *name;
90 const char *name_start = format;
91 const char *name_end = f;
92 size_t n = name_end - name_start;
94 name = (char *) xmalloc (n + 1);
95 memcpy (name, name_start, n);
96 name[n] = '\0';
98 spec.directives++;
100 if (spec.allocated == spec.named_arg_count)
102 spec.allocated = 2 * spec.allocated + 1;
103 spec.named = (struct named_arg *) xrealloc (spec.named, spec.allocated * sizeof (struct named_arg));
105 spec.named[spec.named_arg_count].name = name;
106 spec.named_arg_count++;
108 format = ++f;
113 /* Sort the named argument array, and eliminate duplicates. */
114 if (spec.named_arg_count > 1)
116 unsigned int i, j;
118 qsort (spec.named, spec.named_arg_count, sizeof (struct named_arg),
119 named_arg_compare);
121 /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i. */
122 for (i = j = 0; i < spec.named_arg_count; i++)
123 if (j > 0 && strcmp (spec.named[i].name, spec.named[j-1].name) == 0)
124 free (spec.named[i].name);
125 else
127 if (j < i)
128 spec.named[j].name = spec.named[i].name;
129 j++;
131 spec.named_arg_count = j;
134 result = (struct spec *) xmalloc (sizeof (struct spec));
135 *result = spec;
136 return result;
139 static void
140 format_free (void *descr)
142 struct spec *spec = (struct spec *) descr;
144 if (spec->named != NULL)
146 unsigned int i;
147 for (i = 0; i < spec->named_arg_count; i++)
148 free (spec->named[i].name);
149 free (spec->named);
151 free (spec);
154 static int
155 format_get_number_of_directives (void *descr)
157 struct spec *spec = (struct spec *) descr;
159 return spec->directives;
162 static bool
163 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
164 formatstring_error_logger_t error_logger,
165 const char *pretty_msgstr)
167 struct spec *spec1 = (struct spec *) msgid_descr;
168 struct spec *spec2 = (struct spec *) msgstr_descr;
169 bool err = false;
171 if (spec1->named_arg_count + spec2->named_arg_count > 0)
173 unsigned int i, j;
174 unsigned int n1 = spec1->named_arg_count;
175 unsigned int n2 = spec2->named_arg_count;
177 /* Check the argument names in spec1 are contained in those of spec2.
178 Additional arguments in spec2 are allowed; they expand to themselves
179 (including the surrounding braces) at runtime.
180 Both arrays are sorted. We search for the differences. */
181 for (i = 0, j = 0; i < n1 || j < n2; )
183 int cmp = (i >= n1 ? 1 :
184 j >= n2 ? -1 :
185 strcmp (spec1->named[i].name, spec2->named[j].name));
187 if (cmp > 0)
188 j++;
189 else if (cmp < 0)
191 if (equality)
193 if (error_logger)
194 error_logger (_("a format specification for argument '%s' doesn't exist in '%s'"),
195 spec1->named[i].name, pretty_msgstr);
196 err = true;
197 break;
199 else
200 i++;
202 else
203 j++, i++;
207 return err;
211 struct formatstring_parser formatstring_perl_brace =
213 format_parse,
214 format_free,
215 format_get_number_of_directives,
216 format_check
220 #ifdef TEST
222 /* Test program: Print the argument list specification returned by
223 format_parse for strings read from standard input. */
225 #include <stdio.h>
226 #include "getline.h"
228 static void
229 format_print (void *descr)
231 struct spec *spec = (struct spec *) descr;
232 unsigned int i;
234 if (spec == NULL)
236 printf ("INVALID");
237 return;
240 printf ("{");
241 for (i = 0; i < spec->named_arg_count; i++)
243 if (i > 0)
244 printf (", ");
245 printf ("'%s'", spec->named[i].name);
247 printf ("}");
251 main ()
253 for (;;)
255 char *line = NULL;
256 size_t line_size = 0;
257 int line_len;
258 char *invalid_reason;
259 void *descr;
261 line_len = getline (&line, &line_size, stdin);
262 if (line_len < 0)
263 break;
264 if (line_len > 0 && line[line_len - 1] == '\n')
265 line[--line_len] = '\0';
267 invalid_reason = NULL;
268 descr = format_parse (line, false, &invalid_reason);
270 format_print (descr);
271 printf ("\n");
272 if (descr == NULL)
273 printf ("%s\n", invalid_reason);
275 free (invalid_reason);
276 free (line);
279 return 0;
283 * For Emacs M-x compile
284 * Local Variables:
285 * compile-command: "/bin/sh ../libtool --mode=link gcc -o a.out -static -O -g -Wall -I.. -I../lib -I../intl -DHAVE_CONFIG_H -DTEST format-perl-brace.c ../lib/libgettextlib.la"
286 * End:
289 #endif /* TEST */