PIPS
printf-parse.c
Go to the documentation of this file.
1 /* Formatted output to strings.
2  Copyright (C) 1999-2000, 2002-2003, 2006-2014 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
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)
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))
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)
538  else if (flags & 2)
540  else if (flags & 1)
542  else
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
#define error(fun, msg)
NewGen interface with C3 type Psysteme for PIPS project.
Definition: Psc.c:78
void const char const char const int
struct _newgen_struct_type_ * type
void * malloc(YYSIZE_T)
void free(void *)
#define N_DIRECT_ALLOC_ARGUMENTS
Number of directly allocated arguments (no malloc() needed).
Definition: printf-args.h:139
arg_type
Get size_t.
Definition: printf-args.h:50
@ TYPE_DOUBLE
Definition: printf-args.h:64
@ TYPE_NONE
Definition: printf-args.h:51
@ TYPE_SHORT
Definition: printf-args.h:54
@ TYPE_CHAR
Definition: printf-args.h:66
@ TYPE_USHORT
Definition: printf-args.h:55
@ TYPE_INT
Definition: printf-args.h:56
@ TYPE_LONGINT
Definition: printf-args.h:58
@ TYPE_COUNT_SCHAR_POINTER
Definition: printf-args.h:75
@ TYPE_POINTER
Definition: printf-args.h:74
@ TYPE_SCHAR
Definition: printf-args.h:52
@ TYPE_LONGDOUBLE
Definition: printf-args.h:65
@ TYPE_COUNT_SHORT_POINTER
Definition: printf-args.h:76
@ TYPE_COUNT_LONGINT_POINTER
Definition: printf-args.h:78
@ TYPE_COUNT_INT_POINTER
Definition: printf-args.h:77
@ TYPE_UINT
Definition: printf-args.h:57
@ TYPE_ULONGINT
Definition: printf-args.h:59
@ TYPE_STRING
Definition: printf-args.h:70
@ TYPE_UCHAR
Definition: printf-args.h:53
#define DIRECTIVES
Definition: printf-parse.c:44
#define DIRECTIVE
Definition: printf-parse.c:43
#define REGISTER_ARG(_index_, _type_)
#define PRINTF_PARSE
Formatted output to strings.
Definition: printf-parse.c:41
#define CHAR_T
Definition: printf-parse.c:42
#define FLAG_GROUP
Parse printf format string.
Definition: printf-parse.h:33
#define FLAG_LEFT
Definition: printf-parse.h:34
#define ARG_NONE
arg_index value indicating that no argument is consumed.
Definition: printf-parse.h:44
#define FLAG_SHOWSIGN
Definition: printf-parse.h:35
#define FLAG_ZERO
Definition: printf-parse.h:38
#define FLAG_ALT
Definition: printf-parse.h:37
#define N_DIRECT_ALLOC_DIRECTIVES
xxx_directive: A parsed directive.
Definition: printf-parse.h:50
#define FLAG_SPACE
Definition: printf-parse.h:36
Pvecteur cp
pointeur sur l'egalite ou l'inegalite courante
Definition: sc_read.c:87
#define intmax_t
Definition: stdint.in.h:316
size_t count
Definition: printf-args.h:143
argument * arg
Definition: printf-args.h:144
argument direct_alloc_arg[N_DIRECT_ALLOC_ARGUMENTS]
Definition: printf-args.h:145
#define size_overflow_p(SIZE)
Check for overflow.
Definition: xsize.h:109
#define xtimes(N, ELSIZE)
Multiplication of a count with an element size, with overflow check.
Definition: xsize.h:105
XSIZE_INLINE size_t xsum(size_t size1, size_t size2)
Sum of two sizes, with overflow check.
Definition: xsize.h:63