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)
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. */
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 '}'.
48 unsigned int directives
;
49 unsigned int named_arg_count
;
50 unsigned int allocated
;
51 struct named_arg
*named
;
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
);
63 format_parse (const char *format
, bool translated
, char **invalid_reason
)
69 spec
.named_arg_count
= 0;
73 for (; *format
!= '\0';)
76 const char *f
= format
;
80 if ((c
>= 'A' && c
<= 'Z') || (c
>= 'a' && c
<= 'z') || c
== '_')
84 while ((c
>= 'A' && c
<= 'Z') || (c
>= 'a' && c
<= 'z') || c
== '_'
85 || (c
>= '0' && c
<= '9'));
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
);
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
++;
113 /* Sort the named argument array, and eliminate duplicates. */
114 if (spec
.named_arg_count
> 1)
118 qsort (spec
.named
, spec
.named_arg_count
, sizeof (struct named_arg
),
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
);
128 spec
.named
[j
].name
= spec
.named
[i
].name
;
131 spec
.named_arg_count
= j
;
134 result
= (struct spec
*) xmalloc (sizeof (struct spec
));
140 format_free (void *descr
)
142 struct spec
*spec
= (struct spec
*) descr
;
144 if (spec
->named
!= NULL
)
147 for (i
= 0; i
< spec
->named_arg_count
; i
++)
148 free (spec
->named
[i
].name
);
155 format_get_number_of_directives (void *descr
)
157 struct spec
*spec
= (struct spec
*) descr
;
159 return spec
->directives
;
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
;
171 if (spec1
->named_arg_count
+ spec2
->named_arg_count
> 0)
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 :
185 strcmp (spec1
->named
[i
].name
, spec2
->named
[j
].name
));
194 error_logger (_("a format specification for argument '%s' doesn't exist in '%s'"),
195 spec1
->named
[i
].name
, pretty_msgstr
);
211 struct formatstring_parser formatstring_perl_brace
=
215 format_get_number_of_directives
,
222 /* Test program: Print the argument list specification returned by
223 format_parse for strings read from standard input. */
229 format_print (void *descr
)
231 struct spec
*spec
= (struct spec
*) descr
;
241 for (i
= 0; i
< spec
->named_arg_count
; i
++)
245 printf ("'%s'", spec
->named
[i
].name
);
256 size_t line_size
= 0;
258 char *invalid_reason
;
261 line_len
= getline (&line
, &line_size
, stdin
);
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
);
273 printf ("%s\n", invalid_reason
);
275 free (invalid_reason
);
283 * For Emacs M-x compile
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"