• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "g-gnulib.h"
24 
25 /* Specification.  */
26 #include "printf-parse.h"
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 #ifdef STATIC
43 STATIC
44 #endif
45 int
printf_parse(const char * format,char_directives * d,arguments * a)46 printf_parse (const char *format, char_directives *d, arguments *a)
47 {
48   const char *cp = format;		/* pointer into format */
49   int arg_posn = 0;		/* number of regular arguments consumed */
50   unsigned int d_allocated;		/* allocated elements of d->dir */
51   unsigned int a_allocated;		/* allocated elements of a->arg */
52   unsigned int max_width_length = 0;
53   unsigned int max_precision_length = 0;
54 
55   d->count = 0;
56   d_allocated = 1;
57   d->dir = malloc (d_allocated * sizeof (char_directive));
58   if (d->dir == NULL)
59     /* Out of memory.  */
60     return -1;
61 
62   a->count = 0;
63   a_allocated = 0;
64   a->arg = NULL;
65 
66 #define REGISTER_ARG(_index_,_type_) \
67   {									\
68     unsigned int n = (_index_);						\
69     if (n >= a_allocated)						\
70       {									\
71 	argument *memory;						\
72 	a_allocated = 2 * a_allocated;					\
73 	if (a_allocated <= n)						\
74 	  a_allocated = n + 1;						\
75 	memory = (a->arg						\
76 		  ? realloc (a->arg, a_allocated * sizeof (argument))	\
77 		  : malloc (a_allocated * sizeof (argument)));		\
78 	if (memory == NULL)						\
79 	  /* Out of memory.  */						\
80 	  goto error;							\
81 	a->arg = memory;						\
82       }									\
83     while (a->count <= n)						\
84       a->arg[a->count++].type = TYPE_NONE;				\
85     if (a->arg[n].type == TYPE_NONE)					\
86       a->arg[n].type = (_type_);					\
87     else if (a->arg[n].type != (_type_))				\
88       /* Ambiguous type for positional argument.  */			\
89       goto error;							\
90   }
91 
92   while (*cp != '\0')
93     {
94       char c = *cp++;
95       if (c == '%')
96 	{
97 	  int arg_index = -1;
98 	  char_directive *dp = &d->dir[d->count];/* pointer to next directive */
99 
100 	  /* Initialize the next directive.  */
101 	  dp->dir_start = cp - 1;
102 	  dp->flags = 0;
103 	  dp->width_start = NULL;
104 	  dp->width_end = NULL;
105 	  dp->width_arg_index = -1;
106 	  dp->precision_start = NULL;
107 	  dp->precision_end = NULL;
108 	  dp->precision_arg_index = -1;
109 	  dp->arg_index = -1;
110 
111 	  /* Test for positional argument.  */
112 	  if (*cp >= '0' && *cp <= '9')
113 	    {
114 	      const char *np;
115 
116 	      for (np = cp; *np >= '0' && *np <= '9'; np++)
117 		;
118 	      if (*np == '$')
119 		{
120 		  unsigned int n = 0;
121 
122 		  for (np = cp; *np >= '0' && *np <= '9'; np++)
123 		    n = 10 * n + (*np - '0');
124 		  if (n == 0)
125 		    /* Positional argument 0.  */
126 		    goto error;
127 		  arg_index = n - 1;
128 		  cp = np + 1;
129 		}
130 	    }
131 
132 	  /* Read the flags.  */
133 	  for (;;)
134 	    {
135 	      if (*cp == '\'')
136 		{
137 		  dp->flags |= FLAG_GROUP;
138 		  cp++;
139 		}
140 	      else if (*cp == '-')
141 		{
142 		  dp->flags |= FLAG_LEFT;
143 		  cp++;
144 		}
145 	      else if (*cp == '+')
146 		{
147 		  dp->flags |= FLAG_SHOWSIGN;
148 		  cp++;
149 		}
150 	      else if (*cp == ' ')
151 		{
152 		  dp->flags |= FLAG_SPACE;
153 		  cp++;
154 		}
155 	      else if (*cp == '#')
156 		{
157 		  dp->flags |= FLAG_ALT;
158 		  cp++;
159 		}
160 	      else if (*cp == '0')
161 		{
162 		  dp->flags |= FLAG_ZERO;
163 		  cp++;
164 		}
165 	      else
166 		break;
167 	    }
168 
169 	  /* Parse the field width.  */
170 	  if (*cp == '*')
171 	    {
172 	      dp->width_start = cp;
173 	      cp++;
174 	      dp->width_end = cp;
175 	      if (max_width_length < 1)
176 		max_width_length = 1;
177 
178 	      /* Test for positional argument.  */
179 	      if (*cp >= '0' && *cp <= '9')
180 		{
181 		  const char *np;
182 
183 		  for (np = cp; *np >= '0' && *np <= '9'; np++)
184 		    ;
185 		  if (*np == '$')
186 		    {
187 		      unsigned int n = 0;
188 
189 		      for (np = cp; *np >= '0' && *np <= '9'; np++)
190 			n = 10 * n + (*np - '0');
191 		      if (n == 0)
192 			/* Positional argument 0.  */
193 			goto error;
194 		      dp->width_arg_index = n - 1;
195 		      cp = np + 1;
196 		    }
197 		}
198 	      if (dp->width_arg_index < 0)
199 		dp->width_arg_index = arg_posn++;
200 	      REGISTER_ARG (dp->width_arg_index, TYPE_INT);
201 	    }
202 	  else if (*cp >= '0' && *cp <= '9')
203 	    {
204 	      unsigned int width_length;
205 
206 	      dp->width_start = cp;
207 	      for (; *cp >= '0' && *cp <= '9'; cp++)
208 		;
209 	      dp->width_end = cp;
210 	      width_length = dp->width_end - dp->width_start;
211 	      if (max_width_length < width_length)
212 		max_width_length = width_length;
213 	    }
214 
215 	  /* Parse the precision.  */
216 	  if (*cp == '.')
217 	    {
218 	      cp++;
219 	      if (*cp == '*')
220 		{
221 		  dp->precision_start = cp - 1;
222 		  cp++;
223 		  dp->precision_end = cp;
224 		  if (max_precision_length < 2)
225 		    max_precision_length = 2;
226 
227 		  /* Test for positional argument.  */
228 		  if (*cp >= '0' && *cp <= '9')
229 		    {
230 		      const char *np;
231 
232 		      for (np = cp; *np >= '0' && *np <= '9'; np++)
233 			;
234 		      if (*np == '$')
235 			{
236 			  unsigned int n = 0;
237 
238 			  for (np = cp; *np >= '0' && *np <= '9'; np++)
239 			    n = 10 * n + (*np - '0');
240 			  if (n == 0)
241 			    /* Positional argument 0.  */
242 			    goto error;
243 			  dp->precision_arg_index = n - 1;
244 			  cp = np + 1;
245 			}
246 		    }
247 		  if (dp->precision_arg_index < 0)
248 		    dp->precision_arg_index = arg_posn++;
249 		  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
250 		}
251 	      else
252 		{
253 		  unsigned int precision_length;
254 
255 		  dp->precision_start = cp - 1;
256 		  for (; *cp >= '0' && *cp <= '9'; cp++)
257 		    ;
258 		  dp->precision_end = cp;
259 		  precision_length = dp->precision_end - dp->precision_start;
260 		  if (max_precision_length < precision_length)
261 		    max_precision_length = precision_length;
262 		}
263 	    }
264 
265 	  {
266 	    arg_type type;
267 
268 	    /* Parse argument type/size specifiers.  */
269 	    {
270 	      int flags = 0;
271 
272 	      for (;;)
273 		{
274 		  if (*cp == 'h')
275 		    {
276 		      flags |= (1 << (flags & 1));
277 		      cp++;
278 		    }
279 		  else if (*cp == 'L')
280 		    {
281 		      flags |= 4;
282 		      cp++;
283 		    }
284 		  else if (*cp == 'l')
285 		    {
286 		      flags += 8;
287 		      cp++;
288 		    }
289 #ifdef HAVE_INT64_AND_I64
290 		  else if (cp[0] == 'I' &&
291 			   cp[1] == '6' &&
292 			   cp[2] == '4')
293 		    {
294 		      flags = 64;
295 		      cp += 3;
296 		    }
297 #endif
298 #ifdef HAVE_INTMAX_T
299 		  else if (*cp == 'j')
300 		    {
301 		      if (sizeof (intmax_t) > sizeof (long))
302 			{
303 			  /* intmax_t = long long */
304 			  flags += 16;
305 			}
306 		      else if (sizeof (intmax_t) > sizeof (int))
307 			{
308 			  /* intmax_t = long */
309 			  flags += 8;
310 			}
311 		      cp++;
312 		    }
313 #endif
314 		  else if (*cp == 'z' || *cp == 'Z')
315 		    {
316 		      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
317 			 because the warning facility in gcc-2.95.2 understands
318 			 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
319 		      if (sizeof (size_t) > sizeof (long))
320 			{
321 			  /* size_t = long long */
322 			  flags += 16;
323 			}
324 		      else if (sizeof (size_t) > sizeof (int))
325 			{
326 			  /* size_t = long */
327 			  flags += 8;
328 			}
329 		      cp++;
330 		    }
331 		  else if (*cp == 't')
332 		    {
333 		      if (sizeof (ptrdiff_t) > sizeof (long))
334 			{
335 			  /* ptrdiff_t = long long */
336 			  flags += 16;
337 			}
338 		      else if (sizeof (ptrdiff_t) > sizeof (int))
339 			{
340 			  /* ptrdiff_t = long */
341 			  flags += 8;
342 			}
343 		      cp++;
344 		    }
345 		  else
346 		    break;
347 		}
348 
349 	      /* Read the conversion character.  */
350 	      c = *cp++;
351 	      switch (c)
352 		{
353 		case 'd': case 'i':
354 #ifdef HAVE_INT64_AND_I64
355 		  if (flags == 64)
356 		    type = TYPE_INT64;
357 		  else
358 #endif
359 #ifdef HAVE_LONG_LONG
360 		  if (flags >= 16 || (flags & 4))
361 		    type = TYPE_LONGLONGINT;
362 		  else
363 #endif
364 		  if (flags >= 8)
365 		    type = TYPE_LONGINT;
366 		  else if (flags & 2)
367 		    type = TYPE_SCHAR;
368 		  else if (flags & 1)
369 		    type = TYPE_SHORT;
370 		  else
371 		    type = TYPE_INT;
372 		  break;
373 		case 'o': case 'u': case 'x': case 'X':
374 #ifdef HAVE_INT64_AND_I64
375 		  if (flags == 64)
376 		    type = TYPE_UINT64;
377 		  else
378 #endif
379 #ifdef HAVE_LONG_LONG
380 		  if (flags >= 16 || (flags & 4))
381 		    type = TYPE_ULONGLONGINT;
382 		  else
383 #endif
384 		  if (flags >= 8)
385 		    type = TYPE_ULONGINT;
386 		  else if (flags & 2)
387 		    type = TYPE_UCHAR;
388 		  else if (flags & 1)
389 		    type = TYPE_USHORT;
390 		  else
391 		    type = TYPE_UINT;
392 		  break;
393 		case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
394 		case 'a': case 'A':
395 #ifdef HAVE_LONG_DOUBLE
396 		  if (flags >= 16 || (flags & 4))
397 		    type = TYPE_LONGDOUBLE;
398 		  else
399 #endif
400 		  type = TYPE_DOUBLE;
401 		  break;
402 		case 'c':
403 		  if (flags >= 8)
404 #ifdef HAVE_WINT_T
405 		    type = TYPE_WIDE_CHAR;
406 #else
407 		    goto error;
408 #endif
409 		  else
410 		    type = TYPE_CHAR;
411 		  break;
412 #ifdef HAVE_WINT_T
413 		case 'C':
414 		  type = TYPE_WIDE_CHAR;
415 		  c = 'c';
416 		  break;
417 #endif
418 		case 's':
419 		  if (flags >= 8)
420 #ifdef HAVE_WCHAR_T
421 		    type = TYPE_WIDE_STRING;
422 #else
423 		    goto error;
424 #endif
425 		  else
426 		    type = TYPE_STRING;
427 		  break;
428 #ifdef HAVE_WCHAR_T
429 		case 'S':
430 		  type = TYPE_WIDE_STRING;
431 		  c = 's';
432 		  break;
433 #endif
434 		case 'p':
435 		  type = TYPE_POINTER;
436 		  break;
437 		case 'n':
438 #ifdef HAVE_LONG_LONG
439 		  if (flags >= 16 || (flags & 4))
440 		    type = TYPE_COUNT_LONGLONGINT_POINTER;
441 		  else
442 #endif
443 		  if (flags >= 8)
444 		    type = TYPE_COUNT_LONGINT_POINTER;
445 		  else if (flags & 2)
446 		    type = TYPE_COUNT_SCHAR_POINTER;
447 		  else if (flags & 1)
448 		    type = TYPE_COUNT_SHORT_POINTER;
449 		  else
450 		    type = TYPE_COUNT_INT_POINTER;
451 		  break;
452 		case '%':
453 		  type = TYPE_NONE;
454 		  break;
455 		default:
456 		  /* Unknown conversion character.  */
457 		  goto error;
458 		}
459 	    }
460 
461 	    if (type != TYPE_NONE)
462 	      {
463 		dp->arg_index = arg_index;
464 		if (dp->arg_index < 0)
465 		  dp->arg_index = arg_posn++;
466 		REGISTER_ARG (dp->arg_index, type);
467 	      }
468 	    dp->conversion = c;
469 	    dp->dir_end = cp;
470 	  }
471 
472 	  d->count++;
473 	  if (d->count >= d_allocated)
474 	    {
475 	      char_directive *memory;
476 
477 	      d_allocated = 2 * d_allocated;
478 	      memory = realloc (d->dir, d_allocated * sizeof (char_directive));
479 	      if (memory == NULL)
480 		/* Out of memory.  */
481 		goto error;
482 	      d->dir = memory;
483 	    }
484 	}
485     }
486   d->dir[d->count].dir_start = cp;
487 
488   d->max_width_length = max_width_length;
489   d->max_precision_length = max_precision_length;
490   return 0;
491 
492 error:
493   if (a->arg)
494     free (a->arg);
495   if (d->dir)
496     free (d->dir);
497   return -1;
498 }
499