Switched to GPLv3.
[gnupg.git] / intl / printf-parse.c
1 /* Formatted output to strings.
2    Copyright (C) 1999-2000, 2002-2003, 2006 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU Library General Public License as published
6    by 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 GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17    USA.  */
18
19 #include <config.h>
20
21 /* Specification.  */
22 #if WIDE_CHAR_VERSION
23 # include "wprintf-parse.h"
24 #else
25 # include "printf-parse.h"
26 #endif
27
28 /* Get size_t, NULL.  */
29 #include <stddef.h>
30
31 /* Get intmax_t.  */
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
39 /* malloc(), realloc(), free().  */
40 #include <stdlib.h>
41
42 /* Checked size_t computations.  */
43 #include "xsize.h"
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 = xtimes (a_allocated, 2);                          \
90         if (a_allocated <= n)                                           \
91           a_allocated = xsum (n, 1);                                    \
92         memory_size = xtimes (a_allocated, sizeof (argument));          \
93         if (size_overflow_p (memory_size))                              \
94           /* Overflow, would lead to out of memory.  */                 \
95           goto error;                                                   \
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                     n = xsum (xtimes (n, 10), *np - '0');
145                   if (n == 0)
146                     /* Positional argument 0.  */
147                     goto error;
148                   if (size_overflow_p (n))
149                     /* n too large, would lead to out of memory later.  */
150                     goto error;
151                   arg_index = n - 1;
152                   cp = np + 1;
153                 }
154             }
155
156           /* Read the flags.  */
157           for (;;)
158             {
159               if (*cp == '\'')
160                 {
161                   dp->flags |= FLAG_GROUP;
162                   cp++;
163                 }
164               else if (*cp == '-')
165                 {
166                   dp->flags |= FLAG_LEFT;
167                   cp++;
168                 }
169               else if (*cp == '+')
170                 {
171                   dp->flags |= FLAG_SHOWSIGN;
172                   cp++;
173                 }
174               else if (*cp == ' ')
175                 {
176                   dp->flags |= FLAG_SPACE;
177                   cp++;
178                 }
179               else if (*cp == '#')
180                 {
181                   dp->flags |= FLAG_ALT;
182                   cp++;
183                 }
184               else if (*cp == '0')
185                 {
186                   dp->flags |= FLAG_ZERO;
187                   cp++;
188                 }
189               else
190                 break;
191             }
192
193           /* Parse the field width.  */
194           if (*cp == '*')
195             {
196               dp->width_start = cp;
197               cp++;
198               dp->width_end = cp;
199               if (max_width_length < 1)
200                 max_width_length = 1;
201
202               /* Test for positional argument.  */
203               if (*cp >= '0' && *cp <= '9')
204                 {
205                   const CHAR_T *np;
206
207                   for (np = cp; *np >= '0' && *np <= '9'; np++)
208                     ;
209                   if (*np == '$')
210                     {
211                       size_t n = 0;
212
213                       for (np = cp; *np >= '0' && *np <= '9'; np++)
214                         n = xsum (xtimes (n, 10), *np - '0');
215                       if (n == 0)
216                         /* Positional argument 0.  */
217                         goto error;
218                       if (size_overflow_p (n))
219                         /* n too large, would lead to out of memory later.  */
220                         goto error;
221                       dp->width_arg_index = n - 1;
222                       cp = np + 1;
223                     }
224                 }
225               if (dp->width_arg_index == ARG_NONE)
226                 {
227                   dp->width_arg_index = arg_posn++;
228                   if (dp->width_arg_index == ARG_NONE)
229                     /* arg_posn wrapped around.  */
230                     goto error;
231                 }
232               REGISTER_ARG (dp->width_arg_index, TYPE_INT);
233             }
234           else if (*cp >= '0' && *cp <= '9')
235             {
236               size_t width_length;
237
238               dp->width_start = cp;
239               for (; *cp >= '0' && *cp <= '9'; cp++)
240                 ;
241               dp->width_end = cp;
242               width_length = dp->width_end - dp->width_start;
243               if (max_width_length < width_length)
244                 max_width_length = width_length;
245             }
246
247           /* Parse the precision.  */
248           if (*cp == '.')
249             {
250               cp++;
251               if (*cp == '*')
252                 {
253                   dp->precision_start = cp - 1;
254                   cp++;
255                   dp->precision_end = cp;
256                   if (max_precision_length < 2)
257                     max_precision_length = 2;
258
259                   /* Test for positional argument.  */
260                   if (*cp >= '0' && *cp <= '9')
261                     {
262                       const CHAR_T *np;
263
264                       for (np = cp; *np >= '0' && *np <= '9'; np++)
265                         ;
266                       if (*np == '$')
267                         {
268                           size_t n = 0;
269
270                           for (np = cp; *np >= '0' && *np <= '9'; np++)
271                             n = xsum (xtimes (n, 10), *np - '0');
272                           if (n == 0)
273                             /* Positional argument 0.  */
274                             goto error;
275                           if (size_overflow_p (n))
276                             /* n too large, would lead to out of memory
277                                later.  */
278                             goto error;
279                           dp->precision_arg_index = n - 1;
280                           cp = np + 1;
281                         }
282                     }
283                   if (dp->precision_arg_index == ARG_NONE)
284                     {
285                       dp->precision_arg_index = arg_posn++;
286                       if (dp->precision_arg_index == ARG_NONE)
287                         /* arg_posn wrapped around.  */
288                         goto error;
289                     }
290                   REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
291                 }
292               else
293                 {
294                   size_t precision_length;
295
296                   dp->precision_start = cp - 1;
297                   for (; *cp >= '0' && *cp <= '9'; cp++)
298                     ;
299                   dp->precision_end = cp;
300                   precision_length = dp->precision_end - dp->precision_start;
301                   if (max_precision_length < precision_length)
302                     max_precision_length = precision_length;
303                 }
304             }
305
306           {
307             arg_type type;
308
309             /* Parse argument type/size specifiers.  */
310             {
311               int flags = 0;
312
313               for (;;)
314                 {
315                   if (*cp == 'h')
316                     {
317                       flags |= (1 << (flags & 1));
318                       cp++;
319                     }
320                   else if (*cp == 'L')
321                     {
322                       flags |= 4;
323                       cp++;
324                     }
325                   else if (*cp == 'l')
326                     {
327                       flags += 8;
328                       cp++;
329                     }
330 #ifdef HAVE_INTMAX_T
331                   else if (*cp == 'j')
332                     {
333                       if (sizeof (intmax_t) > sizeof (long))
334                         {
335                           /* intmax_t = long long */
336                           flags += 16;
337                         }
338                       else if (sizeof (intmax_t) > sizeof (int))
339                         {
340                           /* intmax_t = long */
341                           flags += 8;
342                         }
343                       cp++;
344                     }
345 #endif
346                   else if (*cp == 'z' || *cp == 'Z')
347                     {
348                       /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
349                          because the warning facility in gcc-2.95.2 understands
350                          only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
351                       if (sizeof (size_t) > sizeof (long))
352                         {
353                           /* size_t = long long */
354                           flags += 16;
355                         }
356                       else if (sizeof (size_t) > sizeof (int))
357                         {
358                           /* size_t = long */
359                           flags += 8;
360                         }
361                       cp++;
362                     }
363                   else if (*cp == 't')
364                     {
365                       if (sizeof (ptrdiff_t) > sizeof (long))
366                         {
367                           /* ptrdiff_t = long long */
368                           flags += 16;
369                         }
370                       else if (sizeof (ptrdiff_t) > sizeof (int))
371                         {
372                           /* ptrdiff_t = long */
373                           flags += 8;
374                         }
375                       cp++;
376                     }
377                   else
378                     break;
379                 }
380
381               /* Read the conversion character.  */
382               c = *cp++;
383               switch (c)
384                 {
385                 case 'd': case 'i':
386 #ifdef HAVE_LONG_LONG_INT
387                   /* If 'long long' exists and is larger than 'long':  */
388                   if (flags >= 16 || (flags & 4))
389                     type = TYPE_LONGLONGINT;
390                   else
391 #endif
392                   /* If 'long long' exists and is the same as 'long', we parse
393                      "lld" into TYPE_LONGINT.  */
394                   if (flags >= 8)
395                     type = TYPE_LONGINT;
396                   else if (flags & 2)
397                     type = TYPE_SCHAR;
398                   else if (flags & 1)
399                     type = TYPE_SHORT;
400                   else
401                     type = TYPE_INT;
402                   break;
403                 case 'o': case 'u': case 'x': case 'X':
404 #ifdef HAVE_LONG_LONG_INT
405                   /* If 'long long' exists and is larger than 'long':  */
406                   if (flags >= 16 || (flags & 4))
407                     type = TYPE_ULONGLONGINT;
408                   else
409 #endif
410                   /* If 'unsigned long long' exists and is the same as
411                      'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
412                   if (flags >= 8)
413                     type = TYPE_ULONGINT;
414                   else if (flags & 2)
415                     type = TYPE_UCHAR;
416                   else if (flags & 1)
417                     type = TYPE_USHORT;
418                   else
419                     type = TYPE_UINT;
420                   break;
421                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
422                 case 'a': case 'A':
423 #ifdef HAVE_LONG_DOUBLE
424                   if (flags >= 16 || (flags & 4))
425                     type = TYPE_LONGDOUBLE;
426                   else
427 #endif
428                   type = TYPE_DOUBLE;
429                   break;
430                 case 'c':
431                   if (flags >= 8)
432 #ifdef HAVE_WINT_T
433                     type = TYPE_WIDE_CHAR;
434 #else
435                     goto error;
436 #endif
437                   else
438                     type = TYPE_CHAR;
439                   break;
440 #ifdef HAVE_WINT_T
441                 case 'C':
442                   type = TYPE_WIDE_CHAR;
443                   c = 'c';
444                   break;
445 #endif
446                 case 's':
447                   if (flags >= 8)
448 #ifdef HAVE_WCHAR_T
449                     type = TYPE_WIDE_STRING;
450 #else
451                     goto error;
452 #endif
453                   else
454                     type = TYPE_STRING;
455                   break;
456 #ifdef HAVE_WCHAR_T
457                 case 'S':
458                   type = TYPE_WIDE_STRING;
459                   c = 's';
460                   break;
461 #endif
462                 case 'p':
463                   type = TYPE_POINTER;
464                   break;
465                 case 'n':
466 #ifdef HAVE_LONG_LONG_INT
467                   /* If 'long long' exists and is larger than 'long':  */
468                   if (flags >= 16 || (flags & 4))
469                     type = TYPE_COUNT_LONGLONGINT_POINTER;
470                   else
471 #endif
472                   /* If 'long long' exists and is the same as 'long', we parse
473                      "lln" into TYPE_COUNT_LONGINT_POINTER.  */
474                   if (flags >= 8)
475                     type = TYPE_COUNT_LONGINT_POINTER;
476                   else if (flags & 2)
477                     type = TYPE_COUNT_SCHAR_POINTER;
478                   else if (flags & 1)
479                     type = TYPE_COUNT_SHORT_POINTER;
480                   else
481                     type = TYPE_COUNT_INT_POINTER;
482                   break;
483                 case '%':
484                   type = TYPE_NONE;
485                   break;
486                 default:
487                   /* Unknown conversion character.  */
488                   goto error;
489                 }
490             }
491
492             if (type != TYPE_NONE)
493               {
494                 dp->arg_index = arg_index;
495                 if (dp->arg_index == ARG_NONE)
496                   {
497                     dp->arg_index = arg_posn++;
498                     if (dp->arg_index == ARG_NONE)
499                       /* arg_posn wrapped around.  */
500                       goto error;
501                   }
502                 REGISTER_ARG (dp->arg_index, type);
503               }
504             dp->conversion = c;
505             dp->dir_end = cp;
506           }
507
508           d->count++;
509           if (d->count >= d_allocated)
510             {
511               size_t memory_size;
512               DIRECTIVE *memory;
513
514               d_allocated = xtimes (d_allocated, 2);
515               memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
516               if (size_overflow_p (memory_size))
517                 /* Overflow, would lead to out of memory.  */
518                 goto error;
519               memory = realloc (d->dir, memory_size);
520               if (memory == NULL)
521                 /* Out of memory.  */
522                 goto error;
523               d->dir = memory;
524             }
525         }
526     }
527   d->dir[d->count].dir_start = cp;
528
529   d->max_width_length = max_width_length;
530   d->max_precision_length = max_precision_length;
531   return 0;
532
533 error:
534   if (a->arg)
535     free (a->arg);
536   if (d->dir)
537     free (d->dir);
538   return -1;
539 }
540
541 #undef DIRECTIVES
542 #undef DIRECTIVE
543 #undef CHAR_T
544 #undef PRINTF_PARSE