Moved 1.9 branch to trunk
[gnupg.git] / intl / 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17    USA.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 /* Specification.  */
24 #if WIDE_CHAR_VERSION
25 # include "wprintf-parse.h"
26 #else
27 # include "printf-parse.h"
28 #endif
29
30 /* Get size_t, NULL.  */
31 #include <stddef.h>
32
33 /* Get intmax_t.  */
34 #if HAVE_STDINT_H_WITH_UINTMAX
35 # include <stdint.h>
36 #endif
37 #if HAVE_INTTYPES_H_WITH_UINTMAX
38 # include <inttypes.h>
39 #endif
40
41 /* malloc(), realloc(), free().  */
42 #include <stdlib.h>
43
44 /* Checked size_t computations.  */
45 #include "xsize.h"
46
47 #if WIDE_CHAR_VERSION
48 # define PRINTF_PARSE wprintf_parse
49 # define CHAR_T wchar_t
50 # define DIRECTIVE wchar_t_directive
51 # define DIRECTIVES wchar_t_directives
52 #else
53 # define PRINTF_PARSE printf_parse
54 # define CHAR_T char
55 # define DIRECTIVE char_directive
56 # define DIRECTIVES char_directives
57 #endif
58
59 #ifdef STATIC
60 STATIC
61 #endif
62 int
63 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
64 {
65   const CHAR_T *cp = format;            /* pointer into format */
66   size_t arg_posn = 0;          /* number of regular arguments consumed */
67   size_t d_allocated;                   /* allocated elements of d->dir */
68   size_t a_allocated;                   /* allocated elements of a->arg */
69   size_t max_width_length = 0;
70   size_t max_precision_length = 0;
71
72   d->count = 0;
73   d_allocated = 1;
74   d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
75   if (d->dir == NULL)
76     /* Out of memory.  */
77     return -1;
78
79   a->count = 0;
80   a_allocated = 0;
81   a->arg = NULL;
82
83 #define REGISTER_ARG(_index_,_type_) \
84   {                                                                     \
85     size_t n = (_index_);                                               \
86     if (n >= a_allocated)                                               \
87       {                                                                 \
88         size_t memory_size;                                             \
89         argument *memory;                                               \
90                                                                         \
91         a_allocated = xtimes (a_allocated, 2);                          \
92         if (a_allocated <= n)                                           \
93           a_allocated = xsum (n, 1);                                    \
94         memory_size = xtimes (a_allocated, sizeof (argument));          \
95         if (size_overflow_p (memory_size))                              \
96           /* Overflow, would lead to out of memory.  */                 \
97           goto error;                                                   \
98         memory = (a->arg                                                \
99                   ? realloc (a->arg, memory_size)                       \
100                   : malloc (memory_size));                              \
101         if (memory == NULL)                                             \
102           /* Out of memory.  */                                         \
103           goto error;                                                   \
104         a->arg = memory;                                                \
105       }                                                                 \
106     while (a->count <= n)                                               \
107       a->arg[a->count++].type = TYPE_NONE;                              \
108     if (a->arg[n].type == TYPE_NONE)                                    \
109       a->arg[n].type = (_type_);                                        \
110     else if (a->arg[n].type != (_type_))                                \
111       /* Ambiguous type for positional argument.  */                    \
112       goto error;                                                       \
113   }
114
115   while (*cp != '\0')
116     {
117       CHAR_T c = *cp++;
118       if (c == '%')
119         {
120           size_t arg_index = ARG_NONE;
121           DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
122
123           /* Initialize the next directive.  */
124           dp->dir_start = cp - 1;
125           dp->flags = 0;
126           dp->width_start = NULL;
127           dp->width_end = NULL;
128           dp->width_arg_index = ARG_NONE;
129           dp->precision_start = NULL;
130           dp->precision_end = NULL;
131           dp->precision_arg_index = ARG_NONE;
132           dp->arg_index = ARG_NONE;
133
134           /* Test for positional argument.  */
135           if (*cp >= '0' && *cp <= '9')
136             {
137               const CHAR_T *np;
138
139               for (np = cp; *np >= '0' && *np <= '9'; np++)
140                 ;
141               if (*np == '$')
142                 {
143                   size_t n = 0;
144
145                   for (np = cp; *np >= '0' && *np <= '9'; np++)
146                     n = xsum (xtimes (n, 10), *np - '0');
147                   if (n == 0)
148                     /* Positional argument 0.  */
149                     goto error;
150                   if (size_overflow_p (n))
151                     /* n too large, would lead to out of memory later.  */
152                     goto error;
153                   arg_index = n - 1;
154                   cp = np + 1;
155                 }
156             }
157
158           /* Read the flags.  */
159           for (;;)
160             {
161               if (*cp == '\'')
162                 {
163                   dp->flags |= FLAG_GROUP;
164                   cp++;
165                 }
166               else if (*cp == '-')
167                 {
168                   dp->flags |= FLAG_LEFT;
169                   cp++;
170                 }
171               else if (*cp == '+')
172                 {
173                   dp->flags |= FLAG_SHOWSIGN;
174                   cp++;
175                 }
176               else if (*cp == ' ')
177                 {
178                   dp->flags |= FLAG_SPACE;
179                   cp++;
180                 }
181               else if (*cp == '#')
182                 {
183                   dp->flags |= FLAG_ALT;
184                   cp++;
185                 }
186               else if (*cp == '0')
187                 {
188                   dp->flags |= FLAG_ZERO;
189                   cp++;
190                 }
191               else
192                 break;
193             }
194
195           /* Parse the field width.  */
196           if (*cp == '*')
197             {
198               dp->width_start = cp;
199               cp++;
200               dp->width_end = cp;
201               if (max_width_length < 1)
202                 max_width_length = 1;
203
204               /* Test for positional argument.  */
205               if (*cp >= '0' && *cp <= '9')
206                 {
207                   const CHAR_T *np;
208
209                   for (np = cp; *np >= '0' && *np <= '9'; np++)
210                     ;
211                   if (*np == '$')
212                     {
213                       size_t n = 0;
214
215                       for (np = cp; *np >= '0' && *np <= '9'; np++)
216                         n = xsum (xtimes (n, 10), *np - '0');
217                       if (n == 0)
218                         /* Positional argument 0.  */
219                         goto error;
220                       if (size_overflow_p (n))
221                         /* n too large, would lead to out of memory later.  */
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                             n = xsum (xtimes (n, 10), *np - '0');
274                           if (n == 0)
275                             /* Positional argument 0.  */
276                             goto error;
277                           if (size_overflow_p (n))
278                             /* n too large, would lead to out of memory
279                                later.  */
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               size_t memory_size;
505               DIRECTIVE *memory;
506
507               d_allocated = xtimes (d_allocated, 2);
508               memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
509               if (size_overflow_p (memory_size))
510                 /* Overflow, would lead to out of memory.  */
511                 goto error;
512               memory = realloc (d->dir, memory_size);
513               if (memory == NULL)
514                 /* Out of memory.  */
515                 goto error;
516               d->dir = memory;
517             }
518         }
519     }
520   d->dir[d->count].dir_start = cp;
521
522   d->max_width_length = max_width_length;
523   d->max_precision_length = max_precision_length;
524   return 0;
525
526 error:
527   if (a->arg)
528     free (a->arg);
529   if (d->dir)
530     free (d->dir);
531   return -1;
532 }
533
534 #undef DIRECTIVES
535 #undef DIRECTIVE
536 #undef CHAR_T
537 #undef PRINTF_PARSE