Imported Upstream version 0.19.7
[platform/upstream/gettext.git] / gettext-tools / src / format-python.c
1 /* Python format strings.
2    Copyright (C) 2001-2004, 2006-2009, 2015 Free Software Foundation,
3    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 #include <string.h>
26
27 #include "format.h"
28 #include "c-ctype.h"
29 #include "xalloc.h"
30 #include "xvasprintf.h"
31 #include "format-invalid.h"
32 #include "gettext.h"
33
34 #define _(str) gettext (str)
35
36 /* Python format strings are described in
37      Python Library reference
38      2. Built-in Types, Exceptions and Functions
39      2.1. Built-in Types
40      2.1.5. Sequence Types
41      2.1.5.2. String Formatting Operations
42    Any string or Unicode string can act as format string via the '%' operator,
43    implemented in stringobject.c and unicodeobject.c.
44    A directive
45    - starts with '%'
46    - is optionally followed by '(ident)' where ident is any sequence of
47      characters with balanced left and right parentheses,
48    - is optionally followed by any of the characters '-' (left justification),
49      '+' (sign), ' ' (blank), '#' (alt), '0' (zero), each of which acts as a
50      flag,
51    - is optionally followed by a width specification: '*' (reads an argument)
52      or a nonempty digit sequence,
53    - is optionally followed by '.' and a precision specification: '*' (reads
54      an argument) or a nonempty digit sequence,
55    - is optionally followed by a size specifier, one of 'h' 'l' 'L'.
56    - is finished by a specifier
57        - '%', that needs no argument,
58        - 'c', that needs a character argument,
59        - 's', 'r', that need a string argument (or, when a precision of 0 is
60          given, an argument of any type),
61        - 'i', 'd', 'u', 'o', 'x', 'X', that need an integer argument,
62        - 'e', 'E', 'f', 'g', 'G', that need a floating-point argument.
63    Use of '(ident)' and use of unnamed argument specifications are exclusive,
64    because the first requires a mapping as argument, while the second requires
65    a tuple as argument. When unnamed arguments are used, the number of
66    arguments in the format string and the number of elements in the argument
67    tuple (to the right of the '%' operator) must be the same.
68  */
69
70 enum format_arg_type
71 {
72   FAT_NONE,
73   FAT_ANY,
74   FAT_CHARACTER,
75   FAT_STRING,
76   FAT_INTEGER,
77   FAT_FLOAT
78 };
79
80 struct named_arg
81 {
82   char *name;
83   enum format_arg_type type;
84 };
85
86 struct unnamed_arg
87 {
88   enum format_arg_type type;
89 };
90
91 struct spec
92 {
93   unsigned int directives;
94   unsigned int named_arg_count;
95   unsigned int unnamed_arg_count;
96   unsigned int allocated;
97   struct named_arg *named;
98   struct unnamed_arg *unnamed;
99 };
100
101 /* Locale independent test for a decimal digit.
102    Argument can be  'char' or 'unsigned char'.  (Whereas the argument of
103    <ctype.h> isdigit must be an 'unsigned char'.)  */
104 #undef isdigit
105 #define isdigit(c) ((unsigned int) ((c) - '0') < 10)
106
107
108 static int
109 named_arg_compare (const void *p1, const void *p2)
110 {
111   return strcmp (((const struct named_arg *) p1)->name,
112                  ((const struct named_arg *) p2)->name);
113 }
114
115 #define INVALID_MIXES_NAMED_UNNAMED() \
116   xstrdup (_("The string refers to arguments both through argument names and through unnamed argument specifications."))
117
118 static void *
119 format_parse (const char *format, bool translated, char *fdi,
120               char **invalid_reason)
121 {
122   const char *const format_start = format;
123   struct spec spec;
124   struct spec *result;
125
126   spec.directives = 0;
127   spec.named_arg_count = 0;
128   spec.unnamed_arg_count = 0;
129   spec.allocated = 0;
130   spec.named = NULL;
131   spec.unnamed = NULL;
132
133   for (; *format != '\0';)
134     if (*format++ == '%')
135       {
136         /* A directive.  */
137         char *name = NULL;
138         bool zero_precision = false;
139         enum format_arg_type type;
140
141         FDI_SET (format - 1, FMTDIR_START);
142         spec.directives++;
143
144         if (*format == '(')
145           {
146             unsigned int depth;
147             const char *name_start;
148             const char *name_end;
149             size_t n;
150
151             name_start = ++format;
152             depth = 0;
153             for (; *format != '\0'; format++)
154               {
155                 if (*format == '(')
156                   depth++;
157                 else if (*format == ')')
158                   {
159                     if (depth == 0)
160                       break;
161                     else
162                       depth--;
163                   }
164               }
165             if (*format == '\0')
166               {
167                 *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
168                 FDI_SET (format - 1, FMTDIR_ERROR);
169                 goto bad_format;
170               }
171             name_end = format++;
172
173             n = name_end - name_start;
174             name = XNMALLOC (n + 1, char);
175             memcpy (name, name_start, n);
176             name[n] = '\0';
177           }
178
179         while (*format == '-' || *format == '+' || *format == ' '
180                || *format == '#' || *format == '0')
181           format++;
182
183         if (*format == '*')
184           {
185             format++;
186
187             /* Named and unnamed specifications are exclusive.  */
188             if (spec.named_arg_count > 0)
189               {
190                 *invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
191                 FDI_SET (format - 1, FMTDIR_ERROR);
192                 goto bad_format;
193               }
194
195             if (spec.allocated == spec.unnamed_arg_count)
196               {
197                 spec.allocated = 2 * spec.allocated + 1;
198                 spec.unnamed = (struct unnamed_arg *) xrealloc (spec.unnamed, spec.allocated * sizeof (struct unnamed_arg));
199               }
200             spec.unnamed[spec.unnamed_arg_count].type = FAT_INTEGER;
201             spec.unnamed_arg_count++;
202           }
203         else if (isdigit (*format))
204           {
205             do format++; while (isdigit (*format));
206           }
207
208         if (*format == '.')
209           {
210             format++;
211
212             if (*format == '*')
213               {
214                 format++;
215
216                 /* Named and unnamed specifications are exclusive.  */
217                 if (spec.named_arg_count > 0)
218                   {
219                     *invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
220                     FDI_SET (format - 1, FMTDIR_ERROR);
221                     goto bad_format;
222                   }
223
224                 if (spec.allocated == spec.unnamed_arg_count)
225                   {
226                     spec.allocated = 2 * spec.allocated + 1;
227                     spec.unnamed = (struct unnamed_arg *) xrealloc (spec.unnamed, spec.allocated * sizeof (struct unnamed_arg));
228                   }
229                 spec.unnamed[spec.unnamed_arg_count].type = FAT_INTEGER;
230                 spec.unnamed_arg_count++;
231               }
232             else if (isdigit (*format))
233               {
234                 zero_precision = true;
235                 do
236                   {
237                     if (*format != '0')
238                       zero_precision = false;
239                     format++;
240                   }
241                 while (isdigit (*format));
242               }
243           }
244
245         if (*format == 'h' || *format == 'l' || *format == 'L')
246           format++;
247
248         switch (*format)
249           {
250           case '%':
251             type = FAT_NONE;
252             break;
253           case 'c':
254             type = FAT_CHARACTER;
255             break;
256           case 's': case 'r':
257             type = (zero_precision ? FAT_ANY : FAT_STRING);
258             break;
259           case 'i': case 'd': case 'u': case 'o': case 'x': case 'X':
260             type = FAT_INTEGER;
261             break;
262           case 'e': case 'E': case 'f': case 'g': case 'G':
263             type = FAT_FLOAT;
264             break;
265           default:
266             if (*format == '\0')
267               {
268                 *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
269                 FDI_SET (format - 1, FMTDIR_ERROR);
270               }
271             else
272               {
273                 *invalid_reason =
274                   INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
275                 FDI_SET (format, FMTDIR_ERROR);
276               }
277             goto bad_format;
278           }
279
280         if (name != NULL)
281           {
282             /* Named argument.  */
283
284             /* Named and unnamed specifications are exclusive.  */
285             if (spec.unnamed_arg_count > 0)
286               {
287                 *invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
288                 FDI_SET (format, FMTDIR_ERROR);
289                 goto bad_format;
290               }
291
292             if (spec.allocated == spec.named_arg_count)
293               {
294                 spec.allocated = 2 * spec.allocated + 1;
295                 spec.named = (struct named_arg *) xrealloc (spec.named, spec.allocated * sizeof (struct named_arg));
296               }
297             spec.named[spec.named_arg_count].name = name;
298             spec.named[spec.named_arg_count].type = type;
299             spec.named_arg_count++;
300           }
301         else if (*format != '%')
302           {
303             /* Unnamed argument.  */
304
305             /* Named and unnamed specifications are exclusive.  */
306             if (spec.named_arg_count > 0)
307               {
308                 *invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
309                 FDI_SET (format, FMTDIR_ERROR);
310                 goto bad_format;
311               }
312
313             if (spec.allocated == spec.unnamed_arg_count)
314               {
315                 spec.allocated = 2 * spec.allocated + 1;
316                 spec.unnamed = (struct unnamed_arg *) xrealloc (spec.unnamed, spec.allocated * sizeof (struct unnamed_arg));
317               }
318             spec.unnamed[spec.unnamed_arg_count].type = type;
319             spec.unnamed_arg_count++;
320           }
321
322         FDI_SET (format, FMTDIR_END);
323
324         format++;
325       }
326
327   /* Sort the named argument array, and eliminate duplicates.  */
328   if (spec.named_arg_count > 1)
329     {
330       unsigned int i, j;
331       bool err;
332
333       qsort (spec.named, spec.named_arg_count, sizeof (struct named_arg),
334              named_arg_compare);
335
336       /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i.  */
337       err = false;
338       for (i = j = 0; i < spec.named_arg_count; i++)
339         if (j > 0 && strcmp (spec.named[i].name, spec.named[j-1].name) == 0)
340           {
341             enum format_arg_type type1 = spec.named[i].type;
342             enum format_arg_type type2 = spec.named[j-1].type;
343             enum format_arg_type type_both;
344
345             if (type1 == type2 || type2 == FAT_ANY)
346               type_both = type1;
347             else if (type1 == FAT_ANY)
348               type_both = type2;
349             else
350               {
351                 /* Incompatible types.  */
352                 type_both = FAT_NONE;
353                 if (!err)
354                   *invalid_reason =
355                     xasprintf (_("The string refers to the argument named '%s' in incompatible ways."), spec.named[i].name);
356                 err = true;
357               }
358
359             spec.named[j-1].type = type_both;
360             free (spec.named[i].name);
361           }
362         else
363           {
364             if (j < i)
365               {
366                 spec.named[j].name = spec.named[i].name;
367                 spec.named[j].type = spec.named[i].type;
368               }
369             j++;
370           }
371       spec.named_arg_count = j;
372       if (err)
373         /* *invalid_reason has already been set above.  */
374         goto bad_format;
375     }
376
377   result = XMALLOC (struct spec);
378   *result = spec;
379   return result;
380
381  bad_format:
382   if (spec.named != NULL)
383     {
384       unsigned int i;
385       for (i = 0; i < spec.named_arg_count; i++)
386         free (spec.named[i].name);
387       free (spec.named);
388     }
389   if (spec.unnamed != NULL)
390     free (spec.unnamed);
391   return NULL;
392 }
393
394 static void
395 format_free (void *descr)
396 {
397   struct spec *spec = (struct spec *) descr;
398
399   if (spec->named != NULL)
400     {
401       unsigned int i;
402       for (i = 0; i < spec->named_arg_count; i++)
403         free (spec->named[i].name);
404       free (spec->named);
405     }
406   if (spec->unnamed != NULL)
407     free (spec->unnamed);
408   free (spec);
409 }
410
411 static int
412 format_get_number_of_directives (void *descr)
413 {
414   struct spec *spec = (struct spec *) descr;
415
416   return spec->directives;
417 }
418
419 static bool
420 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
421               formatstring_error_logger_t error_logger,
422               const char *pretty_msgid, const char *pretty_msgstr)
423 {
424   struct spec *spec1 = (struct spec *) msgid_descr;
425   struct spec *spec2 = (struct spec *) msgstr_descr;
426   bool err = false;
427
428   if (spec1->named_arg_count > 0 && spec2->unnamed_arg_count > 0)
429     {
430       if (error_logger)
431         error_logger (_("format specifications in '%s' expect a mapping, those in '%s' expect a tuple"),
432                       pretty_msgid, pretty_msgstr);
433       err = true;
434     }
435   else if (spec1->unnamed_arg_count > 0 && spec2->named_arg_count > 0)
436     {
437       if (error_logger)
438         error_logger (_("format specifications in '%s' expect a tuple, those in '%s' expect a mapping"),
439                       pretty_msgid, pretty_msgstr);
440       err = true;
441     }
442   else
443     {
444       if (spec1->named_arg_count + spec2->named_arg_count > 0)
445         {
446           unsigned int i, j;
447           unsigned int n1 = spec1->named_arg_count;
448           unsigned int n2 = spec2->named_arg_count;
449
450           /* Check the argument names are the same.
451              Both arrays are sorted.  We search for the first difference.  */
452           for (i = 0, j = 0; i < n1 || j < n2; )
453             {
454               int cmp = (i >= n1 ? 1 :
455                          j >= n2 ? -1 :
456                          strcmp (spec1->named[i].name, spec2->named[j].name));
457
458               if (cmp > 0)
459                 {
460                   if (error_logger)
461                     error_logger (_("a format specification for argument '%s', as in '%s', doesn't exist in '%s'"),
462                                   spec2->named[j].name, pretty_msgstr,
463                                   pretty_msgid);
464                   err = true;
465                   break;
466                 }
467               else if (cmp < 0)
468                 {
469                   if (equality)
470                     {
471                       if (error_logger)
472                         error_logger (_("a format specification for argument '%s' doesn't exist in '%s'"),
473                                       spec1->named[i].name, pretty_msgstr);
474                       err = true;
475                       break;
476                     }
477                   else
478                     i++;
479                 }
480               else
481                 j++, i++;
482             }
483           /* Check the argument types are the same.  */
484           if (!err)
485             for (i = 0, j = 0; j < n2; )
486               {
487                 if (strcmp (spec1->named[i].name, spec2->named[j].name) == 0)
488                   {
489                     if (!(spec1->named[i].type == spec2->named[j].type
490                           || (!equality
491                               && (spec1->named[i].type == FAT_ANY
492                                   || spec2->named[j].type == FAT_ANY))))
493                       {
494                         if (error_logger)
495                           error_logger (_("format specifications in '%s' and '%s' for argument '%s' are not the same"),
496                                         pretty_msgid, pretty_msgstr,
497                                         spec2->named[j].name);
498                         err = true;
499                         break;
500                       }
501                     j++, i++;
502                   }
503                 else
504                   i++;
505               }
506         }
507
508       if (spec1->unnamed_arg_count + spec2->unnamed_arg_count > 0)
509         {
510           unsigned int i;
511
512           /* Check the argument types are the same.  */
513           if (spec1->unnamed_arg_count != spec2->unnamed_arg_count)
514             {
515               if (error_logger)
516                 error_logger (_("number of format specifications in '%s' and '%s' does not match"),
517                               pretty_msgid, pretty_msgstr);
518               err = true;
519             }
520           else
521             for (i = 0; i < spec2->unnamed_arg_count; i++)
522               if (!(spec1->unnamed[i].type == spec2->unnamed[i].type
523                     || (!equality
524                         && (spec1->unnamed[i].type == FAT_ANY
525                             || spec2->unnamed[i].type == FAT_ANY))))
526                 {
527                   if (error_logger)
528                     error_logger (_("format specifications in '%s' and '%s' for argument %u are not the same"),
529                                   pretty_msgid, pretty_msgstr, i + 1);
530                   err = true;
531                 }
532         }
533     }
534
535   return err;
536 }
537
538
539 struct formatstring_parser formatstring_python =
540 {
541   format_parse,
542   format_free,
543   format_get_number_of_directives,
544   NULL,
545   format_check
546 };
547
548
549 unsigned int
550 get_python_format_unnamed_arg_count (const char *string)
551 {
552   /* Parse the format string.  */
553   char *invalid_reason = NULL;
554   struct spec *descr =
555     (struct spec *) format_parse (string, false, NULL, &invalid_reason);
556
557   if (descr != NULL)
558     {
559       unsigned int result = descr->unnamed_arg_count;
560
561       format_free (descr);
562       return result;
563     }
564   else
565     {
566       free (invalid_reason);
567       return 0;
568     }
569 }
570
571
572 #ifdef TEST
573
574 /* Test program: Print the argument list specification returned by
575    format_parse for strings read from standard input.  */
576
577 #include <stdio.h>
578
579 static void
580 format_print (void *descr)
581 {
582   struct spec *spec = (struct spec *) descr;
583   unsigned int i;
584
585   if (spec == NULL)
586     {
587       printf ("INVALID");
588       return;
589     }
590
591   if (spec->named_arg_count > 0)
592     {
593       if (spec->unnamed_arg_count > 0)
594         abort ();
595
596       printf ("{");
597       for (i = 0; i < spec->named_arg_count; i++)
598         {
599           if (i > 0)
600             printf (", ");
601           printf ("'%s':", spec->named[i].name);
602           switch (spec->named[i].type)
603             {
604             case FAT_ANY:
605               printf ("*");
606               break;
607             case FAT_CHARACTER:
608               printf ("c");
609               break;
610             case FAT_STRING:
611               printf ("s");
612               break;
613             case FAT_INTEGER:
614               printf ("i");
615               break;
616             case FAT_FLOAT:
617               printf ("f");
618               break;
619             default:
620               abort ();
621             }
622         }
623       printf ("}");
624     }
625   else
626     {
627       printf ("(");
628       for (i = 0; i < spec->unnamed_arg_count; i++)
629         {
630           if (i > 0)
631             printf (" ");
632           switch (spec->unnamed[i].type)
633             {
634             case FAT_ANY:
635               printf ("*");
636               break;
637             case FAT_CHARACTER:
638               printf ("c");
639               break;
640             case FAT_STRING:
641               printf ("s");
642               break;
643             case FAT_INTEGER:
644               printf ("i");
645               break;
646             case FAT_FLOAT:
647               printf ("f");
648               break;
649             default:
650               abort ();
651             }
652         }
653       printf (")");
654     }
655 }
656
657 int
658 main ()
659 {
660   for (;;)
661     {
662       char *line = NULL;
663       size_t line_size = 0;
664       int line_len;
665       char *invalid_reason;
666       void *descr;
667
668       line_len = getline (&line, &line_size, stdin);
669       if (line_len < 0)
670         break;
671       if (line_len > 0 && line[line_len - 1] == '\n')
672         line[--line_len] = '\0';
673
674       invalid_reason = NULL;
675       descr = format_parse (line, false, NULL, &invalid_reason);
676
677       format_print (descr);
678       printf ("\n");
679       if (descr == NULL)
680         printf ("%s\n", invalid_reason);
681
682       free (invalid_reason);
683       free (line);
684     }
685
686   return 0;
687 }
688
689 /*
690  * For Emacs M-x compile
691  * Local Variables:
692  * 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-python.c ../gnulib-lib/libgettextlib.la"
693  * End:
694  */
695
696 #endif /* TEST */