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