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
PRINTF_PARSE(const CHAR_T * format,DIRECTIVES * d,arguments * a)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   free (a->arg);
528   free (d->dir);
529   return -1;
530 }
531 
532 #undef DIRECTIVES
533 #undef DIRECTIVE
534 #undef CHAR_T
535 #undef PRINTF_PARSE
536