2e679809779bf325d6b193e7c403e0d30773a672
[debian/amanda] / gnulib / printf-parse.c
1 /* Formatted output to strings.
2    Copyright (C) 1999-2000, 2002-2003, 2006-2007 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* This file can be parametrized with the following macros:
19      CHAR_T             The element type of the format string.
20      CHAR_T_ONLY_ASCII  Set to 1 to enable verification that all characters
21                         in the format string are ASCII.
22      DIRECTIVE          Structure denoting a format directive.
23                         Depends on CHAR_T.
24      DIRECTIVES         Structure denoting the set of format directives of a
25                         format string.  Depends on CHAR_T.
26      PRINTF_PARSE       Function that parses a format string.
27                         Depends on CHAR_T.
28      STATIC             Set to 'static' to declare the function static.
29      ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.  */
30
31 #ifndef PRINTF_PARSE
32 # include <config.h>
33 #endif
34
35 /* Specification.  */
36 #ifndef PRINTF_PARSE
37 # include "printf-parse.h"
38 #endif
39
40 /* Default parameters.  */
41 #ifndef PRINTF_PARSE
42 # define PRINTF_PARSE printf_parse
43 # define CHAR_T char
44 # define DIRECTIVE char_directive
45 # define DIRECTIVES char_directives
46 #endif
47
48 /* Get size_t, NULL.  */
49 #include <stddef.h>
50
51 /* Get intmax_t.  */
52 #ifdef IN_LIBINTL
53 # if HAVE_STDINT_H_WITH_UINTMAX
54 #  include <stdint.h>
55 # endif
56 # if HAVE_INTTYPES_H_WITH_UINTMAX
57 #  include <inttypes.h>
58 # endif
59 #else
60 # include <stdint.h>
61 #endif
62
63 /* malloc(), realloc(), free().  */
64 #include <stdlib.h>
65
66 /* Checked size_t computations.  */
67 #include "xsize.h"
68
69 #if CHAR_T_ONLY_ASCII
70 /* c_isascii().  */
71 # include "c-ctype.h"
72 #endif
73
74 #ifdef STATIC
75 STATIC
76 #endif
77 int
78 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
79 {
80   const CHAR_T *cp = format;            /* pointer into format */
81   size_t arg_posn = 0;          /* number of regular arguments consumed */
82   size_t d_allocated;                   /* allocated elements of d->dir */
83   size_t a_allocated;                   /* allocated elements of a->arg */
84   size_t max_width_length = 0;
85   size_t max_precision_length = 0;
86
87   d->count = 0;
88   d_allocated = 1;
89   d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE));
90   if (d->dir == NULL)
91     /* Out of memory.  */
92     return -1;
93
94   a->count = 0;
95   a_allocated = 0;
96   a->arg = NULL;
97
98 #define REGISTER_ARG(_index_,_type_) \
99   {                                                                     \
100     size_t n = (_index_);                                               \
101     if (n >= a_allocated)                                               \
102       {                                                                 \
103         size_t memory_size;                                             \
104         argument *memory;                                               \
105                                                                         \
106         a_allocated = xtimes (a_allocated, 2);                          \
107         if (a_allocated <= n)                                           \
108           a_allocated = xsum (n, 1);                                    \
109         memory_size = xtimes (a_allocated, sizeof (argument));          \
110         if (size_overflow_p (memory_size))                              \
111           /* Overflow, would lead to out of memory.  */                 \
112           goto error;                                                   \
113         memory = (argument *) (a->arg                                   \
114                                ? realloc (a->arg, memory_size)          \
115                                : malloc (memory_size));                 \
116         if (memory == NULL)                                             \
117           /* Out of memory.  */                                         \
118           goto error;                                                   \
119         a->arg = memory;                                                \
120       }                                                                 \
121     while (a->count <= n)                                               \
122       a->arg[a->count++].type = TYPE_NONE;                              \
123     if (a->arg[n].type == TYPE_NONE)                                    \
124       a->arg[n].type = (_type_);                                        \
125     else if (a->arg[n].type != (_type_))                                \
126       /* Ambiguous type for positional argument.  */                    \
127       goto error;                                                       \
128   }
129
130   while (*cp != '\0')
131     {
132       CHAR_T c = *cp++;
133       if (c == '%')
134         {
135           size_t arg_index = ARG_NONE;
136           DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
137
138           /* Initialize the next directive.  */
139           dp->dir_start = cp - 1;
140           dp->flags = 0;
141           dp->width_start = NULL;
142           dp->width_end = NULL;
143           dp->width_arg_index = ARG_NONE;
144           dp->precision_start = NULL;
145           dp->precision_end = NULL;
146           dp->precision_arg_index = ARG_NONE;
147           dp->arg_index = ARG_NONE;
148
149           /* Test for positional argument.  */
150           if (*cp >= '0' && *cp <= '9')
151             {
152               const CHAR_T *np;
153
154               for (np = cp; *np >= '0' && *np <= '9'; np++)
155                 ;
156               if (*np == '$')
157                 {
158                   size_t n = 0;
159
160                   for (np = cp; *np >= '0' && *np <= '9'; np++)
161                     n = xsum (xtimes (n, 10), *np - '0');
162                   if (n == 0)
163                     /* Positional argument 0.  */
164                     goto error;
165                   if (size_overflow_p (n))
166                     /* n too large, would lead to out of memory later.  */
167                     goto error;
168                   arg_index = n - 1;
169                   cp = np + 1;
170                 }
171             }
172
173           /* Read the flags.  */
174           for (;;)
175             {
176               if (*cp == '\'')
177                 {
178                   dp->flags |= FLAG_GROUP;
179                   cp++;
180                 }
181               else if (*cp == '-')
182                 {
183                   dp->flags |= FLAG_LEFT;
184                   cp++;
185                 }
186               else if (*cp == '+')
187                 {
188                   dp->flags |= FLAG_SHOWSIGN;
189                   cp++;
190                 }
191               else if (*cp == ' ')
192                 {
193                   dp->flags |= FLAG_SPACE;
194                   cp++;
195                 }
196               else if (*cp == '#')
197                 {
198                   dp->flags |= FLAG_ALT;
199                   cp++;
200                 }
201               else if (*cp == '0')
202                 {
203                   dp->flags |= FLAG_ZERO;
204                   cp++;
205                 }
206               else
207                 break;
208             }
209
210           /* Parse the field width.  */
211           if (*cp == '*')
212             {
213               dp->width_start = cp;
214               cp++;
215               dp->width_end = cp;
216               if (max_width_length < 1)
217                 max_width_length = 1;
218
219               /* Test for positional argument.  */
220               if (*cp >= '0' && *cp <= '9')
221                 {
222                   const CHAR_T *np;
223
224                   for (np = cp; *np >= '0' && *np <= '9'; np++)
225                     ;
226                   if (*np == '$')
227                     {
228                       size_t n = 0;
229
230                       for (np = cp; *np >= '0' && *np <= '9'; np++)
231                         n = xsum (xtimes (n, 10), *np - '0');
232                       if (n == 0)
233                         /* Positional argument 0.  */
234                         goto error;
235                       if (size_overflow_p (n))
236                         /* n too large, would lead to out of memory later.  */
237                         goto error;
238                       dp->width_arg_index = n - 1;
239                       cp = np + 1;
240                     }
241                 }
242               if (dp->width_arg_index == ARG_NONE)
243                 {
244                   dp->width_arg_index = arg_posn++;
245                   if (dp->width_arg_index == ARG_NONE)
246                     /* arg_posn wrapped around.  */
247                     goto error;
248                 }
249               REGISTER_ARG (dp->width_arg_index, TYPE_INT);
250             }
251           else if (*cp >= '0' && *cp <= '9')
252             {
253               size_t width_length;
254
255               dp->width_start = cp;
256               for (; *cp >= '0' && *cp <= '9'; cp++)
257                 ;
258               dp->width_end = cp;
259               width_length = dp->width_end - dp->width_start;
260               if (max_width_length < width_length)
261                 max_width_length = width_length;
262             }
263
264           /* Parse the precision.  */
265           if (*cp == '.')
266             {
267               cp++;
268               if (*cp == '*')
269                 {
270                   dp->precision_start = cp - 1;
271                   cp++;
272                   dp->precision_end = cp;
273                   if (max_precision_length < 2)
274                     max_precision_length = 2;
275
276                   /* Test for positional argument.  */
277                   if (*cp >= '0' && *cp <= '9')
278                     {
279                       const CHAR_T *np;
280
281                       for (np = cp; *np >= '0' && *np <= '9'; np++)
282                         ;
283                       if (*np == '$')
284                         {
285                           size_t n = 0;
286
287                           for (np = cp; *np >= '0' && *np <= '9'; np++)
288                             n = xsum (xtimes (n, 10), *np - '0');
289                           if (n == 0)
290                             /* Positional argument 0.  */
291                             goto error;
292                           if (size_overflow_p (n))
293                             /* n too large, would lead to out of memory
294                                later.  */
295                             goto error;
296                           dp->precision_arg_index = n - 1;
297                           cp = np + 1;
298                         }
299                     }
300                   if (dp->precision_arg_index == ARG_NONE)
301                     {
302                       dp->precision_arg_index = arg_posn++;
303                       if (dp->precision_arg_index == ARG_NONE)
304                         /* arg_posn wrapped around.  */
305                         goto error;
306                     }
307                   REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
308                 }
309               else
310                 {
311                   size_t precision_length;
312
313                   dp->precision_start = cp - 1;
314                   for (; *cp >= '0' && *cp <= '9'; cp++)
315                     ;
316                   dp->precision_end = cp;
317                   precision_length = dp->precision_end - dp->precision_start;
318                   if (max_precision_length < precision_length)
319                     max_precision_length = precision_length;
320                 }
321             }
322
323           {
324             arg_type type;
325
326             /* Parse argument type/size specifiers.  */
327             {
328               int flags = 0;
329
330               for (;;)
331                 {
332                   if (*cp == 'h')
333                     {
334                       flags |= (1 << (flags & 1));
335                       cp++;
336                     }
337                   else if (*cp == 'L')
338                     {
339                       flags |= 4;
340                       cp++;
341                     }
342                   else if (*cp == 'l')
343                     {
344                       flags += 8;
345                       cp++;
346                     }
347                   else if (*cp == 'j')
348                     {
349                       if (sizeof (intmax_t) > sizeof (long))
350                         {
351                           /* intmax_t = long long */
352                           flags += 16;
353                         }
354                       else if (sizeof (intmax_t) > sizeof (int))
355                         {
356                           /* intmax_t = long */
357                           flags += 8;
358                         }
359                       cp++;
360                     }
361                   else if (*cp == 'z' || *cp == 'Z')
362                     {
363                       /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
364                          because the warning facility in gcc-2.95.2 understands
365                          only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
366                       if (sizeof (size_t) > sizeof (long))
367                         {
368                           /* size_t = long long */
369                           flags += 16;
370                         }
371                       else if (sizeof (size_t) > sizeof (int))
372                         {
373                           /* size_t = long */
374                           flags += 8;
375                         }
376                       cp++;
377                     }
378                   else if (*cp == 't')
379                     {
380                       if (sizeof (ptrdiff_t) > sizeof (long))
381                         {
382                           /* ptrdiff_t = long long */
383                           flags += 16;
384                         }
385                       else if (sizeof (ptrdiff_t) > sizeof (int))
386                         {
387                           /* ptrdiff_t = long */
388                           flags += 8;
389                         }
390                       cp++;
391                     }
392                   else
393                     break;
394                 }
395
396               /* Read the conversion character.  */
397               c = *cp++;
398               switch (c)
399                 {
400                 case 'd': case 'i':
401 #if HAVE_LONG_LONG_INT
402                   /* If 'long long' exists and is larger than 'long':  */
403                   if (flags >= 16 || (flags & 4))
404                     type = TYPE_LONGLONGINT;
405                   else
406 #endif
407                   /* If 'long long' exists and is the same as 'long', we parse
408                      "lld" into TYPE_LONGINT.  */
409                   if (flags >= 8)
410                     type = TYPE_LONGINT;
411                   else if (flags & 2)
412                     type = TYPE_SCHAR;
413                   else if (flags & 1)
414                     type = TYPE_SHORT;
415                   else
416                     type = TYPE_INT;
417                   break;
418                 case 'o': case 'u': case 'x': case 'X':
419 #if HAVE_LONG_LONG_INT
420                   /* If 'long long' exists and is larger than 'long':  */
421                   if (flags >= 16 || (flags & 4))
422                     type = TYPE_ULONGLONGINT;
423                   else
424 #endif
425                   /* If 'unsigned long long' exists and is the same as
426                      'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
427                   if (flags >= 8)
428                     type = TYPE_ULONGINT;
429                   else if (flags & 2)
430                     type = TYPE_UCHAR;
431                   else if (flags & 1)
432                     type = TYPE_USHORT;
433                   else
434                     type = TYPE_UINT;
435                   break;
436                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
437                 case 'a': case 'A':
438                   if (flags >= 16 || (flags & 4))
439                     type = TYPE_LONGDOUBLE;
440                   else
441                     type = TYPE_DOUBLE;
442                   break;
443                 case 'c':
444                   if (flags >= 8)
445 #if HAVE_WINT_T
446                     type = TYPE_WIDE_CHAR;
447 #else
448                     goto error;
449 #endif
450                   else
451                     type = TYPE_CHAR;
452                   break;
453 #if HAVE_WINT_T
454                 case 'C':
455                   type = TYPE_WIDE_CHAR;
456                   c = 'c';
457                   break;
458 #endif
459                 case 's':
460                   if (flags >= 8)
461 #if HAVE_WCHAR_T
462                     type = TYPE_WIDE_STRING;
463 #else
464                     goto error;
465 #endif
466                   else
467                     type = TYPE_STRING;
468                   break;
469 #if HAVE_WCHAR_T
470                 case 'S':
471                   type = TYPE_WIDE_STRING;
472                   c = 's';
473                   break;
474 #endif
475                 case 'p':
476                   type = TYPE_POINTER;
477                   break;
478                 case 'n':
479 #if HAVE_LONG_LONG_INT
480                   /* If 'long long' exists and is larger than 'long':  */
481                   if (flags >= 16 || (flags & 4))
482                     type = TYPE_COUNT_LONGLONGINT_POINTER;
483                   else
484 #endif
485                   /* If 'long long' exists and is the same as 'long', we parse
486                      "lln" into TYPE_COUNT_LONGINT_POINTER.  */
487                   if (flags >= 8)
488                     type = TYPE_COUNT_LONGINT_POINTER;
489                   else if (flags & 2)
490                     type = TYPE_COUNT_SCHAR_POINTER;
491                   else if (flags & 1)
492                     type = TYPE_COUNT_SHORT_POINTER;
493                   else
494                     type = TYPE_COUNT_INT_POINTER;
495                   break;
496 #if ENABLE_UNISTDIO
497                 /* The unistdio extensions.  */
498                 case 'U':
499                   if (flags >= 16)
500                     type = TYPE_U32_STRING;
501                   else if (flags >= 8)
502                     type = TYPE_U16_STRING;
503                   else
504                     type = TYPE_U8_STRING;
505                   break;
506 #endif
507                 case '%':
508                   type = TYPE_NONE;
509                   break;
510                 default:
511                   /* Unknown conversion character.  */
512                   goto error;
513                 }
514             }
515
516             if (type != TYPE_NONE)
517               {
518                 dp->arg_index = arg_index;
519                 if (dp->arg_index == ARG_NONE)
520                   {
521                     dp->arg_index = arg_posn++;
522                     if (dp->arg_index == ARG_NONE)
523                       /* arg_posn wrapped around.  */
524                       goto error;
525                   }
526                 REGISTER_ARG (dp->arg_index, type);
527               }
528             dp->conversion = c;
529             dp->dir_end = cp;
530           }
531
532           d->count++;
533           if (d->count >= d_allocated)
534             {
535               size_t memory_size;
536               DIRECTIVE *memory;
537
538               d_allocated = xtimes (d_allocated, 2);
539               memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
540               if (size_overflow_p (memory_size))
541                 /* Overflow, would lead to out of memory.  */
542                 goto error;
543               memory = (DIRECTIVE *) realloc (d->dir, memory_size);
544               if (memory == NULL)
545                 /* Out of memory.  */
546                 goto error;
547               d->dir = memory;
548             }
549         }
550 #if CHAR_T_ONLY_ASCII
551       else if (!c_isascii (c))
552         {
553           /* Non-ASCII character.  Not supported.  */
554           goto error;
555         }
556 #endif
557     }
558   d->dir[d->count].dir_start = cp;
559
560   d->max_width_length = max_width_length;
561   d->max_precision_length = max_precision_length;
562   return 0;
563
564 error:
565   if (a->arg)
566     free (a->arg);
567   if (d->dir)
568     free (d->dir);
569   return -1;
570 }
571
572 #undef PRINTF_PARSE
573 #undef DIRECTIVES
574 #undef DIRECTIVE
575 #undef CHAR_T_ONLY_ASCII
576 #undef CHAR_T