Add -lm dependency for gettextlib to fix LTO build
[platform/upstream/gettext.git] / gettext-tools / src / format-c.c
1 /* C format strings.
2    Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software
3    Foundation, Inc.
4    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5
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.
10
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.
15
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/>.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdbool.h>
24 #include <stdlib.h>
25
26 #include "format.h"
27 #include "c-ctype.h"
28 #include "xalloc.h"
29 #include "xvasprintf.h"
30 #include "gettext.h"
31
32 #define _(str) gettext (str)
33
34 #include "format-invalid.h"
35
36 #define INVALID_C99_MACRO(directive_number) \
37   xasprintf (_("In the directive number %u, the token after '<' is not the name of a format specifier macro. The valid macro names are listed in ISO C 99 section 7.8.1."), directive_number)
38
39 #define INVALID_ANGLE_BRACKET(directive_number) \
40   xasprintf (_("In the directive number %u, the token after '<' is not followed by '>'."), directive_number)
41
42 #define INVALID_IGNORED_ARGUMENT(referenced_arg, ignored_arg) \
43   xasprintf (_("The string refers to argument number %u but ignores argument number %u."), referenced_arg, ignored_arg)
44
45 /* Execute statement if memory allocation function returned NULL.  */
46 #define IF_OOM(allocated_ptr, statement)  /* nothing, since we use xalloc.h */
47
48 /* Specifies whether the system dependent segments in msgid and msgstr have
49    been processed.  This means:
50      - If false, ISO C 99 <inttypes.h> directives are denoted with angle
51        brackets.  If true, they have already been expanded, leading in
52        particular to %I64d directives on native Windows platforms.
53      - If false, the 'I' flag may be present in msgstr (also on platforms
54        other than glibc).  If true, the 'I' directive may be present in msgstr
55        only on glibc >= 2.2 platforms.  */
56 #define SYSDEP_SEGMENTS_PROCESSED false
57
58 /* Include the bulk of the C format string parsing code.  */
59 #include "format-c-parse.h"
60
61 static void *
62 format_parse (const char *format, bool translated, bool objc_extensions,
63               char *fdi, char **invalid_reason)
64 {
65   struct spec result_buf;
66   struct spec *result;
67
68   result = format_parse_entrails (format, translated, objc_extensions, fdi, invalid_reason, &result_buf);
69
70   if (result != NULL)
71     {
72       /* Copy the result to a heap-allocated object.  */
73       struct spec *safe_result = XMALLOC (struct spec);
74       *safe_result = *result;
75       result = safe_result;
76     }
77   return result;
78 }
79
80 static void *
81 format_c_parse (const char *format, bool translated, char *fdi,
82                 char **invalid_reason)
83 {
84   return format_parse (format, translated, false, fdi, invalid_reason);
85 }
86
87 static void *
88 format_objc_parse (const char *format, bool translated, char *fdi,
89                    char **invalid_reason)
90 {
91   return format_parse (format, translated, true, fdi, invalid_reason);
92 }
93
94 static void
95 format_free (void *descr)
96 {
97   struct spec *spec = (struct spec *) descr;
98
99   if (spec->unnumbered != NULL)
100     free (spec->unnumbered);
101   if (spec->sysdep_directives != NULL)
102     free (spec->sysdep_directives);
103   free (spec);
104 }
105
106 static bool
107 format_is_unlikely_intentional (void *descr)
108 {
109   struct spec *spec = (struct spec *) descr;
110
111   return spec->unlikely_intentional;
112 }
113
114 static int
115 format_get_number_of_directives (void *descr)
116 {
117   struct spec *spec = (struct spec *) descr;
118
119   return spec->directives;
120 }
121
122 static bool
123 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
124               formatstring_error_logger_t error_logger,
125               const char *pretty_msgid, const char *pretty_msgstr)
126 {
127   struct spec *spec1 = (struct spec *) msgid_descr;
128   struct spec *spec2 = (struct spec *) msgstr_descr;
129   bool err = false;
130   unsigned int i;
131
132   /* Check the argument types are the same.  */
133   if (equality
134       ? spec1->unnumbered_arg_count != spec2->unnumbered_arg_count
135       : spec1->unnumbered_arg_count < spec2->unnumbered_arg_count)
136     {
137       if (error_logger)
138         error_logger (_("number of format specifications in '%s' and '%s' does not match"),
139                       pretty_msgid, pretty_msgstr);
140       err = true;
141     }
142   else
143     for (i = 0; i < spec2->unnumbered_arg_count; i++)
144       if (spec1->unnumbered[i].type != spec2->unnumbered[i].type)
145         {
146           if (error_logger)
147             error_logger (_("format specifications in '%s' and '%s' for argument %u are not the same"),
148                           pretty_msgid, pretty_msgstr, i + 1);
149           err = true;
150         }
151
152   return err;
153 }
154
155
156 struct formatstring_parser formatstring_c =
157 {
158   format_c_parse,
159   format_free,
160   format_get_number_of_directives,
161   format_is_unlikely_intentional,
162   format_check
163 };
164
165
166 struct formatstring_parser formatstring_objc =
167 {
168   format_objc_parse,
169   format_free,
170   format_get_number_of_directives,
171   format_is_unlikely_intentional,
172   format_check
173 };
174
175
176 void
177 get_sysdep_c_format_directives (const char *string, bool translated,
178                                 struct interval **intervalsp, size_t *lengthp)
179 {
180   /* Parse the format string with all possible extensions turned on.  (The
181      caller has already verified that the format string is valid for the
182      particular language.)  */
183   char *invalid_reason = NULL;
184   struct spec *descr =
185     (struct spec *)
186     format_parse (string, translated, true, NULL, &invalid_reason);
187
188   if (descr != NULL && descr->sysdep_directives_count > 0)
189     {
190       unsigned int n = descr->sysdep_directives_count;
191       struct interval *intervals = XNMALLOC (n, struct interval);
192       unsigned int i;
193
194       for (i = 0; i < n; i++)
195         {
196           intervals[i].startpos = descr->sysdep_directives[2 * i] - string;
197           intervals[i].endpos = descr->sysdep_directives[2 * i + 1] - string;
198         }
199       *intervalsp = intervals;
200       *lengthp = n;
201     }
202   else
203     {
204       *intervalsp = NULL;
205       *lengthp = 0;
206     }
207
208   if (descr != NULL)
209     format_free (descr);
210   else
211     free (invalid_reason);
212 }
213
214
215 #ifdef TEST
216
217 /* Test program: Print the argument list specification returned by
218    format_parse for strings read from standard input.  */
219
220 #include <stdio.h>
221
222 static void
223 format_print (void *descr)
224 {
225   struct spec *spec = (struct spec *) descr;
226   unsigned int i;
227
228   if (spec == NULL)
229     {
230       printf ("INVALID");
231       return;
232     }
233
234   printf ("(");
235   for (i = 0; i < spec->unnumbered_arg_count; i++)
236     {
237       if (i > 0)
238         printf (" ");
239       if (spec->unnumbered[i].type & FAT_UNSIGNED)
240         printf ("[unsigned]");
241       switch (spec->unnumbered[i].type & FAT_SIZE_MASK)
242         {
243         case 0:
244           break;
245         case FAT_SIZE_SHORT:
246           printf ("[short]");
247           break;
248         case FAT_SIZE_CHAR:
249           printf ("[char]");
250           break;
251         case FAT_SIZE_LONG:
252           printf ("[long]");
253           break;
254         case FAT_SIZE_LONGLONG:
255           printf ("[long long]");
256           break;
257         case FAT_SIZE_8_T:
258           printf ("[int8_t]");
259           break;
260         case FAT_SIZE_16_T:
261           printf ("[int16_t]");
262           break;
263         case FAT_SIZE_32_T:
264           printf ("[int32_t]");
265           break;
266         case FAT_SIZE_64_T:
267           printf ("[int64_t]");
268           break;
269         case FAT_SIZE_LEAST8_T:
270           printf ("[int_least8_t]");
271           break;
272         case FAT_SIZE_LEAST16_T:
273           printf ("[int_least16_t]");
274           break;
275         case FAT_SIZE_LEAST32_T:
276           printf ("[int_least32_t]");
277           break;
278         case FAT_SIZE_LEAST64_T:
279           printf ("[int_least64_t]");
280           break;
281         case FAT_SIZE_FAST8_T:
282           printf ("[int_fast8_t]");
283           break;
284         case FAT_SIZE_FAST16_T:
285           printf ("[int_fast16_t]");
286           break;
287         case FAT_SIZE_FAST32_T:
288           printf ("[int_fast32_t]");
289           break;
290         case FAT_SIZE_FAST64_T:
291           printf ("[int_fast64_t]");
292           break;
293         case FAT_SIZE_INTMAX_T:
294           printf ("[intmax_t]");
295           break;
296         case FAT_SIZE_INTPTR_T:
297           printf ("[intptr_t]");
298           break;
299         case FAT_SIZE_SIZE_T:
300           printf ("[size_t]");
301           break;
302         case FAT_SIZE_PTRDIFF_T:
303           printf ("[ptrdiff_t]");
304           break;
305         default:
306           abort ();
307         }
308       switch (spec->unnumbered[i].type & ~(FAT_UNSIGNED | FAT_SIZE_MASK))
309         {
310         case FAT_INTEGER:
311           printf ("i");
312           break;
313         case FAT_DOUBLE:
314           printf ("f");
315           break;
316         case FAT_CHAR:
317           printf ("c");
318           break;
319         case FAT_STRING:
320           printf ("s");
321           break;
322         case FAT_OBJC_OBJECT:
323           printf ("@");
324           break;
325         case FAT_POINTER:
326           printf ("p");
327           break;
328         case FAT_COUNT_POINTER:
329           printf ("n");
330           break;
331         default:
332           abort ();
333         }
334     }
335   printf (")");
336 }
337
338 int
339 main ()
340 {
341   for (;;)
342     {
343       char *line = NULL;
344       size_t line_size = 0;
345       int line_len;
346       char *invalid_reason;
347       void *descr;
348
349       line_len = getline (&line, &line_size, stdin);
350       if (line_len < 0)
351         break;
352       if (line_len > 0 && line[line_len - 1] == '\n')
353         line[--line_len] = '\0';
354
355       invalid_reason = NULL;
356       descr = format_c_parse (line, false, NULL, &invalid_reason);
357
358       format_print (descr);
359       printf ("\n");
360       if (descr == NULL)
361         printf ("%s\n", invalid_reason);
362
363       free (invalid_reason);
364       free (line);
365     }
366
367   return 0;
368 }
369
370 /*
371  * For Emacs M-x compile
372  * Local Variables:
373  * 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-c.c ../gnulib-lib/libgettextlib.la"
374  * End:
375  */
376
377 #endif /* TEST */