• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Formatted output to strings.
2    Copyright (C) 1999-2000, 2002-2003, 2006-2012 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 3, 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, see <http://www.gnu.org/licenses/>.  */
16 
17 /* This file can be parametrized with the following macros:
18      CHAR_T             The element type of the format string.
19      CHAR_T_ONLY_ASCII  Set to 1 to enable verification that all characters
20                         in the format string are ASCII.
21      DIRECTIVE          Structure denoting a format directive.
22                         Depends on CHAR_T.
23      DIRECTIVES         Structure denoting the set of format directives of a
24                         format string.  Depends on CHAR_T.
25      PRINTF_PARSE       Function that parses a format string.
26                         Depends on CHAR_T.
27      STATIC             Set to 'static' to declare the function static.
28      ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.  */
29 
30 #ifndef PRINTF_PARSE
31 # include <config.h>
32 #endif
33 
34 /* Specification.  */
35 #ifndef PRINTF_PARSE
36 # include "printf-parse.h"
37 #endif
38 
39 /* Default parameters.  */
40 #ifndef PRINTF_PARSE
41 # define PRINTF_PARSE printf_parse
42 # define CHAR_T char
43 # define DIRECTIVE char_directive
44 # define DIRECTIVES char_directives
45 #endif
46 
47 /* Get size_t, NULL.  */
48 #include <stddef.h>
49 
50 /* Get intmax_t.  */
51 #if defined IN_LIBINTL || defined IN_LIBASPRINTF
52 # if HAVE_STDINT_H_WITH_UINTMAX
53 #  include <stdint.h>
54 # endif
55 # if HAVE_INTTYPES_H_WITH_UINTMAX
56 #  include <inttypes.h>
57 # endif
58 #else
59 # include <stdint.h>
60 #endif
61 
62 /* malloc(), realloc(), free().  */
63 #include <stdlib.h>
64 
65 /* memcpy().  */
66 #include <string.h>
67 
68 /* errno.  */
69 #include <errno.h>
70 
71 /* Checked size_t computations.  */
72 #include "xsize.h"
73 
74 #if CHAR_T_ONLY_ASCII
75 /* c_isascii().  */
76 # include "c-ctype.h"
77 #endif
78 
79 #ifdef STATIC
80 STATIC
81 #endif
82 int
PRINTF_PARSE(const CHAR_T * format,DIRECTIVES * d,arguments * a)83 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
84 {
85   const CHAR_T *cp = format;    /* pointer into format */
86   size_t arg_posn = 0;          /* number of regular arguments consumed */
87   size_t d_allocated;           /* allocated elements of d->dir */
88   size_t a_allocated;           /* allocated elements of a->arg */
89   size_t max_width_length = 0;
90   size_t max_precision_length = 0;
91 
92   d->count = 0;
93   d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
94   d->dir = d->direct_alloc_dir;
95 
96   a->count = 0;
97   a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
98   a->arg = a->direct_alloc_arg;
99 
100 #define REGISTER_ARG(_index_,_type_) \
101   {                                                                     \
102     size_t n = (_index_);                                               \
103     if (n >= a_allocated)                                               \
104       {                                                                 \
105         size_t memory_size;                                             \
106         argument *memory;                                               \
107                                                                         \
108         a_allocated = xtimes (a_allocated, 2);                          \
109         if (a_allocated <= n)                                           \
110           a_allocated = xsum (n, 1);                                    \
111         memory_size = xtimes (a_allocated, sizeof (argument));          \
112         if (size_overflow_p (memory_size))                              \
113           /* Overflow, would lead to out of memory.  */                 \
114           goto out_of_memory;                                           \
115         memory = (argument *) (a->arg != a->direct_alloc_arg            \
116                                ? realloc (a->arg, memory_size)          \
117                                : malloc (memory_size));                 \
118         if (memory == NULL)                                             \
119           /* Out of memory.  */                                         \
120           goto out_of_memory;                                           \
121         if (a->arg == a->direct_alloc_arg)                              \
122           memcpy (memory, a->arg, a->count * sizeof (argument));        \
123         a->arg = memory;                                                \
124       }                                                                 \
125     while (a->count <= n)                                               \
126       a->arg[a->count++].type = TYPE_NONE;                              \
127     if (a->arg[n].type == TYPE_NONE)                                    \
128       a->arg[n].type = (_type_);                                        \
129     else if (a->arg[n].type != (_type_))                                \
130       /* Ambiguous type for positional argument.  */                    \
131       goto error;                                                       \
132   }
133 
134   while (*cp != '\0')
135     {
136       CHAR_T c = *cp++;
137       if (c == '%')
138         {
139           size_t arg_index = ARG_NONE;
140           DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
141 
142           /* Initialize the next directive.  */
143           dp->dir_start = cp - 1;
144           dp->flags = 0;
145           dp->width_start = NULL;
146           dp->width_end = NULL;
147           dp->width_arg_index = ARG_NONE;
148           dp->precision_start = NULL;
149           dp->precision_end = NULL;
150           dp->precision_arg_index = ARG_NONE;
151           dp->arg_index = ARG_NONE;
152 
153           /* Test for positional argument.  */
154           if (*cp >= '0' && *cp <= '9')
155             {
156               const CHAR_T *np;
157 
158               for (np = cp; *np >= '0' && *np <= '9'; np++)
159                 ;
160               if (*np == '$')
161                 {
162                   size_t n = 0;
163 
164                   for (np = cp; *np >= '0' && *np <= '9'; np++)
165                     n = xsum (xtimes (n, 10), *np - '0');
166                   if (n == 0)
167                     /* Positional argument 0.  */
168                     goto error;
169                   if (size_overflow_p (n))
170                     /* n too large, would lead to out of memory later.  */
171                     goto error;
172                   arg_index = n - 1;
173                   cp = np + 1;
174                 }
175             }
176 
177           /* Read the flags.  */
178           for (;;)
179             {
180               if (*cp == '\'')
181                 {
182                   dp->flags |= FLAG_GROUP;
183                   cp++;
184                 }
185               else if (*cp == '-')
186                 {
187                   dp->flags |= FLAG_LEFT;
188                   cp++;
189                 }
190               else if (*cp == '+')
191                 {
192                   dp->flags |= FLAG_SHOWSIGN;
193                   cp++;
194                 }
195               else if (*cp == ' ')
196                 {
197                   dp->flags |= FLAG_SPACE;
198                   cp++;
199                 }
200               else if (*cp == '#')
201                 {
202                   dp->flags |= FLAG_ALT;
203                   cp++;
204                 }
205               else if (*cp == '0')
206                 {
207                   dp->flags |= FLAG_ZERO;
208                   cp++;
209                 }
210 #if __GLIBC__ >= 2 && !defined __UCLIBC__
211               else if (*cp == 'I')
212                 {
213                   dp->flags |= FLAG_LOCALIZED;
214                   cp++;
215                 }
216 #endif
217               else
218                 break;
219             }
220 
221           /* Parse the field width.  */
222           if (*cp == '*')
223             {
224               dp->width_start = cp;
225               cp++;
226               dp->width_end = cp;
227               if (max_width_length < 1)
228                 max_width_length = 1;
229 
230               /* Test for positional argument.  */
231               if (*cp >= '0' && *cp <= '9')
232                 {
233                   const CHAR_T *np;
234 
235                   for (np = cp; *np >= '0' && *np <= '9'; np++)
236                     ;
237                   if (*np == '$')
238                     {
239                       size_t n = 0;
240 
241                       for (np = cp; *np >= '0' && *np <= '9'; np++)
242                         n = xsum (xtimes (n, 10), *np - '0');
243                       if (n == 0)
244                         /* Positional argument 0.  */
245                         goto error;
246                       if (size_overflow_p (n))
247                         /* n too large, would lead to out of memory later.  */
248                         goto error;
249                       dp->width_arg_index = n - 1;
250                       cp = np + 1;
251                     }
252                 }
253               if (dp->width_arg_index == ARG_NONE)
254                 {
255                   dp->width_arg_index = arg_posn++;
256                   if (dp->width_arg_index == ARG_NONE)
257                     /* arg_posn wrapped around.  */
258                     goto error;
259                 }
260               REGISTER_ARG (dp->width_arg_index, TYPE_INT);
261             }
262           else if (*cp >= '0' && *cp <= '9')
263             {
264               size_t width_length;
265 
266               dp->width_start = cp;
267               for (; *cp >= '0' && *cp <= '9'; cp++)
268                 ;
269               dp->width_end = cp;
270               width_length = dp->width_end - dp->width_start;
271               if (max_width_length < width_length)
272                 max_width_length = width_length;
273             }
274 
275           /* Parse the precision.  */
276           if (*cp == '.')
277             {
278               cp++;
279               if (*cp == '*')
280                 {
281                   dp->precision_start = cp - 1;
282                   cp++;
283                   dp->precision_end = cp;
284                   if (max_precision_length < 2)
285                     max_precision_length = 2;
286 
287                   /* Test for positional argument.  */
288                   if (*cp >= '0' && *cp <= '9')
289                     {
290                       const CHAR_T *np;
291 
292                       for (np = cp; *np >= '0' && *np <= '9'; np++)
293                         ;
294                       if (*np == '$')
295                         {
296                           size_t n = 0;
297 
298                           for (np = cp; *np >= '0' && *np <= '9'; np++)
299                             n = xsum (xtimes (n, 10), *np - '0');
300                           if (n == 0)
301                             /* Positional argument 0.  */
302                             goto error;
303                           if (size_overflow_p (n))
304                             /* n too large, would lead to out of memory
305                                later.  */
306                             goto error;
307                           dp->precision_arg_index = n - 1;
308                           cp = np + 1;
309                         }
310                     }
311                   if (dp->precision_arg_index == ARG_NONE)
312                     {
313                       dp->precision_arg_index = arg_posn++;
314                       if (dp->precision_arg_index == ARG_NONE)
315                         /* arg_posn wrapped around.  */
316                         goto error;
317                     }
318                   REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
319                 }
320               else
321                 {
322                   size_t precision_length;
323 
324                   dp->precision_start = cp - 1;
325                   for (; *cp >= '0' && *cp <= '9'; cp++)
326                     ;
327                   dp->precision_end = cp;
328                   precision_length = dp->precision_end - dp->precision_start;
329                   if (max_precision_length < precision_length)
330                     max_precision_length = precision_length;
331                 }
332             }
333 
334           {
335             arg_type type;
336 
337             /* Parse argument type/size specifiers.  */
338             {
339               int flags = 0;
340 
341               for (;;)
342                 {
343                   if (*cp == 'h')
344                     {
345                       flags |= (1 << (flags & 1));
346                       cp++;
347                     }
348                   else if (*cp == 'L')
349                     {
350                       flags |= 4;
351                       cp++;
352                     }
353                   else if (*cp == 'l')
354                     {
355                       flags += 8;
356                       cp++;
357                     }
358                   else if (*cp == 'j')
359                     {
360                       if (sizeof (intmax_t) > sizeof (long))
361                         {
362                           /* intmax_t = long long */
363                           flags += 16;
364                         }
365                       else if (sizeof (intmax_t) > sizeof (int))
366                         {
367                           /* intmax_t = long */
368                           flags += 8;
369                         }
370                       cp++;
371                     }
372                   else if (*cp == 'z' || *cp == 'Z')
373                     {
374                       /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
375                          because the warning facility in gcc-2.95.2 understands
376                          only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
377                       if (sizeof (size_t) > sizeof (long))
378                         {
379                           /* size_t = long long */
380                           flags += 16;
381                         }
382                       else if (sizeof (size_t) > sizeof (int))
383                         {
384                           /* size_t = long */
385                           flags += 8;
386                         }
387                       cp++;
388                     }
389                   else if (*cp == 't')
390                     {
391                       if (sizeof (ptrdiff_t) > sizeof (long))
392                         {
393                           /* ptrdiff_t = long long */
394                           flags += 16;
395                         }
396                       else if (sizeof (ptrdiff_t) > sizeof (int))
397                         {
398                           /* ptrdiff_t = long */
399                           flags += 8;
400                         }
401                       cp++;
402                     }
403 #if defined __APPLE__ && defined __MACH__
404                   /* On Mac OS X 10.3, PRIdMAX is defined as "qd".
405                      We cannot change it to "lld" because PRIdMAX must also
406                      be understood by the system's printf routines.  */
407                   else if (*cp == 'q')
408                     {
409                       if (64 / 8 > sizeof (long))
410                         {
411                           /* int64_t = long long */
412                           flags += 16;
413                         }
414                       else
415                         {
416                           /* int64_t = long */
417                           flags += 8;
418                         }
419                       cp++;
420                     }
421 #endif
422 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
423                   /* On native Windows, PRIdMAX is defined as "I64d".
424                      We cannot change it to "lld" because PRIdMAX must also
425                      be understood by the system's printf routines.  */
426                   else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
427                     {
428                       if (64 / 8 > sizeof (long))
429                         {
430                           /* __int64 = long long */
431                           flags += 16;
432                         }
433                       else
434                         {
435                           /* __int64 = long */
436                           flags += 8;
437                         }
438                       cp += 3;
439                     }
440 #endif
441                   else
442                     break;
443                 }
444 
445               /* Read the conversion character.  */
446               c = *cp++;
447               switch (c)
448                 {
449                 case 'd': case 'i':
450 #if HAVE_LONG_LONG_INT
451                   /* If 'long long' exists and is larger than 'long':  */
452                   if (flags >= 16 || (flags & 4))
453                     type = TYPE_LONGLONGINT;
454                   else
455 #endif
456                   /* If 'long long' exists and is the same as 'long', we parse
457                      "lld" into TYPE_LONGINT.  */
458                   if (flags >= 8)
459                     type = TYPE_LONGINT;
460                   else if (flags & 2)
461                     type = TYPE_SCHAR;
462                   else if (flags & 1)
463                     type = TYPE_SHORT;
464                   else
465                     type = TYPE_INT;
466                   break;
467                 case 'o': case 'u': case 'x': case 'X':
468 #if HAVE_LONG_LONG_INT
469                   /* If 'long long' exists and is larger than 'long':  */
470                   if (flags >= 16 || (flags & 4))
471                     type = TYPE_ULONGLONGINT;
472                   else
473 #endif
474                   /* If 'unsigned long long' exists and is the same as
475                      'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
476                   if (flags >= 8)
477                     type = TYPE_ULONGINT;
478                   else if (flags & 2)
479                     type = TYPE_UCHAR;
480                   else if (flags & 1)
481                     type = TYPE_USHORT;
482                   else
483                     type = TYPE_UINT;
484                   break;
485                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
486                 case 'a': case 'A':
487                   if (flags >= 16 || (flags & 4))
488                     type = TYPE_LONGDOUBLE;
489                   else
490                     type = TYPE_DOUBLE;
491                   break;
492                 case 'c':
493                   if (flags >= 8)
494 #if HAVE_WINT_T
495                     type = TYPE_WIDE_CHAR;
496 #else
497                     goto error;
498 #endif
499                   else
500                     type = TYPE_CHAR;
501                   break;
502 #if HAVE_WINT_T
503                 case 'C':
504                   type = TYPE_WIDE_CHAR;
505                   c = 'c';
506                   break;
507 #endif
508                 case 's':
509                   if (flags >= 8)
510 #if HAVE_WCHAR_T
511                     type = TYPE_WIDE_STRING;
512 #else
513                     goto error;
514 #endif
515                   else
516                     type = TYPE_STRING;
517                   break;
518 #if HAVE_WCHAR_T
519                 case 'S':
520                   type = TYPE_WIDE_STRING;
521                   c = 's';
522                   break;
523 #endif
524                 case 'p':
525                   type = TYPE_POINTER;
526                   break;
527                 case 'n':
528 #if HAVE_LONG_LONG_INT
529                   /* If 'long long' exists and is larger than 'long':  */
530                   if (flags >= 16 || (flags & 4))
531                     type = TYPE_COUNT_LONGLONGINT_POINTER;
532                   else
533 #endif
534                   /* If 'long long' exists and is the same as 'long', we parse
535                      "lln" into TYPE_COUNT_LONGINT_POINTER.  */
536                   if (flags >= 8)
537                     type = TYPE_COUNT_LONGINT_POINTER;
538                   else if (flags & 2)
539                     type = TYPE_COUNT_SCHAR_POINTER;
540                   else if (flags & 1)
541                     type = TYPE_COUNT_SHORT_POINTER;
542                   else
543                     type = TYPE_COUNT_INT_POINTER;
544                   break;
545 #if ENABLE_UNISTDIO
546                 /* The unistdio extensions.  */
547                 case 'U':
548                   if (flags >= 16)
549                     type = TYPE_U32_STRING;
550                   else if (flags >= 8)
551                     type = TYPE_U16_STRING;
552                   else
553                     type = TYPE_U8_STRING;
554                   break;
555 #endif
556                 case '%':
557                   type = TYPE_NONE;
558                   break;
559                 default:
560                   /* Unknown conversion character.  */
561                   goto error;
562                 }
563             }
564 
565             if (type != TYPE_NONE)
566               {
567                 dp->arg_index = arg_index;
568                 if (dp->arg_index == ARG_NONE)
569                   {
570                     dp->arg_index = arg_posn++;
571                     if (dp->arg_index == ARG_NONE)
572                       /* arg_posn wrapped around.  */
573                       goto error;
574                   }
575                 REGISTER_ARG (dp->arg_index, type);
576               }
577             dp->conversion = c;
578             dp->dir_end = cp;
579           }
580 
581           d->count++;
582           if (d->count >= d_allocated)
583             {
584               size_t memory_size;
585               DIRECTIVE *memory;
586 
587               d_allocated = xtimes (d_allocated, 2);
588               memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
589               if (size_overflow_p (memory_size))
590                 /* Overflow, would lead to out of memory.  */
591                 goto out_of_memory;
592               memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
593                                       ? realloc (d->dir, memory_size)
594                                       : malloc (memory_size));
595               if (memory == NULL)
596                 /* Out of memory.  */
597                 goto out_of_memory;
598               if (d->dir == d->direct_alloc_dir)
599                 memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
600               d->dir = memory;
601             }
602         }
603 #if CHAR_T_ONLY_ASCII
604       else if (!c_isascii (c))
605         {
606           /* Non-ASCII character.  Not supported.  */
607           goto error;
608         }
609 #endif
610     }
611   d->dir[d->count].dir_start = cp;
612 
613   d->max_width_length = max_width_length;
614   d->max_precision_length = max_precision_length;
615   return 0;
616 
617 error:
618   if (a->arg != a->direct_alloc_arg)
619     free (a->arg);
620   if (d->dir != d->direct_alloc_dir)
621     free (d->dir);
622   errno = EINVAL;
623   return -1;
624 
625 out_of_memory:
626   if (a->arg != a->direct_alloc_arg)
627     free (a->arg);
628   if (d->dir != d->direct_alloc_dir)
629     free (d->dir);
630   errno = ENOMEM;
631   return -1;
632 }
633 
634 #undef PRINTF_PARSE
635 #undef DIRECTIVES
636 #undef DIRECTIVE
637 #undef CHAR_T_ONLY_ASCII
638 #undef CHAR_T
639