diff options
author | Ton Voon <ton.voon@opsera.com> | 2010-06-17 10:16:43 +0100 |
---|---|---|
committer | tonvoon <ton.voon@opsera.com> | 2010-06-23 13:30:34 +0000 |
commit | 18f6835edaf7d640a2c9e476cb1babdbdadbfd9b (patch) | |
tree | ae11f40e48dc34658445c99012726f32bfb45c56 /gl/vasnprintf.c | |
parent | f61412478ceb7c821793c8356b936f64066508bf (diff) | |
download | monitoring-plugins-18f6835edaf7d640a2c9e476cb1babdbdadbfd9b.tar.gz |
Added state retention APIs. Implemented for check_snmp with --rate option.
See http://nagiosplugin.org/c-api-private for more details on the API.
Also updated check_snmp -l option to change the perfdata label.
Diffstat (limited to 'gl/vasnprintf.c')
-rw-r--r-- | gl/vasnprintf.c | 601 |
1 files changed, 340 insertions, 261 deletions
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c index 99d921e9..e618901b 100644 --- a/gl/vasnprintf.c +++ b/gl/vasnprintf.c | |||
@@ -148,8 +148,14 @@ | |||
148 | # define USE_SNPRINTF 1 | 148 | # define USE_SNPRINTF 1 |
149 | # if HAVE_DECL__SNWPRINTF | 149 | # if HAVE_DECL__SNWPRINTF |
150 | /* On Windows, the function swprintf() has a different signature than | 150 | /* On Windows, the function swprintf() has a different signature than |
151 | on Unix; we use the _snwprintf() function instead. */ | 151 | on Unix; we use the function _snwprintf() or - on mingw - snwprintf() |
152 | # define SNPRINTF _snwprintf | 152 | instead. The mingw function snwprintf() has fewer bugs than the |
153 | MSVCRT function _snwprintf(), so prefer that. */ | ||
154 | # if defined __MINGW32__ | ||
155 | # define SNPRINTF snwprintf | ||
156 | # else | ||
157 | # define SNPRINTF _snwprintf | ||
158 | # endif | ||
153 | # else | 159 | # else |
154 | /* Unix. */ | 160 | /* Unix. */ |
155 | # define SNPRINTF swprintf | 161 | # define SNPRINTF swprintf |
@@ -167,8 +173,15 @@ | |||
167 | # define USE_SNPRINTF 0 | 173 | # define USE_SNPRINTF 0 |
168 | # endif | 174 | # endif |
169 | # if HAVE_DECL__SNPRINTF | 175 | # if HAVE_DECL__SNPRINTF |
170 | /* Windows. */ | 176 | /* Windows. The mingw function snprintf() has fewer bugs than the MSVCRT |
171 | # define SNPRINTF _snprintf | 177 | function _snprintf(), so prefer that. */ |
178 | # if defined __MINGW32__ | ||
179 | # define SNPRINTF snprintf | ||
180 | /* Here we need to call the native snprintf, not rpl_snprintf. */ | ||
181 | # undef snprintf | ||
182 | # else | ||
183 | # define SNPRINTF _snprintf | ||
184 | # endif | ||
172 | # else | 185 | # else |
173 | /* Unix. */ | 186 | /* Unix. */ |
174 | # define SNPRINTF snprintf | 187 | # define SNPRINTF snprintf |
@@ -194,7 +207,7 @@ | |||
194 | #undef remainder | 207 | #undef remainder |
195 | #define remainder rem | 208 | #define remainder rem |
196 | 209 | ||
197 | #if !USE_SNPRINTF && !WIDE_CHAR_VERSION | 210 | #if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && !WIDE_CHAR_VERSION |
198 | # if (HAVE_STRNLEN && !defined _AIX) | 211 | # if (HAVE_STRNLEN && !defined _AIX) |
199 | # define local_strnlen strnlen | 212 | # define local_strnlen strnlen |
200 | # else | 213 | # else |
@@ -210,7 +223,7 @@ local_strnlen (const char *string, size_t maxlen) | |||
210 | # endif | 223 | # endif |
211 | #endif | 224 | #endif |
212 | 225 | ||
213 | #if (!USE_SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T && (WIDE_CHAR_VERSION || DCHAR_IS_TCHAR) | 226 | #if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T |
214 | # if HAVE_WCSLEN | 227 | # if HAVE_WCSLEN |
215 | # define local_wcslen wcslen | 228 | # define local_wcslen wcslen |
216 | # else | 229 | # else |
@@ -233,7 +246,7 @@ local_wcslen (const wchar_t *s) | |||
233 | # endif | 246 | # endif |
234 | #endif | 247 | #endif |
235 | 248 | ||
236 | #if !USE_SNPRINTF && HAVE_WCHAR_T && WIDE_CHAR_VERSION | 249 | #if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && HAVE_WCHAR_T && WIDE_CHAR_VERSION |
237 | # if HAVE_WCSNLEN | 250 | # if HAVE_WCSNLEN |
238 | # define local_wcsnlen wcsnlen | 251 | # define local_wcsnlen wcsnlen |
239 | # else | 252 | # else |
@@ -1474,6 +1487,258 @@ is_borderline (const char *digits, size_t precision) | |||
1474 | 1487 | ||
1475 | #endif | 1488 | #endif |
1476 | 1489 | ||
1490 | #if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 | ||
1491 | |||
1492 | /* Use a different function name, to make it possible that the 'wchar_t' | ||
1493 | parametrization and the 'char' parametrization get compiled in the same | ||
1494 | translation unit. */ | ||
1495 | # if WIDE_CHAR_VERSION | ||
1496 | # define MAX_ROOM_NEEDED wmax_room_needed | ||
1497 | # else | ||
1498 | # define MAX_ROOM_NEEDED max_room_needed | ||
1499 | # endif | ||
1500 | |||
1501 | /* Returns the number of TCHAR_T units needed as temporary space for the result | ||
1502 | of sprintf or SNPRINTF of a single conversion directive. */ | ||
1503 | static inline size_t | ||
1504 | MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, | ||
1505 | arg_type type, int flags, size_t width, int has_precision, | ||
1506 | size_t precision, int pad_ourselves) | ||
1507 | { | ||
1508 | size_t tmp_length; | ||
1509 | |||
1510 | switch (conversion) | ||
1511 | { | ||
1512 | case 'd': case 'i': case 'u': | ||
1513 | # if HAVE_LONG_LONG_INT | ||
1514 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
1515 | tmp_length = | ||
1516 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
1517 | * 0.30103 /* binary -> decimal */ | ||
1518 | ) | ||
1519 | + 1; /* turn floor into ceil */ | ||
1520 | else | ||
1521 | # endif | ||
1522 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
1523 | tmp_length = | ||
1524 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
1525 | * 0.30103 /* binary -> decimal */ | ||
1526 | ) | ||
1527 | + 1; /* turn floor into ceil */ | ||
1528 | else | ||
1529 | tmp_length = | ||
1530 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
1531 | * 0.30103 /* binary -> decimal */ | ||
1532 | ) | ||
1533 | + 1; /* turn floor into ceil */ | ||
1534 | if (tmp_length < precision) | ||
1535 | tmp_length = precision; | ||
1536 | /* Multiply by 2, as an estimate for FLAG_GROUP. */ | ||
1537 | tmp_length = xsum (tmp_length, tmp_length); | ||
1538 | /* Add 1, to account for a leading sign. */ | ||
1539 | tmp_length = xsum (tmp_length, 1); | ||
1540 | break; | ||
1541 | |||
1542 | case 'o': | ||
1543 | # if HAVE_LONG_LONG_INT | ||
1544 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
1545 | tmp_length = | ||
1546 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
1547 | * 0.333334 /* binary -> octal */ | ||
1548 | ) | ||
1549 | + 1; /* turn floor into ceil */ | ||
1550 | else | ||
1551 | # endif | ||
1552 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
1553 | tmp_length = | ||
1554 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
1555 | * 0.333334 /* binary -> octal */ | ||
1556 | ) | ||
1557 | + 1; /* turn floor into ceil */ | ||
1558 | else | ||
1559 | tmp_length = | ||
1560 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
1561 | * 0.333334 /* binary -> octal */ | ||
1562 | ) | ||
1563 | + 1; /* turn floor into ceil */ | ||
1564 | if (tmp_length < precision) | ||
1565 | tmp_length = precision; | ||
1566 | /* Add 1, to account for a leading sign. */ | ||
1567 | tmp_length = xsum (tmp_length, 1); | ||
1568 | break; | ||
1569 | |||
1570 | case 'x': case 'X': | ||
1571 | # if HAVE_LONG_LONG_INT | ||
1572 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
1573 | tmp_length = | ||
1574 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
1575 | * 0.25 /* binary -> hexadecimal */ | ||
1576 | ) | ||
1577 | + 1; /* turn floor into ceil */ | ||
1578 | else | ||
1579 | # endif | ||
1580 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
1581 | tmp_length = | ||
1582 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
1583 | * 0.25 /* binary -> hexadecimal */ | ||
1584 | ) | ||
1585 | + 1; /* turn floor into ceil */ | ||
1586 | else | ||
1587 | tmp_length = | ||
1588 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
1589 | * 0.25 /* binary -> hexadecimal */ | ||
1590 | ) | ||
1591 | + 1; /* turn floor into ceil */ | ||
1592 | if (tmp_length < precision) | ||
1593 | tmp_length = precision; | ||
1594 | /* Add 2, to account for a leading sign or alternate form. */ | ||
1595 | tmp_length = xsum (tmp_length, 2); | ||
1596 | break; | ||
1597 | |||
1598 | case 'f': case 'F': | ||
1599 | if (type == TYPE_LONGDOUBLE) | ||
1600 | tmp_length = | ||
1601 | (unsigned int) (LDBL_MAX_EXP | ||
1602 | * 0.30103 /* binary -> decimal */ | ||
1603 | * 2 /* estimate for FLAG_GROUP */ | ||
1604 | ) | ||
1605 | + 1 /* turn floor into ceil */ | ||
1606 | + 10; /* sign, decimal point etc. */ | ||
1607 | else | ||
1608 | tmp_length = | ||
1609 | (unsigned int) (DBL_MAX_EXP | ||
1610 | * 0.30103 /* binary -> decimal */ | ||
1611 | * 2 /* estimate for FLAG_GROUP */ | ||
1612 | ) | ||
1613 | + 1 /* turn floor into ceil */ | ||
1614 | + 10; /* sign, decimal point etc. */ | ||
1615 | tmp_length = xsum (tmp_length, precision); | ||
1616 | break; | ||
1617 | |||
1618 | case 'e': case 'E': case 'g': case 'G': | ||
1619 | tmp_length = | ||
1620 | 12; /* sign, decimal point, exponent etc. */ | ||
1621 | tmp_length = xsum (tmp_length, precision); | ||
1622 | break; | ||
1623 | |||
1624 | case 'a': case 'A': | ||
1625 | if (type == TYPE_LONGDOUBLE) | ||
1626 | tmp_length = | ||
1627 | (unsigned int) (LDBL_DIG | ||
1628 | * 0.831 /* decimal -> hexadecimal */ | ||
1629 | ) | ||
1630 | + 1; /* turn floor into ceil */ | ||
1631 | else | ||
1632 | tmp_length = | ||
1633 | (unsigned int) (DBL_DIG | ||
1634 | * 0.831 /* decimal -> hexadecimal */ | ||
1635 | ) | ||
1636 | + 1; /* turn floor into ceil */ | ||
1637 | if (tmp_length < precision) | ||
1638 | tmp_length = precision; | ||
1639 | /* Account for sign, decimal point etc. */ | ||
1640 | tmp_length = xsum (tmp_length, 12); | ||
1641 | break; | ||
1642 | |||
1643 | case 'c': | ||
1644 | # if HAVE_WINT_T && !WIDE_CHAR_VERSION | ||
1645 | if (type == TYPE_WIDE_CHAR) | ||
1646 | tmp_length = MB_CUR_MAX; | ||
1647 | else | ||
1648 | # endif | ||
1649 | tmp_length = 1; | ||
1650 | break; | ||
1651 | |||
1652 | case 's': | ||
1653 | # if HAVE_WCHAR_T | ||
1654 | if (type == TYPE_WIDE_STRING) | ||
1655 | { | ||
1656 | # if WIDE_CHAR_VERSION | ||
1657 | /* ISO C says about %ls in fwprintf: | ||
1658 | "If the precision is not specified or is greater than the size | ||
1659 | of the array, the array shall contain a null wide character." | ||
1660 | So if there is a precision, we must not use wcslen. */ | ||
1661 | const wchar_t *arg = ap->arg[arg_index].a.a_wide_string; | ||
1662 | |||
1663 | if (has_precision) | ||
1664 | tmp_length = local_wcsnlen (arg, precision); | ||
1665 | else | ||
1666 | tmp_length = local_wcslen (arg); | ||
1667 | # else | ||
1668 | /* ISO C says about %ls in fprintf: | ||
1669 | "If a precision is specified, no more than that many bytes are | ||
1670 | written (including shift sequences, if any), and the array | ||
1671 | shall contain a null wide character if, to equal the multibyte | ||
1672 | character sequence length given by the precision, the function | ||
1673 | would need to access a wide character one past the end of the | ||
1674 | array." | ||
1675 | So if there is a precision, we must not use wcslen. */ | ||
1676 | /* This case has already been handled separately in VASNPRINTF. */ | ||
1677 | abort (); | ||
1678 | # endif | ||
1679 | } | ||
1680 | else | ||
1681 | # endif | ||
1682 | { | ||
1683 | # if WIDE_CHAR_VERSION | ||
1684 | /* ISO C says about %s in fwprintf: | ||
1685 | "If the precision is not specified or is greater than the size | ||
1686 | of the converted array, the converted array shall contain a | ||
1687 | null wide character." | ||
1688 | So if there is a precision, we must not use strlen. */ | ||
1689 | /* This case has already been handled separately in VASNPRINTF. */ | ||
1690 | abort (); | ||
1691 | # else | ||
1692 | /* ISO C says about %s in fprintf: | ||
1693 | "If the precision is not specified or greater than the size of | ||
1694 | the array, the array shall contain a null character." | ||
1695 | So if there is a precision, we must not use strlen. */ | ||
1696 | const char *arg = ap->arg[arg_index].a.a_string; | ||
1697 | |||
1698 | if (has_precision) | ||
1699 | tmp_length = local_strnlen (arg, precision); | ||
1700 | else | ||
1701 | tmp_length = strlen (arg); | ||
1702 | # endif | ||
1703 | } | ||
1704 | break; | ||
1705 | |||
1706 | case 'p': | ||
1707 | tmp_length = | ||
1708 | (unsigned int) (sizeof (void *) * CHAR_BIT | ||
1709 | * 0.25 /* binary -> hexadecimal */ | ||
1710 | ) | ||
1711 | + 1 /* turn floor into ceil */ | ||
1712 | + 2; /* account for leading 0x */ | ||
1713 | break; | ||
1714 | |||
1715 | default: | ||
1716 | abort (); | ||
1717 | } | ||
1718 | |||
1719 | if (!pad_ourselves) | ||
1720 | { | ||
1721 | # if ENABLE_UNISTDIO | ||
1722 | /* Padding considers the number of characters, therefore the number of | ||
1723 | elements after padding may be | ||
1724 | > max (tmp_length, width) | ||
1725 | but is certainly | ||
1726 | <= tmp_length + width. */ | ||
1727 | tmp_length = xsum (tmp_length, width); | ||
1728 | # else | ||
1729 | /* Padding considers the number of elements, says POSIX. */ | ||
1730 | if (tmp_length < width) | ||
1731 | tmp_length = width; | ||
1732 | # endif | ||
1733 | } | ||
1734 | |||
1735 | tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ | ||
1736 | |||
1737 | return tmp_length; | ||
1738 | } | ||
1739 | |||
1740 | #endif | ||
1741 | |||
1477 | DCHAR_T * | 1742 | DCHAR_T * |
1478 | VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | 1743 | VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, |
1479 | const FCHAR_T *format, va_list args) | 1744 | const FCHAR_T *format, va_list args) |
@@ -2103,7 +2368,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
2103 | } | 2368 | } |
2104 | } | 2369 | } |
2105 | #endif | 2370 | #endif |
2106 | #if (!USE_SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T | 2371 | #if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T |
2107 | else if (dp->conversion == 's' | 2372 | else if (dp->conversion == 's' |
2108 | # if WIDE_CHAR_VERSION | 2373 | # if WIDE_CHAR_VERSION |
2109 | && a.arg[dp->arg_index].type != TYPE_WIDE_STRING | 2374 | && a.arg[dp->arg_index].type != TYPE_WIDE_STRING |
@@ -2592,8 +2857,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
2592 | count = wctomb (cbuf, *arg); | 2857 | count = wctomb (cbuf, *arg); |
2593 | # endif | 2858 | # endif |
2594 | if (count <= 0) | 2859 | if (count <= 0) |
2595 | /* Inconsistency. */ | 2860 | { |
2596 | abort (); | 2861 | /* Cannot convert. */ |
2862 | if (!(result == resultbuf || result == NULL)) | ||
2863 | free (result); | ||
2864 | if (buf_malloced != NULL) | ||
2865 | free (buf_malloced); | ||
2866 | CLEANUP (); | ||
2867 | errno = EILSEQ; | ||
2868 | return NULL; | ||
2869 | } | ||
2597 | ENSURE_ALLOCATION (xsum (length, count)); | 2870 | ENSURE_ALLOCATION (xsum (length, count)); |
2598 | memcpy (result + length, cbuf, count); | 2871 | memcpy (result + length, cbuf, count); |
2599 | length += count; | 2872 | length += count; |
@@ -2616,8 +2889,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
2616 | length += n; | 2889 | length += n; |
2617 | } | 2890 | } |
2618 | } | 2891 | } |
2619 | } | ||
2620 | # endif | 2892 | # endif |
2893 | } | ||
2621 | #endif | 2894 | #endif |
2622 | #if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL | 2895 | #if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL |
2623 | else if ((dp->conversion == 'a' || dp->conversion == 'A') | 2896 | else if ((dp->conversion == 'a' || dp->conversion == 'A') |
@@ -4301,11 +4574,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
4301 | { | 4574 | { |
4302 | arg_type type = a.arg[dp->arg_index].type; | 4575 | arg_type type = a.arg[dp->arg_index].type; |
4303 | int flags = dp->flags; | 4576 | int flags = dp->flags; |
4304 | #if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 4577 | #if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION |
4305 | int has_width; | 4578 | int has_width; |
4306 | size_t width; | 4579 | size_t width; |
4307 | #endif | 4580 | #endif |
4308 | #if !USE_SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION | 4581 | #if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION |
4309 | int has_precision; | 4582 | int has_precision; |
4310 | size_t precision; | 4583 | size_t precision; |
4311 | #endif | 4584 | #endif |
@@ -4330,7 +4603,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
4330 | TCHAR_T *tmp; | 4603 | TCHAR_T *tmp; |
4331 | #endif | 4604 | #endif |
4332 | 4605 | ||
4333 | #if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION | 4606 | #if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION |
4334 | has_width = 0; | 4607 | has_width = 0; |
4335 | width = 0; | 4608 | width = 0; |
4336 | if (dp->width_start != dp->width_end) | 4609 | if (dp->width_start != dp->width_end) |
@@ -4364,7 +4637,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
4364 | } | 4637 | } |
4365 | #endif | 4638 | #endif |
4366 | 4639 | ||
4367 | #if !USE_SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION | 4640 | #if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION |
4368 | has_precision = 0; | 4641 | has_precision = 0; |
4369 | precision = 6; | 4642 | precision = 6; |
4370 | if (dp->precision_start != dp->precision_end) | 4643 | if (dp->precision_start != dp->precision_end) |
@@ -4437,246 +4710,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
4437 | #if !USE_SNPRINTF | 4710 | #if !USE_SNPRINTF |
4438 | /* Allocate a temporary buffer of sufficient size for calling | 4711 | /* Allocate a temporary buffer of sufficient size for calling |
4439 | sprintf. */ | 4712 | sprintf. */ |
4440 | { | 4713 | tmp_length = |
4441 | switch (dp->conversion) | 4714 | MAX_ROOM_NEEDED (&a, dp->arg_index, dp->conversion, type, |
4442 | { | 4715 | flags, width, has_precision, precision, |
4443 | 4716 | pad_ourselves); | |
4444 | case 'd': case 'i': case 'u': | ||
4445 | # if HAVE_LONG_LONG_INT | ||
4446 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
4447 | tmp_length = | ||
4448 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
4449 | * 0.30103 /* binary -> decimal */ | ||
4450 | ) | ||
4451 | + 1; /* turn floor into ceil */ | ||
4452 | else | ||
4453 | # endif | ||
4454 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
4455 | tmp_length = | ||
4456 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
4457 | * 0.30103 /* binary -> decimal */ | ||
4458 | ) | ||
4459 | + 1; /* turn floor into ceil */ | ||
4460 | else | ||
4461 | tmp_length = | ||
4462 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
4463 | * 0.30103 /* binary -> decimal */ | ||
4464 | ) | ||
4465 | + 1; /* turn floor into ceil */ | ||
4466 | if (tmp_length < precision) | ||
4467 | tmp_length = precision; | ||
4468 | /* Multiply by 2, as an estimate for FLAG_GROUP. */ | ||
4469 | tmp_length = xsum (tmp_length, tmp_length); | ||
4470 | /* Add 1, to account for a leading sign. */ | ||
4471 | tmp_length = xsum (tmp_length, 1); | ||
4472 | break; | ||
4473 | |||
4474 | case 'o': | ||
4475 | # if HAVE_LONG_LONG_INT | ||
4476 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
4477 | tmp_length = | ||
4478 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
4479 | * 0.333334 /* binary -> octal */ | ||
4480 | ) | ||
4481 | + 1; /* turn floor into ceil */ | ||
4482 | else | ||
4483 | # endif | ||
4484 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
4485 | tmp_length = | ||
4486 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
4487 | * 0.333334 /* binary -> octal */ | ||
4488 | ) | ||
4489 | + 1; /* turn floor into ceil */ | ||
4490 | else | ||
4491 | tmp_length = | ||
4492 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
4493 | * 0.333334 /* binary -> octal */ | ||
4494 | ) | ||
4495 | + 1; /* turn floor into ceil */ | ||
4496 | if (tmp_length < precision) | ||
4497 | tmp_length = precision; | ||
4498 | /* Add 1, to account for a leading sign. */ | ||
4499 | tmp_length = xsum (tmp_length, 1); | ||
4500 | break; | ||
4501 | |||
4502 | case 'x': case 'X': | ||
4503 | # if HAVE_LONG_LONG_INT | ||
4504 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
4505 | tmp_length = | ||
4506 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
4507 | * 0.25 /* binary -> hexadecimal */ | ||
4508 | ) | ||
4509 | + 1; /* turn floor into ceil */ | ||
4510 | else | ||
4511 | # endif | ||
4512 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
4513 | tmp_length = | ||
4514 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
4515 | * 0.25 /* binary -> hexadecimal */ | ||
4516 | ) | ||
4517 | + 1; /* turn floor into ceil */ | ||
4518 | else | ||
4519 | tmp_length = | ||
4520 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
4521 | * 0.25 /* binary -> hexadecimal */ | ||
4522 | ) | ||
4523 | + 1; /* turn floor into ceil */ | ||
4524 | if (tmp_length < precision) | ||
4525 | tmp_length = precision; | ||
4526 | /* Add 2, to account for a leading sign or alternate form. */ | ||
4527 | tmp_length = xsum (tmp_length, 2); | ||
4528 | break; | ||
4529 | |||
4530 | case 'f': case 'F': | ||
4531 | if (type == TYPE_LONGDOUBLE) | ||
4532 | tmp_length = | ||
4533 | (unsigned int) (LDBL_MAX_EXP | ||
4534 | * 0.30103 /* binary -> decimal */ | ||
4535 | * 2 /* estimate for FLAG_GROUP */ | ||
4536 | ) | ||
4537 | + 1 /* turn floor into ceil */ | ||
4538 | + 10; /* sign, decimal point etc. */ | ||
4539 | else | ||
4540 | tmp_length = | ||
4541 | (unsigned int) (DBL_MAX_EXP | ||
4542 | * 0.30103 /* binary -> decimal */ | ||
4543 | * 2 /* estimate for FLAG_GROUP */ | ||
4544 | ) | ||
4545 | + 1 /* turn floor into ceil */ | ||
4546 | + 10; /* sign, decimal point etc. */ | ||
4547 | tmp_length = xsum (tmp_length, precision); | ||
4548 | break; | ||
4549 | |||
4550 | case 'e': case 'E': case 'g': case 'G': | ||
4551 | tmp_length = | ||
4552 | 12; /* sign, decimal point, exponent etc. */ | ||
4553 | tmp_length = xsum (tmp_length, precision); | ||
4554 | break; | ||
4555 | |||
4556 | case 'a': case 'A': | ||
4557 | if (type == TYPE_LONGDOUBLE) | ||
4558 | tmp_length = | ||
4559 | (unsigned int) (LDBL_DIG | ||
4560 | * 0.831 /* decimal -> hexadecimal */ | ||
4561 | ) | ||
4562 | + 1; /* turn floor into ceil */ | ||
4563 | else | ||
4564 | tmp_length = | ||
4565 | (unsigned int) (DBL_DIG | ||
4566 | * 0.831 /* decimal -> hexadecimal */ | ||
4567 | ) | ||
4568 | + 1; /* turn floor into ceil */ | ||
4569 | if (tmp_length < precision) | ||
4570 | tmp_length = precision; | ||
4571 | /* Account for sign, decimal point etc. */ | ||
4572 | tmp_length = xsum (tmp_length, 12); | ||
4573 | break; | ||
4574 | |||
4575 | case 'c': | ||
4576 | # if HAVE_WINT_T && !WIDE_CHAR_VERSION | ||
4577 | if (type == TYPE_WIDE_CHAR) | ||
4578 | tmp_length = MB_CUR_MAX; | ||
4579 | else | ||
4580 | # endif | ||
4581 | tmp_length = 1; | ||
4582 | break; | ||
4583 | |||
4584 | case 's': | ||
4585 | # if HAVE_WCHAR_T | ||
4586 | if (type == TYPE_WIDE_STRING) | ||
4587 | { | ||
4588 | # if WIDE_CHAR_VERSION | ||
4589 | /* ISO C says about %ls in fwprintf: | ||
4590 | "If the precision is not specified or is greater | ||
4591 | than the size of the array, the array shall | ||
4592 | contain a null wide character." | ||
4593 | So if there is a precision, we must not use | ||
4594 | wcslen. */ | ||
4595 | const wchar_t *arg = | ||
4596 | a.arg[dp->arg_index].a.a_wide_string; | ||
4597 | |||
4598 | if (has_precision) | ||
4599 | tmp_length = local_wcsnlen (arg, precision); | ||
4600 | else | ||
4601 | tmp_length = local_wcslen (arg); | ||
4602 | # else | ||
4603 | /* ISO C says about %ls in fprintf: | ||
4604 | "If a precision is specified, no more than that | ||
4605 | many bytes are written (including shift | ||
4606 | sequences, if any), and the array shall contain | ||
4607 | a null wide character if, to equal the | ||
4608 | multibyte character sequence length given by | ||
4609 | the precision, the function would need to | ||
4610 | access a wide character one past the end of the | ||
4611 | array." | ||
4612 | So if there is a precision, we must not use | ||
4613 | wcslen. */ | ||
4614 | /* This case has already been handled above. */ | ||
4615 | abort (); | ||
4616 | # endif | ||
4617 | } | ||
4618 | else | ||
4619 | # endif | ||
4620 | { | ||
4621 | # if WIDE_CHAR_VERSION | ||
4622 | /* ISO C says about %s in fwprintf: | ||
4623 | "If the precision is not specified or is greater | ||
4624 | than the size of the converted array, the | ||
4625 | converted array shall contain a null wide | ||
4626 | character." | ||
4627 | So if there is a precision, we must not use | ||
4628 | strlen. */ | ||
4629 | /* This case has already been handled above. */ | ||
4630 | abort (); | ||
4631 | # else | ||
4632 | /* ISO C says about %s in fprintf: | ||
4633 | "If the precision is not specified or greater | ||
4634 | than the size of the array, the array shall | ||
4635 | contain a null character." | ||
4636 | So if there is a precision, we must not use | ||
4637 | strlen. */ | ||
4638 | const char *arg = a.arg[dp->arg_index].a.a_string; | ||
4639 | |||
4640 | if (has_precision) | ||
4641 | tmp_length = local_strnlen (arg, precision); | ||
4642 | else | ||
4643 | tmp_length = strlen (arg); | ||
4644 | # endif | ||
4645 | } | ||
4646 | break; | ||
4647 | |||
4648 | case 'p': | ||
4649 | tmp_length = | ||
4650 | (unsigned int) (sizeof (void *) * CHAR_BIT | ||
4651 | * 0.25 /* binary -> hexadecimal */ | ||
4652 | ) | ||
4653 | + 1 /* turn floor into ceil */ | ||
4654 | + 2; /* account for leading 0x */ | ||
4655 | break; | ||
4656 | |||
4657 | default: | ||
4658 | abort (); | ||
4659 | } | ||
4660 | |||
4661 | if (!pad_ourselves) | ||
4662 | { | ||
4663 | # if ENABLE_UNISTDIO | ||
4664 | /* Padding considers the number of characters, therefore | ||
4665 | the number of elements after padding may be | ||
4666 | > max (tmp_length, width) | ||
4667 | but is certainly | ||
4668 | <= tmp_length + width. */ | ||
4669 | tmp_length = xsum (tmp_length, width); | ||
4670 | # else | ||
4671 | /* Padding considers the number of elements, | ||
4672 | says POSIX. */ | ||
4673 | if (tmp_length < width) | ||
4674 | tmp_length = width; | ||
4675 | # endif | ||
4676 | } | ||
4677 | |||
4678 | tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ | ||
4679 | } | ||
4680 | 4717 | ||
4681 | if (tmp_length <= sizeof (tmpbuf) / sizeof (TCHAR_T)) | 4718 | if (tmp_length <= sizeof (tmpbuf) / sizeof (TCHAR_T)) |
4682 | tmp = tmpbuf; | 4719 | tmp = tmpbuf; |
@@ -4916,6 +4953,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
4916 | } | 4953 | } |
4917 | #endif | 4954 | #endif |
4918 | 4955 | ||
4956 | errno = 0; | ||
4919 | switch (type) | 4957 | switch (type) |
4920 | { | 4958 | { |
4921 | case TYPE_SCHAR: | 4959 | case TYPE_SCHAR: |
@@ -5062,15 +5100,44 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
5062 | /* Look at the snprintf() return value. */ | 5100 | /* Look at the snprintf() return value. */ |
5063 | if (retcount < 0) | 5101 | if (retcount < 0) |
5064 | { | 5102 | { |
5103 | # if !HAVE_SNPRINTF_RETVAL_C99 | ||
5065 | /* HP-UX 10.20 snprintf() is doubly deficient: | 5104 | /* HP-UX 10.20 snprintf() is doubly deficient: |
5066 | It doesn't understand the '%n' directive, | 5105 | It doesn't understand the '%n' directive, |
5067 | *and* it returns -1 (rather than the length | 5106 | *and* it returns -1 (rather than the length |
5068 | that would have been required) when the | 5107 | that would have been required) when the |
5069 | buffer is too small. */ | 5108 | buffer is too small. |
5070 | size_t bigger_need = | 5109 | But a failure at this point can also come |
5071 | xsum (xtimes (allocated, 2), 12); | 5110 | from other reasons than a too small buffer, |
5072 | ENSURE_ALLOCATION (bigger_need); | 5111 | such as an invalid wide string argument to |
5073 | continue; | 5112 | the %ls directive, or possibly an invalid |
5113 | floating-point argument. */ | ||
5114 | size_t tmp_length = | ||
5115 | MAX_ROOM_NEEDED (&a, dp->arg_index, | ||
5116 | dp->conversion, type, flags, | ||
5117 | width, has_precision, | ||
5118 | precision, pad_ourselves); | ||
5119 | |||
5120 | if (maxlen < tmp_length) | ||
5121 | { | ||
5122 | /* Make more room. But try to do through | ||
5123 | this reallocation only once. */ | ||
5124 | size_t bigger_need = | ||
5125 | xsum (length, | ||
5126 | xsum (tmp_length, | ||
5127 | TCHARS_PER_DCHAR - 1) | ||
5128 | / TCHARS_PER_DCHAR); | ||
5129 | /* And always grow proportionally. | ||
5130 | (There may be several arguments, each | ||
5131 | needing a little more room than the | ||
5132 | previous one.) */ | ||
5133 | size_t bigger_need2 = | ||
5134 | xsum (xtimes (allocated, 2), 12); | ||
5135 | if (bigger_need < bigger_need2) | ||
5136 | bigger_need = bigger_need2; | ||
5137 | ENSURE_ALLOCATION (bigger_need); | ||
5138 | continue; | ||
5139 | } | ||
5140 | # endif | ||
5074 | } | 5141 | } |
5075 | else | 5142 | else |
5076 | count = retcount; | 5143 | count = retcount; |
@@ -5081,12 +5148,21 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
5081 | /* Attempt to handle failure. */ | 5148 | /* Attempt to handle failure. */ |
5082 | if (count < 0) | 5149 | if (count < 0) |
5083 | { | 5150 | { |
5151 | /* SNPRINTF or sprintf failed. Save and use the errno | ||
5152 | that it has set, if any. */ | ||
5153 | int saved_errno = errno; | ||
5154 | |||
5084 | if (!(result == resultbuf || result == NULL)) | 5155 | if (!(result == resultbuf || result == NULL)) |
5085 | free (result); | 5156 | free (result); |
5086 | if (buf_malloced != NULL) | 5157 | if (buf_malloced != NULL) |
5087 | free (buf_malloced); | 5158 | free (buf_malloced); |
5088 | CLEANUP (); | 5159 | CLEANUP (); |
5089 | errno = EINVAL; | 5160 | errno = |
5161 | (saved_errno != 0 | ||
5162 | ? saved_errno | ||
5163 | : (dp->conversion == 'c' || dp->conversion == 's' | ||
5164 | ? EILSEQ | ||
5165 | : EINVAL)); | ||
5090 | return NULL; | 5166 | return NULL; |
5091 | } | 5167 | } |
5092 | 5168 | ||
@@ -5422,6 +5498,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
5422 | length += count; | 5498 | length += count; |
5423 | break; | 5499 | break; |
5424 | } | 5500 | } |
5501 | #undef pad_ourselves | ||
5502 | #undef prec_ourselves | ||
5425 | } | 5503 | } |
5426 | } | 5504 | } |
5427 | } | 5505 | } |
@@ -5473,6 +5551,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
5473 | } | 5551 | } |
5474 | } | 5552 | } |
5475 | 5553 | ||
5554 | #undef MAX_ROOM_NEEDED | ||
5476 | #undef TCHARS_PER_DCHAR | 5555 | #undef TCHARS_PER_DCHAR |
5477 | #undef SNPRINTF | 5556 | #undef SNPRINTF |
5478 | #undef USE_SNPRINTF | 5557 | #undef USE_SNPRINTF |