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