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 Lesser General Public License as published by |
6 | the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser 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 MacOS 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 | |