-#ifdef SNPRINTF_LONGLONG_SUPPORT
- long long int long_long_arg = 0;
- unsigned long long int ulong_long_arg = 0;
- /* only defined for length modifier ll */
-#endif
- if (fmt_spec == 'p') {
- /* HPUX 10: An l, h, ll or L before any other conversion character
- * (other than d, i, u, o, x, or X) is ignored.
- * Digital Unix:
- * not specified, but seems to behave as HPUX does.
- * Solaris: If an h, l, or L appears before any other conversion
- * specifier (other than d, i, u, o, x, or X), the behavior
- * is undefined. (Actually %hp converts only 16-bits of address
- * and %llp treats address as 64-bit data which is incompatible
- * with (void *) argument on a 32-bit system).
- */
-#ifdef SOLARIS_COMPATIBLE
-# ifdef SOLARIS_BUG_COMPATIBLE
- /* keep length modifiers even if it represents 'll' */
-# else
- if (length_modifier == '2')
- length_modifier = '\0';
-# endif
-#else
- length_modifier = '\0';
-#endif
- ptr_arg = va_arg(ap, void *);
- if (ptr_arg != NULL)
- arg_sign = 1;
- } else if (fmt_spec == 'd') { /* signed */
- switch (length_modifier) {
- case '\0':
- case 'h':
- /* It is non-portable to specify a second argument of char or short
- * to va_arg, because arguments seen by the called function
- * are not char or short. C converts char and short arguments
- * to int before passing them to a function.
- */
- int_arg = va_arg(ap, int);
- if (int_arg > 0)
- arg_sign = 1;
- else if (int_arg < 0)
- arg_sign = -1;
- break;
- case 'l':
- long_arg = va_arg(ap, long int);
- if (long_arg > 0)
- arg_sign = 1;
- else if (long_arg < 0)
- arg_sign = -1;
- break;
-#ifdef SNPRINTF_LONGLONG_SUPPORT
- case '2':
- long_long_arg = va_arg(ap, long long int);
- if (long_long_arg > 0)
- arg_sign = 1;
- else if (long_long_arg < 0)
- arg_sign = -1;
- break;
-#endif
- }
- } else { /* unsigned */
- switch (length_modifier) {
- case '\0':
- case 'h':
- uint_arg = va_arg(ap, unsigned int);
- if (uint_arg)
- arg_sign = 1;
- break;
- case 'l':
- ulong_arg = va_arg(ap, unsigned long int);
- if (ulong_arg)
- arg_sign = 1;
- break;
-#ifdef SNPRINTF_LONGLONG_SUPPORT
- case '2':
- ulong_long_arg = va_arg(ap, unsigned long long int);
- if (ulong_long_arg)
- arg_sign = 1;
- break;
-#endif
- }
- }
- str_arg = tmp;
- str_arg_l = 0;
- /* NOTE:
- * For d, i, u, o, x, and X conversions, if precision is specified,
- * the '0' flag should be ignored. This is so with Solaris 2.6,
- * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
- */
-#ifndef PERL_COMPATIBLE
- if (precision_specified)
- zero_padding = 0;
-#endif
- if (fmt_spec == 'd') {
- if (force_sign && arg_sign >= 0)
- tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
- /* leave negative numbers for sprintf to handle,
- to avoid handling tricky cases like (short int)(-32768) */
-#ifdef LINUX_COMPATIBLE
- } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
- tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
-#endif
- } else if (alternate_form) {
- if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X')) {
- tmp[str_arg_l++] = '0';
- tmp[str_arg_l++] = fmt_spec;
- }
- /* alternate form should have no effect for p conversion, but ... */
-#ifdef HPUX_COMPATIBLE
- else if (fmt_spec == 'p'
- /* HPUX 10: for an alternate form of p conversion,
- * a nonzero result is prefixed by 0x. */
-#ifndef HPUX_BUG_COMPATIBLE
- /* Actually it uses 0x prefix even for a zero value. */
- && arg_sign != 0
-#endif
- ) {
- tmp[str_arg_l++] = '0';
- tmp[str_arg_l++] = 'x';
- }
-#endif
- }
- zero_padding_insertion_ind = str_arg_l;
- if (!precision_specified)
- precision = 1; /* default precision is 1 */
- if (precision == 0 && arg_sign == 0
-#if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE)
- && fmt_spec != 'p'
- /* HPUX 10 man page claims: With conversion character p the result of
- * converting a zero value with a precision of zero is a null string.
- * Actually HP returns all zeroes, and Linux returns "(nil)". */
-#endif
- ) {
- /* converted to null string */
- /* When zero value is formatted with an explicit precision 0,
- the resulting formatted string is empty (d, i, u, o, x, X, p). */
- } else {
- char f[5];
- int f_l = 0;
- f[f_l++] = '%'; /* construct a simple format string for sprintf */
- if (!length_modifier) {
- } else if (length_modifier == '2') {
- f[f_l++] = 'l';
- f[f_l++] = 'l';
- } else
- f[f_l++] = length_modifier;
- f[f_l++] = fmt_spec;
- f[f_l++] = '\0';
- if (fmt_spec == 'p')
- str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg);
- else if (fmt_spec == 'd') { /* signed */
- switch (length_modifier) {
- case '\0':
- case 'h':
- str_arg_l += sprintf(tmp + str_arg_l, f, int_arg);
- break;
- case 'l':
- str_arg_l += sprintf(tmp + str_arg_l, f, long_arg);
- break;
-#ifdef SNPRINTF_LONGLONG_SUPPORT
- case '2':
- str_arg_l += sprintf(tmp + str_arg_l, f, long_long_arg);
- break;
-#endif
- }
- } else { /* unsigned */
- switch (length_modifier) {
- case '\0':
- case 'h':
- str_arg_l += sprintf(tmp + str_arg_l, f, uint_arg);
- break;
- case 'l':
- str_arg_l += sprintf(tmp + str_arg_l, f, ulong_arg);
- break;
-#ifdef SNPRINTF_LONGLONG_SUPPORT
- case '2':
- str_arg_l += sprintf(tmp + str_arg_l, f, ulong_long_arg);
- break;
-#endif
- }
- }
- /* include the optional minus sign and possible "0x"
- in the region before the zero padding insertion point */
- if (zero_padding_insertion_ind < str_arg_l &&
- tmp[zero_padding_insertion_ind] == '-') {
- zero_padding_insertion_ind++;
- }
- if (zero_padding_insertion_ind + 1 < str_arg_l &&
- tmp[zero_padding_insertion_ind] == '0' &&
- (tmp[zero_padding_insertion_ind + 1] == 'x' ||
- tmp[zero_padding_insertion_ind + 1] == 'X')) {
- zero_padding_insertion_ind += 2;
- }
- }
- {
- size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
- if (alternate_form && fmt_spec == 'o'
-#ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */
- && (str_arg_l > 0)
-#endif
-#ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */
-#else
- /* unless zero is already the first character */
- && !(zero_padding_insertion_ind < str_arg_l
- && tmp[zero_padding_insertion_ind] == '0')
-#endif
- ) { /* assure leading zero for alternate-form octal numbers */
- if (!precision_specified || precision < num_of_digits + 1) {
- /* precision is increased to force the first character to be zero,
- except if a zero value is formatted with an explicit precision
- of zero */
- precision = num_of_digits + 1;
- precision_specified = 1;
- }
- }
- /* zero padding to specified precision? */
- if (num_of_digits < precision)
- number_of_zeros_to_pad = precision - num_of_digits;
- }
- /* zero padding to specified minimal field width? */
- if (!justify_left && zero_padding) {
- int n = min_field_width - (str_arg_l + number_of_zeros_to_pad);
- if (n > 0)
- number_of_zeros_to_pad += n;
- }
- break;
- }
- default: /* unrecognized conversion specifier, keep format string as-is */
- zero_padding = 0; /* turn zero padding off for non-numeric convers. */
-#ifndef DIGITAL_UNIX_COMPATIBLE
- justify_left = 1;
- min_field_width = 0; /* reset flags */
-#endif
-#if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE)
- /* keep the entire format string unchanged */
- str_arg = starting_p;
- str_arg_l = p - starting_p;
- /* well, not exactly so for Linux, which does something inbetween,
- * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */
-#else
- /* discard the unrecognized conversion, just keep *
- * the unrecognized conversion character */
- str_arg = p;
- str_arg_l = 0;
-#endif
- if (*p)
- str_arg_l++; /* include invalid conversion specifier unchanged
- if not at end-of-string */
- break;
- }
- if (*p)
- p++; /* step over the just processed conversion specifier */
- /* insert padding to the left as requested by min_field_width;
- this does not include the zero padding in case of numerical conversions */
- if (!justify_left) { /* left padding with blank or zero */
- int n = min_field_width - (str_arg_l + number_of_zeros_to_pad);
- if (n > 0) {
- if (str_l < str_m) {
- int avail = str_m - str_l;
- fast_memset(str + str_l, (zero_padding ? '0' : ' '),
- (n > avail ? avail : n));
- }
- str_l += n;
- }
- }
- /* zero padding as requested by the precision or by the minimal field width
- * for numeric conversions required? */
- if (number_of_zeros_to_pad <= 0) {
- /* will not copy first part of numeric right now, *
- * force it to be copied later in its entirety */
- zero_padding_insertion_ind = 0;
- } else {
- /* insert first part of numerics (sign or '0x') before zero padding */
- int n = zero_padding_insertion_ind;
- if (n > 0) {
- if (str_l < str_m) {
- int avail = str_m - str_l;
- fast_memcpy(str + str_l, str_arg, (n > avail ? avail : n));
- }
- str_l += n;
- }
- /* insert zero padding as requested by the precision or min field width */
- n = number_of_zeros_to_pad;
- if (n > 0) {
- if (str_l < str_m) {
- int avail = str_m - str_l;
- fast_memset(str + str_l, '0', (n > avail ? avail : n));
- }
- str_l += n;
- }
- }
- /* insert formatted string
- * (or as-is conversion specifier for unknown conversions) */
- {
- int n = str_arg_l - zero_padding_insertion_ind;
- if (n > 0) {
- if (str_l < str_m) {
- int avail = str_m - str_l;
- fast_memcpy(str + str_l, str_arg + zero_padding_insertion_ind,
- (n > avail ? avail : n));
- }
- str_l += n;
- }
- }
- /* insert right padding */
- if (justify_left) { /* right blank padding to the field width */
- int n = min_field_width - (str_arg_l + number_of_zeros_to_pad);
- if (n > 0) {
- if (str_l < str_m) {
- int avail = str_m - str_l;
- fast_memset(str + str_l, ' ', (n > avail ? avail : n));
- }
- str_l += n;
- }
- }
- }
- }
-#if defined(NEED_SNPRINTF_ONLY)
- va_end(ap);
-#endif
- if (str_m > 0) { /* make sure the string is null-terminated
- even at the expense of overwriting the last character
- (shouldn't happen, but just in case) */
- str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0';