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