diff options
Diffstat (limited to 'gl/printf-parse.c')
-rw-r--r-- | gl/printf-parse.c | 162 |
1 files changed, 123 insertions, 39 deletions
diff --git a/gl/printf-parse.c b/gl/printf-parse.c index 9a86f773..28b9bd41 100644 --- a/gl/printf-parse.c +++ b/gl/printf-parse.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* Formatted output to strings. | 1 | /* Formatted output to strings. |
2 | Copyright (C) 1999-2000, 2002-2003, 2006 Free Software Foundation, Inc. | 2 | Copyright (C) 1999-2000, 2002-2003, 2006-2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | This program is free software; you can redistribute it and/or modify | 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 | 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) | 6 | the Free Software Foundation; either version 3, or (at your option) |
7 | any later version. | 7 | any later version. |
8 | 8 | ||
9 | This program is distributed in the hope that it will be useful, | 9 | This program is distributed in the hope that it will be useful, |
@@ -15,42 +15,63 @@ | |||
15 | with this program; if not, write to the Free Software Foundation, | 15 | with this program; if not, write to the Free Software Foundation, |
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
17 | 17 | ||
18 | #include <config.h> | 18 | /* This file can be parametrized with the following macros: |
19 | CHAR_T The element type of the format string. | ||
20 | CHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters | ||
21 | in the format string are ASCII. | ||
22 | DIRECTIVE Structure denoting a format directive. | ||
23 | Depends on CHAR_T. | ||
24 | DIRECTIVES Structure denoting the set of format directives of a | ||
25 | format string. Depends on CHAR_T. | ||
26 | PRINTF_PARSE Function that parses a format string. | ||
27 | Depends on CHAR_T. | ||
28 | STATIC Set to 'static' to declare the function static. | ||
29 | ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions. */ | ||
30 | |||
31 | #ifndef PRINTF_PARSE | ||
32 | # include <config.h> | ||
33 | #endif | ||
19 | 34 | ||
20 | /* Specification. */ | 35 | /* Specification. */ |
21 | #if WIDE_CHAR_VERSION | 36 | #ifndef PRINTF_PARSE |
22 | # include "wprintf-parse.h" | ||
23 | #else | ||
24 | # include "printf-parse.h" | 37 | # include "printf-parse.h" |
25 | #endif | 38 | #endif |
26 | 39 | ||
40 | /* Default parameters. */ | ||
41 | #ifndef PRINTF_PARSE | ||
42 | # define PRINTF_PARSE printf_parse | ||
43 | # define CHAR_T char | ||
44 | # define DIRECTIVE char_directive | ||
45 | # define DIRECTIVES char_directives | ||
46 | #endif | ||
47 | |||
27 | /* Get size_t, NULL. */ | 48 | /* Get size_t, NULL. */ |
28 | #include <stddef.h> | 49 | #include <stddef.h> |
29 | 50 | ||
30 | /* Get intmax_t. */ | 51 | /* Get intmax_t. */ |
31 | #if HAVE_STDINT_H_WITH_UINTMAX | 52 | #if defined IN_LIBINTL || defined IN_LIBASPRINTF |
53 | # if HAVE_STDINT_H_WITH_UINTMAX | ||
54 | # include <stdint.h> | ||
55 | # endif | ||
56 | # if HAVE_INTTYPES_H_WITH_UINTMAX | ||
57 | # include <inttypes.h> | ||
58 | # endif | ||
59 | #else | ||
32 | # include <stdint.h> | 60 | # include <stdint.h> |
33 | #endif | 61 | #endif |
34 | #if HAVE_INTTYPES_H_WITH_UINTMAX | ||
35 | # include <inttypes.h> | ||
36 | #endif | ||
37 | 62 | ||
38 | /* malloc(), realloc(), free(). */ | 63 | /* malloc(), realloc(), free(). */ |
39 | #include <stdlib.h> | 64 | #include <stdlib.h> |
40 | 65 | ||
66 | /* errno. */ | ||
67 | #include <errno.h> | ||
68 | |||
41 | /* Checked size_t computations. */ | 69 | /* Checked size_t computations. */ |
42 | #include "xsize.h" | 70 | #include "xsize.h" |
43 | 71 | ||
44 | #if WIDE_CHAR_VERSION | 72 | #if CHAR_T_ONLY_ASCII |
45 | # define PRINTF_PARSE wprintf_parse | 73 | /* c_isascii(). */ |
46 | # define CHAR_T wchar_t | 74 | # include "c-ctype.h" |
47 | # define DIRECTIVE wchar_t_directive | ||
48 | # define DIRECTIVES wchar_t_directives | ||
49 | #else | ||
50 | # define PRINTF_PARSE printf_parse | ||
51 | # define CHAR_T char | ||
52 | # define DIRECTIVE char_directive | ||
53 | # define DIRECTIVES char_directives | ||
54 | #endif | 75 | #endif |
55 | 76 | ||
56 | #ifdef STATIC | 77 | #ifdef STATIC |
@@ -71,7 +92,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
71 | d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE)); | 92 | d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE)); |
72 | if (d->dir == NULL) | 93 | if (d->dir == NULL) |
73 | /* Out of memory. */ | 94 | /* Out of memory. */ |
74 | return -1; | 95 | goto out_of_memory_1; |
75 | 96 | ||
76 | a->count = 0; | 97 | a->count = 0; |
77 | a_allocated = 0; | 98 | a_allocated = 0; |
@@ -91,13 +112,13 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
91 | memory_size = xtimes (a_allocated, sizeof (argument)); \ | 112 | memory_size = xtimes (a_allocated, sizeof (argument)); \ |
92 | if (size_overflow_p (memory_size)) \ | 113 | if (size_overflow_p (memory_size)) \ |
93 | /* Overflow, would lead to out of memory. */ \ | 114 | /* Overflow, would lead to out of memory. */ \ |
94 | goto error; \ | 115 | goto out_of_memory; \ |
95 | memory = (argument *) (a->arg \ | 116 | memory = (argument *) (a->arg \ |
96 | ? realloc (a->arg, memory_size) \ | 117 | ? realloc (a->arg, memory_size) \ |
97 | : malloc (memory_size)); \ | 118 | : malloc (memory_size)); \ |
98 | if (memory == NULL) \ | 119 | if (memory == NULL) \ |
99 | /* Out of memory. */ \ | 120 | /* Out of memory. */ \ |
100 | goto error; \ | 121 | goto out_of_memory; \ |
101 | a->arg = memory; \ | 122 | a->arg = memory; \ |
102 | } \ | 123 | } \ |
103 | while (a->count <= n) \ | 124 | while (a->count <= n) \ |
@@ -115,7 +136,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
115 | if (c == '%') | 136 | if (c == '%') |
116 | { | 137 | { |
117 | size_t arg_index = ARG_NONE; | 138 | size_t arg_index = ARG_NONE; |
118 | DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */ | 139 | DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */ |
119 | 140 | ||
120 | /* Initialize the next directive. */ | 141 | /* Initialize the next directive. */ |
121 | dp->dir_start = cp - 1; | 142 | dp->dir_start = cp - 1; |
@@ -326,7 +347,6 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
326 | flags += 8; | 347 | flags += 8; |
327 | cp++; | 348 | cp++; |
328 | } | 349 | } |
329 | #ifdef HAVE_INTMAX_T | ||
330 | else if (*cp == 'j') | 350 | else if (*cp == 'j') |
331 | { | 351 | { |
332 | if (sizeof (intmax_t) > sizeof (long)) | 352 | if (sizeof (intmax_t) > sizeof (long)) |
@@ -341,7 +361,6 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
341 | } | 361 | } |
342 | cp++; | 362 | cp++; |
343 | } | 363 | } |
344 | #endif | ||
345 | else if (*cp == 'z' || *cp == 'Z') | 364 | else if (*cp == 'z' || *cp == 'Z') |
346 | { | 365 | { |
347 | /* 'z' is standardized in ISO C 99, but glibc uses 'Z' | 366 | /* 'z' is standardized in ISO C 99, but glibc uses 'Z' |
@@ -373,6 +392,44 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
373 | } | 392 | } |
374 | cp++; | 393 | cp++; |
375 | } | 394 | } |
395 | #if defined __APPLE__ && defined __MACH__ | ||
396 | /* On MacOS X 10.3, PRIdMAX is defined as "qd". | ||
397 | We cannot change it to "lld" because PRIdMAX must also | ||
398 | be understood by the system's printf routines. */ | ||
399 | else if (*cp == 'q') | ||
400 | { | ||
401 | if (64 / 8 > sizeof (long)) | ||
402 | { | ||
403 | /* int64_t = long long */ | ||
404 | flags += 16; | ||
405 | } | ||
406 | else | ||
407 | { | ||
408 | /* int64_t = long */ | ||
409 | flags += 8; | ||
410 | } | ||
411 | cp++; | ||
412 | } | ||
413 | #endif | ||
414 | #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | ||
415 | /* On native Win32, PRIdMAX is defined as "I64d". | ||
416 | We cannot change it to "lld" because PRIdMAX must also | ||
417 | be understood by the system's printf routines. */ | ||
418 | else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4') | ||
419 | { | ||
420 | if (64 / 8 > sizeof (long)) | ||
421 | { | ||
422 | /* __int64 = long long */ | ||
423 | flags += 16; | ||
424 | } | ||
425 | else | ||
426 | { | ||
427 | /* __int64 = long */ | ||
428 | flags += 8; | ||
429 | } | ||
430 | cp += 3; | ||
431 | } | ||
432 | #endif | ||
376 | else | 433 | else |
377 | break; | 434 | break; |
378 | } | 435 | } |
@@ -382,7 +439,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
382 | switch (c) | 439 | switch (c) |
383 | { | 440 | { |
384 | case 'd': case 'i': | 441 | case 'd': case 'i': |
385 | #ifdef HAVE_LONG_LONG_INT | 442 | #if HAVE_LONG_LONG_INT |
386 | /* If 'long long' exists and is larger than 'long': */ | 443 | /* If 'long long' exists and is larger than 'long': */ |
387 | if (flags >= 16 || (flags & 4)) | 444 | if (flags >= 16 || (flags & 4)) |
388 | type = TYPE_LONGLONGINT; | 445 | type = TYPE_LONGLONGINT; |
@@ -400,7 +457,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
400 | type = TYPE_INT; | 457 | type = TYPE_INT; |
401 | break; | 458 | break; |
402 | case 'o': case 'u': case 'x': case 'X': | 459 | case 'o': case 'u': case 'x': case 'X': |
403 | #ifdef HAVE_LONG_LONG_INT | 460 | #if HAVE_LONG_LONG_INT |
404 | /* If 'long long' exists and is larger than 'long': */ | 461 | /* If 'long long' exists and is larger than 'long': */ |
405 | if (flags >= 16 || (flags & 4)) | 462 | if (flags >= 16 || (flags & 4)) |
406 | type = TYPE_ULONGLONGINT; | 463 | type = TYPE_ULONGLONGINT; |
@@ -419,16 +476,14 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
419 | break; | 476 | break; |
420 | case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': | 477 | case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': |
421 | case 'a': case 'A': | 478 | case 'a': case 'A': |
422 | #ifdef HAVE_LONG_DOUBLE | ||
423 | if (flags >= 16 || (flags & 4)) | 479 | if (flags >= 16 || (flags & 4)) |
424 | type = TYPE_LONGDOUBLE; | 480 | type = TYPE_LONGDOUBLE; |
425 | else | 481 | else |
426 | #endif | 482 | type = TYPE_DOUBLE; |
427 | type = TYPE_DOUBLE; | ||
428 | break; | 483 | break; |
429 | case 'c': | 484 | case 'c': |
430 | if (flags >= 8) | 485 | if (flags >= 8) |
431 | #ifdef HAVE_WINT_T | 486 | #if HAVE_WINT_T |
432 | type = TYPE_WIDE_CHAR; | 487 | type = TYPE_WIDE_CHAR; |
433 | #else | 488 | #else |
434 | goto error; | 489 | goto error; |
@@ -436,7 +491,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
436 | else | 491 | else |
437 | type = TYPE_CHAR; | 492 | type = TYPE_CHAR; |
438 | break; | 493 | break; |
439 | #ifdef HAVE_WINT_T | 494 | #if HAVE_WINT_T |
440 | case 'C': | 495 | case 'C': |
441 | type = TYPE_WIDE_CHAR; | 496 | type = TYPE_WIDE_CHAR; |
442 | c = 'c'; | 497 | c = 'c'; |
@@ -444,7 +499,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
444 | #endif | 499 | #endif |
445 | case 's': | 500 | case 's': |
446 | if (flags >= 8) | 501 | if (flags >= 8) |
447 | #ifdef HAVE_WCHAR_T | 502 | #if HAVE_WCHAR_T |
448 | type = TYPE_WIDE_STRING; | 503 | type = TYPE_WIDE_STRING; |
449 | #else | 504 | #else |
450 | goto error; | 505 | goto error; |
@@ -452,7 +507,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
452 | else | 507 | else |
453 | type = TYPE_STRING; | 508 | type = TYPE_STRING; |
454 | break; | 509 | break; |
455 | #ifdef HAVE_WCHAR_T | 510 | #if HAVE_WCHAR_T |
456 | case 'S': | 511 | case 'S': |
457 | type = TYPE_WIDE_STRING; | 512 | type = TYPE_WIDE_STRING; |
458 | c = 's'; | 513 | c = 's'; |
@@ -462,7 +517,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
462 | type = TYPE_POINTER; | 517 | type = TYPE_POINTER; |
463 | break; | 518 | break; |
464 | case 'n': | 519 | case 'n': |
465 | #ifdef HAVE_LONG_LONG_INT | 520 | #if HAVE_LONG_LONG_INT |
466 | /* If 'long long' exists and is larger than 'long': */ | 521 | /* If 'long long' exists and is larger than 'long': */ |
467 | if (flags >= 16 || (flags & 4)) | 522 | if (flags >= 16 || (flags & 4)) |
468 | type = TYPE_COUNT_LONGLONGINT_POINTER; | 523 | type = TYPE_COUNT_LONGLONGINT_POINTER; |
@@ -479,6 +534,17 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
479 | else | 534 | else |
480 | type = TYPE_COUNT_INT_POINTER; | 535 | type = TYPE_COUNT_INT_POINTER; |
481 | break; | 536 | break; |
537 | #if ENABLE_UNISTDIO | ||
538 | /* The unistdio extensions. */ | ||
539 | case 'U': | ||
540 | if (flags >= 16) | ||
541 | type = TYPE_U32_STRING; | ||
542 | else if (flags >= 8) | ||
543 | type = TYPE_U16_STRING; | ||
544 | else | ||
545 | type = TYPE_U8_STRING; | ||
546 | break; | ||
547 | #endif | ||
482 | case '%': | 548 | case '%': |
483 | type = TYPE_NONE; | 549 | type = TYPE_NONE; |
484 | break; | 550 | break; |
@@ -514,14 +580,21 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |||
514 | memory_size = xtimes (d_allocated, sizeof (DIRECTIVE)); | 580 | memory_size = xtimes (d_allocated, sizeof (DIRECTIVE)); |
515 | if (size_overflow_p (memory_size)) | 581 | if (size_overflow_p (memory_size)) |
516 | /* Overflow, would lead to out of memory. */ | 582 | /* Overflow, would lead to out of memory. */ |
517 | goto error; | 583 | goto out_of_memory; |
518 | memory = (DIRECTIVE *) realloc (d->dir, memory_size); | 584 | memory = (DIRECTIVE *) realloc (d->dir, memory_size); |
519 | if (memory == NULL) | 585 | if (memory == NULL) |
520 | /* Out of memory. */ | 586 | /* Out of memory. */ |
521 | goto error; | 587 | goto out_of_memory; |
522 | d->dir = memory; | 588 | d->dir = memory; |
523 | } | 589 | } |
524 | } | 590 | } |
591 | #if CHAR_T_ONLY_ASCII | ||
592 | else if (!c_isascii (c)) | ||
593 | { | ||
594 | /* Non-ASCII character. Not supported. */ | ||
595 | goto error; | ||
596 | } | ||
597 | #endif | ||
525 | } | 598 | } |
526 | d->dir[d->count].dir_start = cp; | 599 | d->dir[d->count].dir_start = cp; |
527 | 600 | ||
@@ -534,10 +607,21 @@ error: | |||
534 | free (a->arg); | 607 | free (a->arg); |
535 | if (d->dir) | 608 | if (d->dir) |
536 | free (d->dir); | 609 | free (d->dir); |
610 | errno = EINVAL; | ||
611 | return -1; | ||
612 | |||
613 | out_of_memory: | ||
614 | if (a->arg) | ||
615 | free (a->arg); | ||
616 | if (d->dir) | ||
617 | free (d->dir); | ||
618 | out_of_memory_1: | ||
619 | errno = ENOMEM; | ||
537 | return -1; | 620 | return -1; |
538 | } | 621 | } |
539 | 622 | ||
623 | #undef PRINTF_PARSE | ||
540 | #undef DIRECTIVES | 624 | #undef DIRECTIVES |
541 | #undef DIRECTIVE | 625 | #undef DIRECTIVE |
626 | #undef CHAR_T_ONLY_ASCII | ||
542 | #undef CHAR_T | 627 | #undef CHAR_T |
543 | #undef PRINTF_PARSE | ||