Update
[debian/tar] / lib / printf-parse.c
1 /* Formatted output to strings.
2    Copyright (C) 1999-2000, 2002-2004, 2006 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 #include <config.h>
19
20 /* Specification.  */
21 #if WIDE_CHAR_VERSION
22 # include "wprintf-parse.h"
23 #else
24 # include "printf-parse.h"
25 #endif
26
27 /* Get size_t, NULL.  */
28 #include <stddef.h>
29
30 /* Get intmax_t.  */
31 #if HAVE_STDINT_H_WITH_UINTMAX
32 # include <stdint.h>
33 #endif
34 #if HAVE_INTTYPES_H_WITH_UINTMAX
35 # include <inttypes.h>
36 #endif
37
38 /* malloc(), realloc(), free().  */
39 #include <stdlib.h>
40
41 #ifndef SIZE_MAX
42 # define SIZE_MAX ((size_t) -1)
43 #endif
44
45 #if WIDE_CHAR_VERSION
46 # define PRINTF_PARSE wprintf_parse
47 # define CHAR_T wchar_t
48 # define DIRECTIVE wchar_t_directive
49 # define DIRECTIVES wchar_t_directives
50 #else
51 # define PRINTF_PARSE printf_parse
52 # define CHAR_T char
53 # define DIRECTIVE char_directive
54 # define DIRECTIVES char_directives
55 #endif
56
57 #ifdef STATIC
58 STATIC
59 #endif
60 int
61 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
62 {
63   const CHAR_T *cp = format;            /* pointer into format */
64   size_t arg_posn = 0;          /* number of regular arguments consumed */
65   size_t d_allocated;                   /* allocated elements of d->dir */
66   size_t a_allocated;                   /* allocated elements of a->arg */
67   size_t max_width_length = 0;
68   size_t max_precision_length = 0;
69
70   d->count = 0;
71   d_allocated = 1;
72   d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
73   if (d->dir == NULL)
74     /* Out of memory.  */
75     return -1;
76
77   a->count = 0;
78   a_allocated = 0;
79   a->arg = NULL;
80
81 #define REGISTER_ARG(_index_,_type_) \
82   {                                                                     \
83     size_t n = (_index_);                                               \
84     if (n >= a_allocated)                                               \
85       {                                                                 \
86         size_t memory_size;                                             \
87         argument *memory;                                               \
88                                                                         \
89         a_allocated *= 2;                                               \
90         if (a_allocated <= n)                                           \
91           a_allocated = n + 1;                                          \
92         if (SIZE_MAX / sizeof (argument) < a_allocated)                 \
93           /* Overflow, would lead to out of memory.  */                 \
94           goto error;                                                   \
95         memory_size = a_allocated * sizeof (argument);                  \
96         memory = (a->arg                                                \
97                   ? realloc (a->arg, memory_size)                       \
98                   : malloc (memory_size));                              \
99         if (memory == NULL)                                             \
100           /* Out of memory.  */                                         \
101           goto error;                                                   \
102         a->arg = memory;                                                \
103       }                                                                 \
104     while (a->count <= n)                                               \
105       a->arg[a->count++].type = TYPE_NONE;                              \
106     if (a->arg[n].type == TYPE_NONE)                                    \
107       a->arg[n].type = (_type_);                                        \
108     else if (a->arg[n].type != (_type_))                                \
109       /* Ambiguous type for positional argument.  */                    \
110       goto error;                                                       \
111   }
112
113   while (*cp != '\0')
114     {
115       CHAR_T c = *cp++;
116       if (c == '%')
117         {
118           size_t arg_index = ARG_NONE;
119           DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
120
121           /* Initialize the next directive.  */
122           dp->dir_start = cp - 1;
123           dp->flags = 0;
124           dp->width_start = NULL;
125           dp->width_end = NULL;
126           dp->width_arg_index = ARG_NONE;
127           dp->precision_start = NULL;
128           dp->precision_end = NULL;
129           dp->precision_arg_index = ARG_NONE;
130           dp->arg_index = ARG_NONE;
131
132           /* Test for positional argument.  */
133           if (*cp >= '0' && *cp <= '9')
134             {
135               const CHAR_T *np;
136
137               for (np = cp; *np >= '0' && *np <= '9'; np++)
138                 ;
139               if (*np == '$')
140                 {
141                   size_t n = 0;
142
143                   for (np = cp; *np >= '0' && *np <= '9'; np++)
144                     if (n < SIZE_MAX / 10)
145                       n = 10 * n + (*np - '0');
146                     else
147                       /* n too large for memory.  */
148                       goto error;
149                   if (n == 0)
150                     /* Positional argument 0.  */
151                     goto error;
152                   arg_index = n - 1;
153                   cp = np + 1;
154                 }
155             }
156
157           /* Read the flags.  */
158           for (;;)
159             {
160               if (*cp == '\'')
161                 {
162                   dp->flags |= FLAG_GROUP;
163                   cp++;
164                 }
165               else if (*cp == '-')
166                 {
167                   dp->flags |= FLAG_LEFT;
168                   cp++;
169                 }
170               else if (*cp == '+')
171                 {
172                   dp->flags |= FLAG_SHOWSIGN;
173                   cp++;
174                 }
175               else if (*cp == ' ')
176                 {
177                   dp->flags |= FLAG_SPACE;
178                   cp++;
179                 }
180               else if (*cp == '#')
181                 {
182                   dp->flags |= FLAG_ALT;
183                   cp++;
184                 }
185               else if (*cp == '0')
186                 {
187                   dp->flags |= FLAG_ZERO;
188                   cp++;
189                 }
190               else
191                 break;
192             }
193
194           /* Parse the field width.  */
195           if (*cp == '*')
196             {
197               dp->width_start = cp;
198               cp++;
199               dp->width_end = cp;
200               if (max_width_length < 1)
201                 max_width_length = 1;
202
203               /* Test for positional argument.  */
204               if (*cp >= '0' && *cp <= '9')
205                 {
206                   const CHAR_T *np;
207
208                   for (np = cp; *np >= '0' && *np <= '9'; np++)
209                     ;
210                   if (*np == '$')
211                     {
212                       size_t n = 0;
213
214                       for (np = cp; *np >= '0' && *np <= '9'; np++)
215                         if (n < SIZE_MAX / 10)
216                           n = 10 * n + (*np - '0');
217                         else
218                           /* n too large for memory.  */
219                           goto error;
220                       if (n == 0)
221                         /* Positional argument 0.  */
222                         goto error;
223                       dp->width_arg_index = n - 1;
224                       cp = np + 1;
225                     }
226                 }
227               if (dp->width_arg_index == ARG_NONE)
228                 {
229                   dp->width_arg_index = arg_posn++;
230                   if (dp->width_arg_index == ARG_NONE)
231                     /* arg_posn wrapped around.  */
232                     goto error;
233                 }
234               REGISTER_ARG (dp->width_arg_index, TYPE_INT);
235             }
236           else if (*cp >= '0' && *cp <= '9')
237             {
238               size_t width_length;
239
240               dp->width_start = cp;
241               for (; *cp >= '0' && *cp <= '9'; cp++)
242                 ;
243               dp->width_end = cp;
244               width_length = dp->width_end - dp->width_start;
245               if (max_width_length < width_length)
246                 max_width_length = width_length;
247             }
248
249           /* Parse the precision.  */
250           if (*cp == '.')
251             {
252               cp++;
253               if (*cp == '*')
254                 {
255                   dp->precision_start = cp - 1;
256                   cp++;
257                   dp->precision_end = cp;
258                   if (max_precision_length < 2)
259                     max_precision_length = 2;
260
261                   /* Test for positional argument.  */
262                   if (*cp >= '0' && *cp <= '9')
263                     {
264                       const CHAR_T *np;
265
266                       for (np = cp; *np >= '0' && *np <= '9'; np++)
267                         ;
268                       if (*np == '$')
269                         {
270                           size_t n = 0;
271
272                           for (np = cp; *np >= '0' && *np <= '9'; np++)
273                             if (n < SIZE_MAX / 10)
274                               n = 10 * n + (*np - '0');
275                             else
276                               /* n too large for memory.  */
277                               goto error;
278                           if (n == 0)
279                             /* Positional argument 0.  */
280                             goto error;
281                           dp->precision_arg_index = n - 1;
282                           cp = np + 1;
283                         }
284                     }
285                   if (dp->precision_arg_index == ARG_NONE)
286                     {
287                       dp->precision_arg_index = arg_posn++;
288                       if (dp->precision_arg_index == ARG_NONE)
289                         /* arg_posn wrapped around.  */
290                         goto error;
291                     }
292                   REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
293                 }
294               else
295                 {
296                   size_t precision_length;
297
298                   dp->precision_start = cp - 1;
299                   for (; *cp >= '0' && *cp <= '9'; cp++)
300                     ;
301                   dp->precision_end = cp;
302                   precision_length = dp->precision_end - dp->precision_start;
303                   if (max_precision_length < precision_length)
304                     max_precision_length = precision_length;
305                 }
306             }
307
308           {
309             arg_type type;
310
311             /* Parse argument type/size specifiers.  */
312             {
313               int flags = 0;
314
315               for (;;)
316                 {
317                   if (*cp == 'h')
318                     {
319                       flags |= (1 << (flags & 1));
320                       cp++;
321                     }
322                   else if (*cp == 'L')
323                     {
324                       flags |= 4;
325                       cp++;
326                     }
327                   else if (*cp == 'l')
328                     {
329                       flags += 8;
330                       cp++;
331                     }
332 #ifdef HAVE_INTMAX_T
333                   else if (*cp == 'j')
334                     {
335                       if (sizeof (intmax_t) > sizeof (long))
336                         {
337                           /* intmax_t = long long */
338                           flags += 16;
339                         }
340                       else if (sizeof (intmax_t) > sizeof (int))
341                         {
342                           /* intmax_t = long */
343                           flags += 8;
344                         }
345                       cp++;
346                     }
347 #endif
348                   else if (*cp == 'z' || *cp == 'Z')
349                     {
350                       /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
351                          because the warning facility in gcc-2.95.2 understands
352                          only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
353                       if (sizeof (size_t) > sizeof (long))
354                         {
355                           /* size_t = long long */
356                           flags += 16;
357                         }
358                       else if (sizeof (size_t) > sizeof (int))
359                         {
360                           /* size_t = long */
361                           flags += 8;
362                         }
363                       cp++;
364                     }
365                   else if (*cp == 't')
366                     {
367                       if (sizeof (ptrdiff_t) > sizeof (long))
368                         {
369                           /* ptrdiff_t = long long */
370                           flags += 16;
371                         }
372                       else if (sizeof (ptrdiff_t) > sizeof (int))
373                         {
374                           /* ptrdiff_t = long */
375                           flags += 8;
376                         }
377                       cp++;
378                     }
379                   else
380                     break;
381                 }
382
383               /* Read the conversion character.  */
384               c = *cp++;
385               switch (c)
386                 {
387                 case 'd': case 'i':
388 #ifdef HAVE_LONG_LONG
389                   if (flags >= 16 || (flags & 4))
390                     type = TYPE_LONGLONGINT;
391                   else
392 #endif
393                   if (flags >= 8)
394                     type = TYPE_LONGINT;
395                   else if (flags & 2)
396                     type = TYPE_SCHAR;
397                   else if (flags & 1)
398                     type = TYPE_SHORT;
399                   else
400                     type = TYPE_INT;
401                   break;
402                 case 'o': case 'u': case 'x': case 'X':
403 #ifdef HAVE_LONG_LONG
404                   if (flags >= 16 || (flags & 4))
405                     type = TYPE_ULONGLONGINT;
406                   else
407 #endif
408                   if (flags >= 8)
409                     type = TYPE_ULONGINT;
410                   else if (flags & 2)
411                     type = TYPE_UCHAR;
412                   else if (flags & 1)
413                     type = TYPE_USHORT;
414                   else
415                     type = TYPE_UINT;
416                   break;
417                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
418                 case 'a': case 'A':
419 #ifdef HAVE_LONG_DOUBLE
420                   if (flags >= 16 || (flags & 4))
421                     type = TYPE_LONGDOUBLE;
422                   else
423 #endif
424                   type = TYPE_DOUBLE;
425                   break;
426                 case 'c':
427                   if (flags >= 8)
428 #ifdef HAVE_WINT_T
429                     type = TYPE_WIDE_CHAR;
430 #else
431                     goto error;
432 #endif
433                   else
434                     type = TYPE_CHAR;
435                   break;
436 #ifdef HAVE_WINT_T
437                 case 'C':
438                   type = TYPE_WIDE_CHAR;
439                   c = 'c';
440                   break;
441 #endif
442                 case 's':
443                   if (flags >= 8)
444 #ifdef HAVE_WCHAR_T
445                     type = TYPE_WIDE_STRING;
446 #else
447                     goto error;
448 #endif
449                   else
450                     type = TYPE_STRING;
451                   break;
452 #ifdef HAVE_WCHAR_T
453                 case 'S':
454                   type = TYPE_WIDE_STRING;
455                   c = 's';
456                   break;
457 #endif
458                 case 'p':
459                   type = TYPE_POINTER;
460                   break;
461                 case 'n':
462 #ifdef HAVE_LONG_LONG
463                   if (flags >= 16 || (flags & 4))
464                     type = TYPE_COUNT_LONGLONGINT_POINTER;
465                   else
466 #endif
467                   if (flags >= 8)
468                     type = TYPE_COUNT_LONGINT_POINTER;
469                   else if (flags & 2)
470                     type = TYPE_COUNT_SCHAR_POINTER;
471                   else if (flags & 1)
472                     type = TYPE_COUNT_SHORT_POINTER;
473                   else
474                     type = TYPE_COUNT_INT_POINTER;
475                   break;
476                 case '%':
477                   type = TYPE_NONE;
478                   break;
479                 default:
480                   /* Unknown conversion character.  */
481                   goto error;
482                 }
483             }
484
485             if (type != TYPE_NONE)
486               {
487                 dp->arg_index = arg_index;
488                 if (dp->arg_index == ARG_NONE)
489                   {
490                     dp->arg_index = arg_posn++;
491                     if (dp->arg_index == ARG_NONE)
492                       /* arg_posn wrapped around.  */
493                       goto error;
494                   }
495                 REGISTER_ARG (dp->arg_index, type);
496               }
497             dp->conversion = c;
498             dp->dir_end = cp;
499           }
500
501           d->count++;
502           if (d->count >= d_allocated)
503             {
504               DIRECTIVE *memory;
505
506               if (SIZE_MAX / (2 * sizeof (DIRECTIVE)) < d_allocated)
507                 /* Overflow, would lead to out of memory.  */
508                 goto error;
509               d_allocated *= 2;
510               memory = realloc (d->dir, d_allocated * sizeof (DIRECTIVE));
511               if (memory == NULL)
512                 /* Out of memory.  */
513                 goto error;
514               d->dir = memory;
515             }
516         }
517     }
518   d->dir[d->count].dir_start = cp;
519
520   d->max_width_length = max_width_length;
521   d->max_precision_length = max_precision_length;
522   return 0;
523
524 error:
525   if (a->arg)
526     free (a->arg);
527   if (d->dir)
528     free (d->dir);
529   return -1;
530 }
531
532 #undef DIRECTIVES
533 #undef DIRECTIVE
534 #undef CHAR_T
535 #undef PRINTF_PARSE