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:
parent
146c398eff
commit
0059a5a88e
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user