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 | ||
