mirror of
https://github.com/apache/nuttx.git
synced 2026-06-07 01:05:54 +08:00
Add support for accessing printf, sprintf, puts, etc. strings that do not lie in the MCU data space
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3738 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
+1
-1
@@ -124,7 +124,7 @@ extern int lib_sprintf(FAR struct lib_outstream_s *obj,
|
||||
/* Defined lib_libvsprintf.c */
|
||||
|
||||
extern int lib_vsprintf(FAR struct lib_outstream_s *obj,
|
||||
const char *src, va_list ap);
|
||||
FAR const char *src, va_list ap);
|
||||
|
||||
/* Defined lib_rawprintf.c */
|
||||
|
||||
|
||||
+52
-1
@@ -41,9 +41,14 @@
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include "lib_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
@@ -90,7 +95,53 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_ARCH_ROMGETC)
|
||||
int fputs(FAR const char *s, FAR FILE *stream)
|
||||
{
|
||||
int nput;
|
||||
int ret;
|
||||
char ch;
|
||||
|
||||
/* Make sure that a string was provided. */
|
||||
|
||||
#ifdef CONFIG_DEBUG /* Most parameter checking is disabled if DEBUG is off */
|
||||
if (!s)
|
||||
{
|
||||
set_errno(EINVAL);
|
||||
return EOF;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write the string. Loop until the null terminator is encountered */
|
||||
|
||||
for (nput = 0, ch = up_romgetc(s); ch; nput++, s++, ch = up_romgetc(s))
|
||||
{
|
||||
/* Write the next character to the stream buffer */
|
||||
|
||||
ret = lib_fwrite(&ch, 1, stream);
|
||||
if (ret <= 0)
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Flush the buffer if a newline was written to the buffer */
|
||||
|
||||
#ifdef CONFIG_STDIO_LINEBUFFER
|
||||
if (ch == '\n')
|
||||
{
|
||||
ret = lib_fflush(stream, true);
|
||||
if (ret < 0)
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return nput;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_STDIO_LINEBUFFER)
|
||||
int fputs(FAR const char *s, FAR FILE *stream)
|
||||
{
|
||||
int nput;
|
||||
@@ -118,7 +169,7 @@ int fputs(FAR const char *s, FAR FILE *stream)
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Flush the buffer if a newline was writen to the buffer */
|
||||
/* Flush the buffer if a newline was written to the buffer */
|
||||
|
||||
if (*s == '\n')
|
||||
{
|
||||
|
||||
+95
-50
@@ -44,6 +44,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include "lib_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
@@ -96,6 +98,33 @@ enum
|
||||
#define IS_NEGATE(f) (((f) & FLAG_NEGATE) != 0)
|
||||
#define IS_SIGNED(f) (((f) & (FLAG_SHOWPLUS|FLAG_NEGATE)) != 0)
|
||||
|
||||
/* If CONFIG_ARCH_ROMGETC is defined, then it is assumed that the format
|
||||
* string data cannot be accessed by simply de-referencing the format string
|
||||
* pointer. This might be in the case in Harvard architectures where string
|
||||
* data might be stored in instruction space or if string data were stored
|
||||
* on some media like EEPROM or external serial FLASH. In all of these cases,
|
||||
* string data has to be accessed indirectly using the architecture-supplied
|
||||
* up_romgetc(). The following mechanisms attempt to make these different
|
||||
* access methods indistinguishable in the following code.
|
||||
*
|
||||
* NOTE: It is assumed that string arguments for %s still reside in memory
|
||||
* that can be directly accessed by de-referencing the string pointer.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARCH_ROMGETC
|
||||
# define FMT_TOP ch = up_romgetc(src) /* Loop initialization */
|
||||
# define FMT_BOTTOM src++, ch = up_romgetc(src) /* Bottom of a loop */
|
||||
# define FMT_CHAR ch /* Access a character */
|
||||
# define FMT_NEXT src++; ch = up_romgetc(src) /* Advance to the next character */
|
||||
# define FMT_PREV src--; ch = up_romgetc(src) /* Backup to the previous character */
|
||||
#else
|
||||
# define FMT_TOP /* Loop initialization */
|
||||
# define FMT_BOTTOM src++ /* Bottom of a loop */
|
||||
# define FMT_CHAR *src /* Access a character */
|
||||
# define FMT_NEXT src++ /* Advance to the next character */
|
||||
# define FMT_PREV src-- /* Backup to the previous character */
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Type Declarations
|
||||
****************************************************************************/
|
||||
@@ -1111,30 +1140,33 @@ static void postjustify(FAR struct lib_outstream_s *obj, uint8_t fmt,
|
||||
* lib/stdio/lib_vsprintf
|
||||
****************************************************************************/
|
||||
|
||||
int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
int lib_vsprintf(FAR struct lib_outstream_s *obj, FAR const char *src, va_list ap)
|
||||
{
|
||||
char *ptmp;
|
||||
FAR char *ptmp;
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
int width;
|
||||
int trunc;
|
||||
uint8_t fmt;
|
||||
#endif
|
||||
uint8_t flags;
|
||||
#ifdef CONFIG_ARCH_ROMGETC
|
||||
char ch;
|
||||
#endif
|
||||
|
||||
for (; *src; src++)
|
||||
for (FMT_TOP; FMT_CHAR; FMT_BOTTOM)
|
||||
{
|
||||
/* Just copy regular characters */
|
||||
|
||||
if (*src != '%')
|
||||
if (FMT_CHAR != '%')
|
||||
{
|
||||
/* Output the character */
|
||||
|
||||
obj->put(obj, *src);
|
||||
obj->put(obj, FMT_CHAR);
|
||||
|
||||
/* Flush the buffer if a newline is encountered */
|
||||
|
||||
#ifdef CONFIG_STDIO_LINEBUFFER
|
||||
if (*src == '\n')
|
||||
if (FMT_CHAR == '\n')
|
||||
{
|
||||
/* Should return an error on a failure to flush */
|
||||
|
||||
@@ -1148,7 +1180,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* We have found a format specifier. Move past it. */
|
||||
|
||||
src++;
|
||||
FMT_NEXT;
|
||||
|
||||
/* Assume defaults */
|
||||
|
||||
@@ -1161,18 +1193,18 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Process each format qualifier. */
|
||||
|
||||
for (; *src; src++)
|
||||
for (; FMT_CHAR; FMT_BOTTOM)
|
||||
{
|
||||
/* Break out of the loop when the format is known. */
|
||||
|
||||
if (strchr("diuxXpobeEfgGlLsc%", *src))
|
||||
if (strchr("diuxXpobeEfgGlLsc%", FMT_CHAR))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for left justification. */
|
||||
|
||||
else if (*src == '-')
|
||||
else if (FMT_CHAR == '-')
|
||||
{
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
fmt = FMT_LJUST;
|
||||
@@ -1181,7 +1213,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Check for leading zero fill right justification. */
|
||||
|
||||
else if (*src == '0')
|
||||
else if (FMT_CHAR == '0')
|
||||
{
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
fmt = FMT_RJUST0;
|
||||
@@ -1190,7 +1222,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
#if 0
|
||||
/* Center justification. */
|
||||
|
||||
else if (*src == '~')
|
||||
else if (FMT_CHAR == '~')
|
||||
{
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
fmt = FMT_CENTER;
|
||||
@@ -1198,7 +1230,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
}
|
||||
#endif
|
||||
|
||||
else if (*src == '*')
|
||||
else if (FMT_CHAR == '*')
|
||||
{
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
int value = va_arg(ap, int);
|
||||
@@ -1217,17 +1249,29 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Check for field width */
|
||||
|
||||
else if (*src >= '1' && *src <= '9')
|
||||
else if (FMT_CHAR >= '1' && FMT_CHAR <= '9')
|
||||
{
|
||||
#ifdef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
for (src++; (*src >= '0' && *src <= '9'); src++);
|
||||
do
|
||||
{
|
||||
FMT_NEXT;
|
||||
}
|
||||
while (FMT_CHAR >= '0' && FMT_CHAR <= '9');
|
||||
#else
|
||||
/* Accumulate the field width integer. */
|
||||
|
||||
int n = ((int)(*src)) - (int)'0';
|
||||
for (src++; (*src >= '0' && *src <= '9'); src++)
|
||||
int n = ((int)(FMT_CHAR)) - (int)'0';
|
||||
for (;;)
|
||||
{
|
||||
n = 10*n + (((int)(*src)) - (int)'0');
|
||||
FMT_NEXT;
|
||||
if (FMT_CHAR >= '0' && FMT_CHAR <= '9')
|
||||
{
|
||||
n = 10*n + (((int)(FMT_CHAR)) - (int)'0');
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_HASDOT(flags))
|
||||
@@ -1241,12 +1285,12 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
#endif
|
||||
/* Back up to the last digit. */
|
||||
|
||||
src--;
|
||||
FMT_PREV;
|
||||
}
|
||||
|
||||
/* Check for a decimal point. */
|
||||
|
||||
else if (*src == '.')
|
||||
else if (FMT_CHAR == '.')
|
||||
{
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
SET_HASDOT(flags);
|
||||
@@ -1255,14 +1299,14 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Check for leading plus sign. */
|
||||
|
||||
else if (*src == '+')
|
||||
else if (FMT_CHAR == '+')
|
||||
{
|
||||
SET_SHOWPLUS(flags);
|
||||
}
|
||||
|
||||
/* Check for alternate form. */
|
||||
|
||||
else if (*src == '#')
|
||||
else if (FMT_CHAR == '#')
|
||||
{
|
||||
SET_ALTFORM(flags);
|
||||
}
|
||||
@@ -1272,7 +1316,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
* specification).
|
||||
*/
|
||||
|
||||
if (*src == '%')
|
||||
if (FMT_CHAR == '%')
|
||||
{
|
||||
obj->put(obj, '%');
|
||||
continue;
|
||||
@@ -1280,7 +1324,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Check for the string format. */
|
||||
|
||||
if (*src == 's')
|
||||
if (FMT_CHAR == 's')
|
||||
{
|
||||
/* Just concatenate the string into the output */
|
||||
|
||||
@@ -1300,7 +1344,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Check for the character output */
|
||||
|
||||
else if (*src == 'c')
|
||||
else if (FMT_CHAR == 'c')
|
||||
{
|
||||
/* Just copy the character into the output. */
|
||||
|
||||
@@ -1311,27 +1355,28 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Check for the long long prefix. */
|
||||
|
||||
if (*src == 'L')
|
||||
if (FMT_CHAR == 'L')
|
||||
{
|
||||
SET_LONGLONGPRECISION(flags);
|
||||
++src;
|
||||
FMT_NEXT;
|
||||
}
|
||||
else if (*src == 'l')
|
||||
else if (FMT_CHAR == 'l')
|
||||
{
|
||||
SET_LONGPRECISION(flags);
|
||||
if (*++src == 'l')
|
||||
FMT_NEXT;
|
||||
if (FMT_CHAR == 'l')
|
||||
{
|
||||
SET_LONGLONGPRECISION(flags);
|
||||
++src;
|
||||
FMT_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle integer conversions */
|
||||
|
||||
if (strchr("diuxXpob", *src))
|
||||
if (strchr("diuxXpob", FMT_CHAR))
|
||||
{
|
||||
#ifdef CONFIG_HAVE_LONG_LONG
|
||||
if (IS_LONGLONGPRECISION(flags) && *src != 'p')
|
||||
if (IS_LONGLONGPRECISION(flags) && FMT_CHAR != 'p')
|
||||
{
|
||||
long long lln;
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
@@ -1344,15 +1389,15 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
#ifdef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
/* Output the number */
|
||||
|
||||
llutoascii(obj, *src, flags, (unsigned long long)lln);
|
||||
llutoascii(obj, FMT_CHAR, flags, (unsigned long long)lln);
|
||||
#else
|
||||
/* Resolve sign-ness and format issues */
|
||||
|
||||
llfixup(*src, &flags, &lln);
|
||||
llfixup(FMT_CHAR, &flags, &lln);
|
||||
|
||||
/* Get the width of the output */
|
||||
|
||||
lluwidth = getllusize(*src, flags, lln);
|
||||
lluwidth = getllusize(FMT_CHAR, flags, lln);
|
||||
|
||||
/* Perform left field justification actions */
|
||||
|
||||
@@ -1360,7 +1405,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Output the number */
|
||||
|
||||
llutoascii(obj, *src, flags, (unsigned long long)lln);
|
||||
llutoascii(obj, FMT_CHAR, flags, (unsigned long long)lln);
|
||||
|
||||
/* Perform right field justification actions */
|
||||
|
||||
@@ -1370,7 +1415,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
else
|
||||
#endif /* CONFIG_HAVE_LONG_LONG */
|
||||
#ifdef CONFIG_LONG_IS_NOT_INT
|
||||
if (IS_LONGPRECISION(flags) && *src != 'p')
|
||||
if (IS_LONGPRECISION(flags) && FMT_CHAR != 'p')
|
||||
{
|
||||
long ln;
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
@@ -1383,15 +1428,15 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
#ifdef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
/* Output the number */
|
||||
|
||||
lutoascii(obj, *src, flags, (unsigned long)ln);
|
||||
lutoascii(obj, FMT_CHAR, flags, (unsigned long)ln);
|
||||
#else
|
||||
/* Resolve sign-ness and format issues */
|
||||
|
||||
lfixup(*src, &flags, &ln);
|
||||
lfixup(FMT_CHAR, &flags, &ln);
|
||||
|
||||
/* Get the width of the output */
|
||||
|
||||
luwidth = getlusize(*src, flags, ln);
|
||||
luwidth = getlusize(FMT_CHAR, flags, ln);
|
||||
|
||||
/* Perform left field justification actions */
|
||||
|
||||
@@ -1399,7 +1444,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Output the number */
|
||||
|
||||
lutoascii(obj, *src, flags, (unsigned long)ln);
|
||||
lutoascii(obj, FMT_CHAR, flags, (unsigned long)ln);
|
||||
|
||||
/* Perform right field justification actions */
|
||||
|
||||
@@ -1409,7 +1454,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
else
|
||||
#endif /* CONFIG_LONG_IS_NOT_INT */
|
||||
#ifdef CONFIG_PTR_IS_NOT_INT
|
||||
if (*src == 'p')
|
||||
if (FMT_CHAR == 'p')
|
||||
{
|
||||
void *p;
|
||||
#ifndef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
@@ -1426,11 +1471,11 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
#else
|
||||
/* Resolve sign-ness and format issues */
|
||||
|
||||
lfixup(*src, &flags, &ln);
|
||||
lfixup(FMT_CHAR, &flags, &ln);
|
||||
|
||||
/* Get the width of the output */
|
||||
|
||||
luwidth = getpsize(*src, flags, p);
|
||||
luwidth = getpsize(FMT_CHAR, flags, p);
|
||||
|
||||
/* Perform left field justification actions */
|
||||
|
||||
@@ -1459,15 +1504,15 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
#ifdef CONFIG_NOPRINTF_FIELDWIDTH
|
||||
/* Output the number */
|
||||
|
||||
utoascii(obj, *src, flags, (unsigned int)n);
|
||||
utoascii(obj, FMT_CHAR, flags, (unsigned int)n);
|
||||
#else
|
||||
/* Resolve sign-ness and format issues */
|
||||
|
||||
fixup(*src, &flags, &n);
|
||||
fixup(FMT_CHAR, &flags, &n);
|
||||
|
||||
/* Get the width of the output */
|
||||
|
||||
uwidth = getusize(*src, flags, n);
|
||||
uwidth = getusize(FMT_CHAR, flags, n);
|
||||
|
||||
/* Perform left field justification actions */
|
||||
|
||||
@@ -1475,7 +1520,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
|
||||
/* Output the number */
|
||||
|
||||
utoascii(obj, *src, flags, (unsigned int)n);
|
||||
utoascii(obj, FMT_CHAR, flags, (unsigned int)n);
|
||||
|
||||
/* Perform right field justification actions */
|
||||
|
||||
@@ -1487,10 +1532,10 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, const char *src, va_list ap)
|
||||
/* Handle floating point conversions */
|
||||
|
||||
#ifdef CONFIG_LIBC_FLOATINGPOINT
|
||||
else if (strchr("eEfgG", *src))
|
||||
else if (strchr("eEfgG", FMT_CHAR))
|
||||
{
|
||||
double dblval = va_arg(ap, double);
|
||||
lib_dtoa(obj, *src, trunc, flags, dblval);
|
||||
lib_dtoa(obj, FMT_CHAR, trunc, flags, dblval);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user