libs/libc/stdio/lib_vsprintf.c and Kconfig:

- Numbered arguments now work by using two pass parsing and an argument list.
    The maximum number of numbered args is determined by CONFIG_LIBC_NL_ARGMAX
    which is then copied into NL_ARGMAX.
  - Size of pointer argument ('p') is determined before output.

include/limits.h:  Define NL_ARGMAX (as well as some of the other 'invariant
  values' per http://pubs.opengroup.org/onlinepubs/7908799/xsh/limits.h.html)
This commit is contained in:
Johannes 2019-02-21 13:26:33 -06:00 committed by Gregory Nutt
parent 146c398eff
commit 0059a5a88e
3 changed files with 596 additions and 252 deletions

View File

@ -1,7 +1,7 @@
/********************************************************************************
* include/limits.h
*
* Copyright (C) 2007-2009, 2014 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2014, 2019 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -197,7 +197,7 @@
#define _POSIX_SEM_NSEMS_MAX INT_MAX
#define _POSIX_SEM_VALUE_MAX 0x7fff
/* Actual limits. These values may be increased from the POSIX minimum
/* Numerical limits. These values may be increased from the POSIX minimum
* values above or made indeterminate
*/
@ -230,6 +230,71 @@
#define TIMER_MAX _POSIX_TIMER_MAX
#define CLOCKRES_MIN _POSIX_CLOCKRES_MIN
/* Other invariant values */
/* CHARCLASS_NAME_MAX
* Maximum number of bytes in a character class name. Minimum Acceptable
* Value: 14
*/
#define CHARCLASS_NAME_MAX 14
/* Maximum value of digit in calls to the printf() and scanf() functions.
* Minimum Acceptable Value: 9
*/
#ifdef CONFIG_LIBC_NUMBERED_ARGS
# ifdef CONFIG_LIBC_NL_ARGMAX
# define NL_ARGMAX CONFIG_LIBC_NL_ARGMAX
# else
# define NL_ARGMAX 9
# endif
#endif
/* NL_LANGMAX
* Maximum number of bytes in a LANG name. Minimum Acceptable Value: 14
*/
#define NL_LANGMAX 14
/* NL_MSGMAX
* Maximum message number. Minimum Acceptable Value: 32 67
*/
#define NL_MSGMAX 32767
/* NL_NMAX
* Maximum number of bytes in an N-to-1 collation mapping. Minimum
* Acceptable Value: *
*/
/* NL_SETMAX
* Maximum set number. Minimum Acceptable Value: 255
*/
#define NL_SETMAX 255
/* NL_TEXTMAX
* Maximum number of bytes in a message string. Minimum Acceptable Value:
* _POSIX2_LINE_MAX
*/
#define NL_TEXTMAX _POSIX2_LINE_MAX
/* NZERO
* Default process priority. Minimum Acceptable Value: 20
*/
#define NZERO 20
/* TMP_MAX
* Minimum number of unique pathnames generated by tmpnam(). Maximum
* number of times an application can call tmpnam() reliably. (LEGACY)
* Minimum Acceptable Value: 10000
*/
#define TMP_MAX10000
/* Required for asynchronous I/O */
#define AIO_LISTIO_MAX _POSIX_AIO_LISTIO_MAX

View File

@ -97,16 +97,28 @@ config LIBC_PRINT_MINIMAL
config LIBC_NUMBERED_ARGS
bool "Enable numbered arguments in printf"
default n
depends on (LIBC_FLOATINGPOINT || LIBC_LONG_LONG || !LIBC_PRINT_MINIMAL) && !LIBC_PRINT_LEGACY && EXPERIMENTAL
depends on (LIBC_FLOATINGPOINT || LIBC_LONG_LONG || !LIBC_PRINT_MINIMAL) && !LIBC_PRINT_LEGACY
---help---
Enables support for numbered arguments in printf.
printf("%3$s %3$s %1$s %2$s\n", "1", "2", "3"); --> "3 3 1 2"
printf("%3$*2$.*1$f\n", 4, 8, 1.234567); --> " 1.2346"
Attention mixing of numbered and traditional arguments in one
Attention: Mixing of numbered and sequential arguments in one
format string is not allowed according to POSIX.
config LIBC_NL_ARGMAX
int "Maximum number of numbered arguments for printf"
default 16
depends on LIBC_NUMBERED_ARGS
---help---
Applies only if there are numbered arguments in your format string.
The number of sequential arguments isn't affected.
Will be copied into stdio POSIX macro NL_ARGMAX.
Attention: Increasing this value will increase stack usage
of printf.
config LIBC_SCANSET
bool "Scanset support"
default n

View File

@ -46,6 +46,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <nuttx/streams.h>
@ -71,7 +72,7 @@
#if defined(CONFIG_LIBC_FLOATINGPOINT)
# define PRINTF_LEVEL PRINTF_FLT
#elif defined(CONFIG_LIB_LONG_LONG) || !defined(CONFIG_LIBC_PRINT_MINIMAL)
#elif defined(CONFIG_LIBC_LONG_LONG) || !defined(CONFIG_LIBC_PRINT_MINIMAL)
# define PRINTF_LEVEL PRINTF_STD
#else
# define PRINTF_LEVEL PRINTF_MIN
@ -122,6 +123,12 @@
# define FL_FLTEXP 0x4000
# define FL_FLTFIX 0x8000
# define TYPE_INT 1
# define TYPE_LONG 2
# define TYPE_LONG_LONG 3
# define TYPE_DOUBLE 4
# define TYPE_CHAR_POINTER 5
#endif
/* Support special access to CODE-space strings for Harvard architectures */
@ -132,201 +139,46 @@
# define fmt_char(fmt) (*(fmt)++)
#endif
/****************************************************************************
* Private Types
****************************************************************************/
#if PRINTF_LEVEL > PRINTF_MIN
struct arg
{
unsigned char type;
union
{
unsigned int u;
unsigned long ul;
#ifdef CONFIG_LIBC_LONG_LONG
unsigned long long ull;
#endif
double d;
FAR char *cp;
} value;
};
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
#if PRINTF_LEVEL <= PRINTF_MIN
int lib_vsprintf(FAR struct lib_outstream_s *stream,
FAR const IPTR char *fmt, va_list ap)
#if PRINTF_LEVEL > PRINTF_MIN
static int vsprintf_internal(FAR struct lib_outstream_s *stream,
FAR struct arg *arglist, int numargs,
FAR const IPTR char *fmt, va_list ap)
{
unsigned char c; /* Holds a char from the format string */
unsigned char flags;
unsigned char buf[11]; /* Size for -1 in octal, without '\0' */
int total_len = 0;
for (; ; )
{
for (; ; )
{
c = fmt_char(fmt);
if (c == '\0')
{
goto ret;
}
if (c == '%')
{
c = fmt_char(fmt);
if (c != '%')
{
break;
}
}
putc(c, stream);
}
for (flags = 0; !(flags & FL_LONG); /* 'll' will detect as error */
c = fmt_char(fmt))
{
if (c != '\0' && strchr(" +-.0123456789h", c) != NULL)
{
continue;
}
if (c == '#')
{
flags |= FL_ALT;
continue;
}
if (c == 'l')
{
flags |= FL_LONG;
continue;
}
break;
}
/* Only a format character is valid. */
if (c && strchr("EFGefg", c))
{
(void)va_arg(ap, double);
putc('?', stream);
continue;
}
{
FAR const char *pnt;
switch (c)
{
case 'c':
putc(va_arg(ap, int), stream);
continue;
case 'S':
/* FALLTHROUGH */
case 's':
pnt = va_arg(ap, FAR char *);
while ((c = *pnt++) != 0)
{
putc(c, stream);
}
continue;
}
}
if (c == 'd' || c == 'i')
{
long x = (flags & FL_LONG) ? va_arg(ap, long) : va_arg(ap, int);
flags &= ~FL_ALT;
if (x < 0)
{
x = -x;
/* `putc ('-', stream)' will considarably inlarge stack size. So
* flag is used.
*/
flags |= FL_NEGATIVE;
}
c = __ultoa_invert(x, (FAR char *)buf, 10) - (FAR char *)buf;
}
else
{
int base;
switch (c)
{
case 'u':
flags &= ~FL_ALT;
base = 10;
goto ultoa;
case 'o':
base = 8;
goto ultoa;
case 'p':
flags |= FL_ALT;
/* no break */
case 'x':
flags |= (FL_ALTHEX | FL_ALTLWR);
base = 16;
goto ultoa;
case 'X':
flags |= FL_ALTHEX;
base = 16 | XTOA_UPPER;
ultoa:
c = __ultoa_invert((flags & FL_LONG)
? va_arg(ap, unsigned long)
: va_arg(ap, unsigned int),
(FAR char *)buf, base) - (FAR char *)buf;
break;
default:
goto ret;
}
}
/* Integer number output. */
if ((flags & FL_NEGATIVE) != 0)
{
putc('-', stream);
}
if ((flags & FL_ALT) != 0 && buf[c - 1] != '0')
{
putc('0', stream);
if ((flags & FL_ALTHEX) != 0)
{
# if FL_ALTLWR != 'x' - 'X'
# error
# endif
putc('X' + (flags & FL_ALTLWR), stream);
}
}
do
{
putc(buf[--c], stream);
}
while (c);
}
ret:
return total_len;
}
#else /* i.e. PRINTF_LEVEL > PRINTF_MIN */
int lib_vsprintf(FAR struct lib_outstream_s *stream,
FAR const IPTR char *fmt, va_list ap)
{
unsigned char c; /* Holds a char from the format string */
unsigned char c; /* Holds a char from the format string */
uint16_t flags;
int width;
int prec;
union
{
#ifdef CONFIG_LIBC_LONG_LONG
unsigned char __buf[22]; /* Size for -1 in octal, without '\0' */
#if defined (CONFIG_LIBC_LONG_LONG) || (ULONG_MAX > 4294967295UL)
unsigned char __buf[22]; /* Size for -1 in octal, without '\0' */
#else
unsigned char __buf[11]; /* Size for -1 in octal, without '\0' */
unsigned char __buf[11]; /* Size for -1 in octal, without '\0' */
#endif
#if PRINTF_LEVEL >= PRINTF_FLT
struct dtoa_s __dtoa;
@ -342,12 +194,9 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
int total_len = 0;
#ifdef CONFIG_LIBC_NUMBERED_ARGS
int argnumber;
va_list work_ap;
va_copy(work_ap, ap);
#else
# define work_ap ap
#endif
for (; ; )
@ -369,7 +218,14 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
}
}
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if (stream != NULL)
{
putc(c, stream);
}
#else
putc(c, stream);
#endif
}
flags = 0;
@ -378,7 +234,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
do
{
if (flags < FL_WIDTH)
if (flags < FL_ASTERISK)
{
switch (c)
{
@ -412,6 +268,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
{
if ((flags & FL_ARGNUMBER) == 0)
{
/* No other flag except FL_WIDTH or FL_ZFILL (leading
* zeros) and argument number must be at least 1
*/
@ -425,38 +282,48 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
/* It had been the argument number. */
argnumber = width;
flags |= FL_ARGNUMBER;
width = 0;
flags &= ~(FL_WIDTH | FL_ZFILL);
flags = FL_ARGNUMBER;
}
else if ((flags & FL_ASTERISK) != 0)
{
int index;
flags &= ~FL_ASTERISK;
va_end(work_ap);
va_copy(work_ap, ap);
if ((flags & FL_PREC) == 0)
{
/* Jump to argument */
while (--width)
{
(void)va_arg(work_ap, int);
}
width = va_arg(work_ap, int);
index = width;
}
else
{
/* Jump to argument */
while (--prec)
index = prec;
}
if (index > 0 && index <= numargs)
{
if (stream == NULL)
{
(void)va_arg(work_ap, int);
arglist[index-1].type = TYPE_INT;
if (index > total_len)
{
total_len = index;
}
}
prec = va_arg(work_ap, int);
else
{
if ((flags & FL_PREC) == 0)
{
width = (int)arglist[index-1].value.u;
}
else
{
prec = (int)arglist[index-1].value.u;
}
}
}
else
{
goto ret;
}
}
else
@ -494,7 +361,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
if ((flags & FL_PREC) != 0)
{
prec = va_arg(work_ap, int);
prec = va_arg(ap, int);
if (prec < 0)
{
prec = 0;
@ -502,7 +369,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
}
else
{
width = va_arg(work_ap, int);
width = va_arg(ap, int);
flags |= FL_WIDTH;
if (width < 0)
@ -557,26 +424,86 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
/* Only a format character is valid. */
# if 'F' != 'E'+1 || 'G' != 'F'+1 || 'f' != 'e'+1 || 'g' != 'f'+1
# error
# endif
#if 'F' != 'E'+1 || 'G' != 'F'+1 || 'f' != 'e'+1 || 'g' != 'f'+1
# error
#endif
# ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
if (c == 'p')
{
/* Jump to argument */
/* Determine size of pointer and set flags accordingly */
va_end(work_ap);
va_copy(work_ap, ap);
flags &= ~(FL_LONG | FL_REPD_TYPE);
while (--argnumber)
#ifdef CONFIG_LIBC_LONG_LONG
if (sizeof(void *) == sizeof(unsigned long long))
{
(void)va_arg(work_ap, int);
flags |= (FL_LONG | FL_REPD_TYPE);
}
else
#endif
if (sizeof(void *) == sizeof(unsigned long))
{
flags |= FL_LONG;
}
}
# endif
# if PRINTF_LEVEL >= PRINTF_FLT
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
if (argnumber > 0 && argnumber <= numargs)
{
if (stream == NULL)
{
if ((c >= 'E' && c <= 'G')
|| (c >= 'e' && c <= 'g'))
{
arglist[argnumber-1].type = TYPE_DOUBLE;
}
else if (c == 'i' || c == 'd' || c == 'u' || c == 'p')
{
if ((flags & FL_LONG) == 0)
{
arglist[argnumber-1].type = TYPE_INT;
}
else if ((flags & FL_REPD_TYPE) == 0)
{
arglist[argnumber-1].type = TYPE_LONG;
}
else
{
arglist[argnumber-1].type = TYPE_LONG_LONG;
}
}
else if (c == 'c')
{
arglist[argnumber-1].type = TYPE_INT;
}
else if (c == 's')
{
arglist[argnumber-1].type = TYPE_CHAR_POINTER;
}
if (argnumber > total_len)
{
total_len = argnumber;
}
continue; /* We do only parsing */
}
}
else
{
goto ret;
}
}
else if (stream == NULL)
{
continue; /* We do only parsing */
}
#endif
#if PRINTF_LEVEL >= PRINTF_FLT
if (c >= 'E' && c <= 'G')
{
flags |= FL_FLTUPP;
@ -585,6 +512,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
}
else if (c >= 'e' && c <= 'g')
{
double value;
int exp; /* Exponent of master decimal digit */
int n;
uint8_t sign; /* Sign character (or 0) */
@ -594,7 +522,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
flags &= ~FL_FLTUPP;
flt_oper:
flt_oper:
ndigs = 0;
if ((flags & FL_PREC) == 0)
{
@ -626,9 +554,22 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
ndigs = DTOA_MAX_DIG;
}
ndigs = __dtoa_engine(va_arg(work_ap, double), &_dtoa, ndigs,
ndecimal);
exp = _dtoa.exp;
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
value = arglist[argnumber-1].value.d;
}
else
{
value = va_arg(ap, double);
}
#else
value = va_arg(ap, double);
#endif
ndigs = __dtoa_engine(value, &_dtoa, ndigs,
ndecimal);
exp = _dtoa.exp;
sign = 0;
if ((_dtoa.flags & DTOA_MINUS) && !(_dtoa.flags & DTOA_NAN))
@ -677,9 +618,9 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
p = "nan";
}
# if ('I'-'i' != 'N'-'n') || ('I'-'i' != 'F'-'f') || ('I'-'i' != 'A'-'a')
# error
# endif
# if ('I'-'i' != 'N'-'n') || ('I'-'i' != 'F'-'f') || ('I'-'i' != 'A'-'a')
# error
# endif
while ((ndigs = *p) != 0)
{
if ((flags & FL_FLTUPP) != 0)
@ -792,7 +733,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
* the exponent value
*/
n = exp > 0 ? exp : 0; /* Exponent of left digit */
n = exp > 0 ? exp : 0; /* Exponent of left digit */
do
{
@ -828,7 +769,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
}
while (1);
if (n == exp && (_dtoa.digits[0] > '5' ||
if (n == exp && (_dtoa.digits[0] > '5' ||
(_dtoa.digits[0] == '5' && !(_dtoa.flags & DTOA_CARRY))))
{
out = '1';
@ -887,28 +828,50 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
goto tail;
}
# else /* to: PRINTF_LEVEL >= PRINTF_FLT */
#else /* to: PRINTF_LEVEL >= PRINTF_FLT */
if ((c >= 'E' && c <= 'G') || (c >= 'e' && c <= 'g'))
{
(void)va_arg(work_ap, double);
(void)va_arg(ap, double);
pnt = "*float*";
size = sizeof("*float*") - 1;
goto str_lpad;
}
# endif
#endif
switch (c)
{
case 'c':
buf[0] = va_arg(work_ap, int);
pnt = (FAR char *)buf;
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
buf[0] = (int)arglist[argnumber-1].value.u;
}
else
{
buf[0] = va_arg(ap, int);
}
#else
buf[0] = va_arg(ap, int);
#endif
pnt = (FAR char *) buf;
size = 1;
goto str_lpad;
case 's':
case 'S':
pnt = va_arg(work_ap, FAR char *);
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
pnt = (FAR char *)arglist[argnumber-1].value.cp;
}
else
{
pnt = va_arg(ap, FAR char *);
}
#else
pnt = va_arg(ap, FAR char *);
#endif
size = strnlen(pnt, (flags & FL_PREC) ? prec : ~0);
str_lpad:
@ -944,17 +907,50 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
if ((flags & FL_LONG) != 0 && (flags & FL_REPD_TYPE) != 0)
{
x = va_arg(work_ap, long long);
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
x = (long long)arglist[argnumber-1].value.ull;
}
else
{
x = va_arg(ap, long long);
}
#else
x = va_arg(ap, long long);
#endif
}
else
#endif
if ((flags & FL_LONG) != 0)
{
x = va_arg(work_ap, long);
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
x = (long)arglist[argnumber-1].value.ul;
}
else
{
x = va_arg(ap, long);
}
#else
x = va_arg(ap, long);
#endif
}
else
{
x = va_arg(work_ap, int);
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
x = (int)arglist[argnumber-1].value.u;
}
else
{
x = va_arg(ap, int);
}
#else
x = va_arg(ap, int);
#endif
if ((flags & FL_SHORT) != 0)
{
if ((flags & FL_REPD_TYPE) == 0)
@ -994,17 +990,50 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
if ((flags & FL_LONG) != 0 && (flags & FL_REPD_TYPE) != 0)
{
x = va_arg(work_ap, unsigned long long);
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
x = arglist[argnumber-1].value.ull;
}
else
{
x = va_arg(ap, unsigned long long);
}
#else
x = va_arg(ap, unsigned long long);
#endif
}
else
#endif
if ((flags & FL_LONG) != 0)
{
x = va_arg(work_ap, unsigned long);
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
x = arglist[argnumber-1].value.ul;
}
else
{
x = va_arg(ap, unsigned long);
}
#else
x = va_arg(ap, unsigned long);
#endif
}
else
{
x = va_arg(work_ap, unsigned int);
#ifdef CONFIG_LIBC_NUMBERED_ARGS
if ((flags & FL_ARGNUMBER) != 0)
{
x = (unsigned int)arglist[argnumber-1].value.u;
}
else
{
x = va_arg(ap, unsigned int);
}
#else
x = va_arg(ap, unsigned int);
#endif
if ((flags & FL_SHORT) != 0)
{
if ((flags & FL_REPD_TYPE) == 0)
@ -1163,9 +1192,9 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
putc(buf[--c], stream);
}
tail:
tail:
/* Tail is possible. */
/* Tail is possible. */
while (width)
{
@ -1176,11 +1205,249 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream,
ret:
#ifdef CONFIG_LIBC_NUMBERED_ARGS
va_end(work_ap);
return total_len;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
#if PRINTF_LEVEL <= PRINTF_MIN
int lib_vsprintf(FAR struct lib_outstream_s *stream,
FAR const IPTR char *fmt, va_list ap)
{
unsigned char c; /* Holds a char from the format string */
unsigned char flags;
unsigned char buf[11]; /* Size for -1 in octal, without '\0' */
int total_len = 0;
for (; ; )
{
for (; ; )
{
c = fmt_char(fmt);
if (c == '\0')
{
goto ret;
}
if (c == '%')
{
c = fmt_char(fmt);
if (c != '%')
{
break;
}
}
putc(c, stream);
}
for (flags = 0; !(flags & FL_LONG); /* 'll' will detect as error */
c = fmt_char(fmt))
{
if (c != '\0' && strchr(" +-.0123456789h", c) != NULL)
{
continue;
}
if (c == '#')
{
flags |= FL_ALT;
continue;
}
if (c == 'l')
{
flags |= FL_LONG;
continue;
}
break;
}
/* Only a format character is valid. */
if (c && strchr("EFGefg", c))
{
(void)va_arg(ap, double);
putc('?', stream);
continue;
}
{
FAR const char *pnt;
switch (c)
{
case 'c':
putc(va_arg(ap, int), stream);
continue;
case 'S':
/* FALLTHROUGH */
case 's':
pnt = va_arg(ap, FAR char *);
while ((c = *pnt++) != 0)
{
putc(c, stream);
}
continue;
}
}
if (c == 'd' || c == 'i')
{
long x = (flags & FL_LONG) ? va_arg(ap, long) : va_arg(ap, int);
flags &= ~FL_ALT;
if (x < 0)
{
x = -x;
/* `putc ('-', stream)' will considarably inlarge stack size. So
* flag is used.
*/
flags |= FL_NEGATIVE;
}
c = __ultoa_invert(x, (FAR char *)buf, 10) - (FAR char *)buf;
}
else
{
int base;
switch (c)
{
case 'u':
flags &= ~FL_ALT;
base = 10;
goto ultoa;
case 'o':
base = 8;
goto ultoa;
case 'p':
/* Determine size of pointer and set flags accordingly */
if (sizeof(FAR void *) == sizeof(unsigned long))
{
flags |= FL_LONG;
}
else
{
flags &= ~FL_LONG;
}
flags |= FL_ALT;
/* no break */
case 'x':
flags |= (FL_ALTHEX | FL_ALTLWR);
base = 16;
goto ultoa;
case 'X':
flags |= FL_ALTHEX;
base = 16 | XTOA_UPPER;
ultoa:
c = __ultoa_invert((flags & FL_LONG)
? va_arg(ap, unsigned long)
: va_arg(ap, unsigned int),
(FAR char *)buf, base) - (FAR char *)buf;
break;
default:
goto ret;
}
}
/* Integer number output. */
if ((flags & FL_NEGATIVE) != 0)
{
putc('-', stream);
}
if ((flags & FL_ALT) != 0 && buf[c - 1] != '0')
{
putc('0', stream);
if ((flags & FL_ALTHEX) != 0)
{
#if FL_ALTLWR != 'x' - 'X'
# error
#endif
putc('X' + (flags & FL_ALTLWR), stream);
}
}
do
{
putc(buf[--c], stream);
}
while (c);
}
ret:
return total_len;
}
#else /* i.e. PRINTF_LEVEL > PRINTF_MIN */
int lib_vsprintf(FAR struct lib_outstream_s *stream,
FAR const IPTR char *fmt, va_list ap)
{
#ifdef CONFIG_LIBC_NUMBERED_ARGS
int i;
struct arg arglist[NL_ARGMAX];
int numargs;
/* We do 2 passes of parsing and fill the arglist between the passes. */
numargs = vsprintf_internal(NULL, arglist, NL_ARGMAX, fmt, ap);
for (i = 0; i < numargs; i++)
{
switch (arglist[i].type)
{
case TYPE_LONG_LONG:
#ifdef CONFIG_LIBC_LONG_LONG
arglist[i].value.ull = va_arg(ap, unsigned long long);
break;
#endif
case TYPE_LONG:
arglist[i].value.ul = va_arg(ap, unsigned long);
break;
case TYPE_INT:
arglist[i].value.u = va_arg(ap, unsigned int);
break;
case TYPE_DOUBLE:
arglist[i].value.d = va_arg(ap, double);
break;
case TYPE_CHAR_POINTER:
arglist[i].value.cp = va_arg(ap, FAR char *);
break;
}
}
return vsprintf_internal(stream, arglist, numargs, fmt, ap);
#else
return vsprintf_internal(stream, NULL, 0, fmt, ap);
#endif
}
#endif /* PRINTF_LEVEL > PRINTF_MIN */