summaryrefslogtreecommitdiffstats
path: root/gl/vasnprintf.c
diff options
context:
space:
mode:
authorTon Voon <ton.voon@opsera.com>2010-06-17 10:16:43 +0100
committertonvoon <ton.voon@opsera.com>2010-06-23 13:30:34 +0000
commit18f6835edaf7d640a2c9e476cb1babdbdadbfd9b (patch)
treeae11f40e48dc34658445c99012726f32bfb45c56 /gl/vasnprintf.c
parentf61412478ceb7c821793c8356b936f64066508bf (diff)
downloadmonitoring-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.c601
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. */
1503static inline size_t
1504MAX_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
1477DCHAR_T * 1742DCHAR_T *
1478VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, 1743VASNPRINTF (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