1328 lines
42 KiB
C
1328 lines
42 KiB
C
/*
|
|
* The Clear BSD License
|
|
* Copyright 2017 NXP
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted (subject to the limitations in the disclaimer below) provided
|
|
* that the following conditions are met:
|
|
*
|
|
* o Redistributions of source code must retain the above copyright notice, this list
|
|
* of conditions and the following disclaimer.
|
|
*
|
|
* o Redistributions in binary form must reproduce the above copyright notice, this
|
|
* list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution.
|
|
*
|
|
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include "fsl_str.h"
|
|
#include "fsl_debug_console_conf.h"
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
/*! @brief The overflow value.*/
|
|
#ifndef HUGE_VAL
|
|
#define HUGE_VAL (99.e99)
|
|
#endif /* HUGE_VAL */
|
|
|
|
#if SCANF_FLOAT_ENABLE
|
|
static double fnum = 0.0;
|
|
#endif /* SCANF_FLOAT_ENABLE */
|
|
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
/*! @brief Specification modifier flags for printf. */
|
|
enum _debugconsole_printf_flag
|
|
{
|
|
kPRINTF_Minus = 0x01U, /*!< Minus FLag. */
|
|
kPRINTF_Plus = 0x02U, /*!< Plus Flag. */
|
|
kPRINTF_Space = 0x04U, /*!< Space Flag. */
|
|
kPRINTF_Zero = 0x08U, /*!< Zero Flag. */
|
|
kPRINTF_Pound = 0x10U, /*!< Pound Flag. */
|
|
kPRINTF_LengthChar = 0x20U, /*!< Length: Char Flag. */
|
|
kPRINTF_LengthShortInt = 0x40U, /*!< Length: Short Int Flag. */
|
|
kPRINTF_LengthLongInt = 0x80U, /*!< Length: Long Int Flag. */
|
|
kPRINTF_LengthLongLongInt = 0x100U, /*!< Length: Long Long Int Flag. */
|
|
};
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
|
|
/*! @brief Specification modifier flags for scanf. */
|
|
enum _debugconsole_scanf_flag
|
|
{
|
|
kSCANF_Suppress = 0x2U, /*!< Suppress Flag. */
|
|
kSCANF_DestMask = 0x7cU, /*!< Destination Mask. */
|
|
kSCANF_DestChar = 0x4U, /*!< Destination Char Flag. */
|
|
kSCANF_DestString = 0x8U, /*!< Destination String FLag. */
|
|
kSCANF_DestSet = 0x10U, /*!< Destination Set Flag. */
|
|
kSCANF_DestInt = 0x20U, /*!< Destination Int Flag. */
|
|
kSCANF_DestFloat = 0x30U, /*!< Destination Float Flag. */
|
|
kSCANF_LengthMask = 0x1f00U, /*!< Length Mask Flag. */
|
|
#if SCANF_ADVANCED_ENABLE
|
|
kSCANF_LengthChar = 0x100U, /*!< Length Char Flag. */
|
|
kSCANF_LengthShortInt = 0x200U, /*!< Length ShortInt Flag. */
|
|
kSCANF_LengthLongInt = 0x400U, /*!< Length LongInt Flag. */
|
|
kSCANF_LengthLongLongInt = 0x800U, /*!< Length LongLongInt Flag. */
|
|
#endif /* SCANF_ADVANCED_ENABLE */
|
|
#if PRINTF_FLOAT_ENABLE
|
|
kSCANF_LengthLongLongDouble = 0x1000U, /*!< Length LongLongDuoble Flag. */
|
|
#endif /*PRINTF_FLOAT_ENABLE */
|
|
kSCANF_TypeSinged = 0x2000U, /*!< TypeSinged Flag. */
|
|
};
|
|
|
|
/*! @brief Keil: suppress ellipsis warning in va_arg usage below. */
|
|
#if defined(__CC_ARM)
|
|
#pragma diag_suppress 1256
|
|
#endif /* __CC_ARM */
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
/*!
|
|
* @brief Scanline function which ignores white spaces.
|
|
*
|
|
* @param[in] s The address of the string pointer to update.
|
|
* @return String without white spaces.
|
|
*/
|
|
static uint32_t ScanIgnoreWhiteSpace(const char **s);
|
|
|
|
/*!
|
|
* @brief Converts a radix number to a string and return its length.
|
|
*
|
|
* @param[in] numstr Converted string of the number.
|
|
* @param[in] nump Pointer to the number.
|
|
* @param[in] neg Polarity of the number.
|
|
* @param[in] radix The radix to be converted to.
|
|
* @param[in] use_caps Used to identify %x/X output format.
|
|
|
|
* @return Length of the converted string.
|
|
*/
|
|
static int32_t ConvertRadixNumToString(char *numstr, void *nump, int32_t neg, int32_t radix, bool use_caps);
|
|
|
|
#if PRINTF_FLOAT_ENABLE
|
|
/*!
|
|
* @brief Converts a floating radix number to a string and return its length.
|
|
*
|
|
* @param[in] numstr Converted string of the number.
|
|
* @param[in] nump Pointer to the number.
|
|
* @param[in] radix The radix to be converted to.
|
|
* @param[in] precision_width Specify the precision width.
|
|
|
|
* @return Length of the converted string.
|
|
*/
|
|
static int32_t ConvertFloatRadixNumToString(char *numstr, void *nump, int32_t radix, uint32_t precision_width);
|
|
#endif /* PRINTF_FLOAT_ENABLE */
|
|
|
|
/*!
|
|
*
|
|
*/
|
|
double modf(double input_dbl, double *intpart_ptr);
|
|
|
|
/*************Code for process formatted data*******************************/
|
|
|
|
static uint32_t ScanIgnoreWhiteSpace(const char **s)
|
|
{
|
|
uint8_t count = 0;
|
|
uint8_t c;
|
|
|
|
c = **s;
|
|
while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\v') || (c == '\f'))
|
|
{
|
|
count++;
|
|
(*s)++;
|
|
c = **s;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static int32_t ConvertRadixNumToString(char *numstr, void *nump, int32_t neg, int32_t radix, bool use_caps)
|
|
{
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
int64_t a;
|
|
int64_t b;
|
|
int64_t c;
|
|
|
|
uint64_t ua;
|
|
uint64_t ub;
|
|
uint64_t uc;
|
|
#else
|
|
int32_t a;
|
|
int32_t b;
|
|
int32_t c;
|
|
|
|
uint32_t ua;
|
|
uint32_t ub;
|
|
uint32_t uc;
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
|
|
int32_t nlen;
|
|
char *nstrp;
|
|
|
|
nlen = 0;
|
|
nstrp = numstr;
|
|
*nstrp++ = '\0';
|
|
|
|
if (neg)
|
|
{
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
a = *(int64_t *)nump;
|
|
#else
|
|
a = *(int32_t *)nump;
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
if (a == 0)
|
|
{
|
|
*nstrp = '0';
|
|
++nlen;
|
|
return nlen;
|
|
}
|
|
while (a != 0)
|
|
{
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
b = (int64_t)a / (int64_t)radix;
|
|
c = (int64_t)a - ((int64_t)b * (int64_t)radix);
|
|
if (c < 0)
|
|
{
|
|
uc = (uint64_t)c;
|
|
c = (int64_t)(~uc) + 1 + '0';
|
|
}
|
|
#else
|
|
b = a / radix;
|
|
c = a - (b * radix);
|
|
if (c < 0)
|
|
{
|
|
uc = (uint32_t)c;
|
|
c = (uint32_t)(~uc) + 1 + '0';
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
else
|
|
{
|
|
c = c + '0';
|
|
}
|
|
a = b;
|
|
*nstrp++ = (char)c;
|
|
++nlen;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
ua = *(uint64_t *)nump;
|
|
#else
|
|
ua = *(uint32_t *)nump;
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
if (ua == 0)
|
|
{
|
|
*nstrp = '0';
|
|
++nlen;
|
|
return nlen;
|
|
}
|
|
while (ua != 0)
|
|
{
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
ub = (uint64_t)ua / (uint64_t)radix;
|
|
uc = (uint64_t)ua - ((uint64_t)ub * (uint64_t)radix);
|
|
#else
|
|
ub = ua / (uint32_t)radix;
|
|
uc = ua - (ub * (uint32_t)radix);
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
|
|
if (uc < 10)
|
|
{
|
|
uc = uc + '0';
|
|
}
|
|
else
|
|
{
|
|
uc = uc - 10 + (use_caps ? 'A' : 'a');
|
|
}
|
|
ua = ub;
|
|
*nstrp++ = (char)uc;
|
|
++nlen;
|
|
}
|
|
}
|
|
return nlen;
|
|
}
|
|
|
|
#if PRINTF_FLOAT_ENABLE
|
|
static int32_t ConvertFloatRadixNumToString(char *numstr, void *nump, int32_t radix, uint32_t precision_width)
|
|
{
|
|
int32_t a;
|
|
int32_t b;
|
|
int32_t c;
|
|
int32_t i;
|
|
uint32_t uc;
|
|
double fa;
|
|
double dc;
|
|
double fb;
|
|
double r;
|
|
double fractpart;
|
|
double intpart;
|
|
|
|
int32_t nlen;
|
|
char *nstrp;
|
|
nlen = 0;
|
|
nstrp = numstr;
|
|
*nstrp++ = '\0';
|
|
r = *(double *)nump;
|
|
if (!r)
|
|
{
|
|
*nstrp = '0';
|
|
++nlen;
|
|
return nlen;
|
|
}
|
|
fractpart = modf((double)r, (double *)&intpart);
|
|
/* Process fractional part. */
|
|
for (i = 0; i < precision_width; i++)
|
|
{
|
|
fractpart *= radix;
|
|
}
|
|
if (r >= 0)
|
|
{
|
|
fa = fractpart + (double)0.5;
|
|
if (fa >= pow(10, precision_width))
|
|
{
|
|
intpart++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fa = fractpart - (double)0.5;
|
|
if (fa <= -pow(10, precision_width))
|
|
{
|
|
intpart--;
|
|
}
|
|
}
|
|
for (i = 0; i < precision_width; i++)
|
|
{
|
|
fb = fa / (int32_t)radix;
|
|
dc = (fa - (int64_t)fb * (int32_t)radix);
|
|
c = (int32_t)dc;
|
|
if (c < 0)
|
|
{
|
|
uc = (uint32_t)c;
|
|
c = (int32_t)(~uc) + 1 + '0';
|
|
}
|
|
else
|
|
{
|
|
c = c + '0';
|
|
}
|
|
fa = fb;
|
|
*nstrp++ = (char)c;
|
|
++nlen;
|
|
}
|
|
*nstrp++ = (char)'.';
|
|
++nlen;
|
|
a = (int32_t)intpart;
|
|
if (a == 0)
|
|
{
|
|
*nstrp++ = '0';
|
|
++nlen;
|
|
}
|
|
else
|
|
{
|
|
while (a != 0)
|
|
{
|
|
b = (int32_t)a / (int32_t)radix;
|
|
c = (int32_t)a - ((int32_t)b * (int32_t)radix);
|
|
if (c < 0)
|
|
{
|
|
uc = (uint32_t)c;
|
|
c = (int32_t)(~uc) + 1 + '0';
|
|
}
|
|
else
|
|
{
|
|
c = c + '0';
|
|
}
|
|
a = b;
|
|
*nstrp++ = (char)c;
|
|
++nlen;
|
|
}
|
|
}
|
|
return nlen;
|
|
}
|
|
#endif /* PRINTF_FLOAT_ENABLE */
|
|
|
|
int StrFormatPrintf(const char *fmt, va_list ap, char *buf, printfCb cb)
|
|
{
|
|
/* va_list ap; */
|
|
char *p;
|
|
int32_t c;
|
|
|
|
char vstr[33];
|
|
char *vstrp = NULL;
|
|
int32_t vlen = 0;
|
|
|
|
int32_t done;
|
|
int32_t count = 0;
|
|
|
|
uint32_t field_width;
|
|
uint32_t precision_width;
|
|
char *sval;
|
|
int32_t cval;
|
|
bool use_caps;
|
|
uint8_t radix = 0;
|
|
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
uint32_t flags_used;
|
|
int32_t schar, dschar;
|
|
int64_t ival;
|
|
uint64_t uval = 0;
|
|
bool valid_precision_width;
|
|
#else
|
|
int32_t ival;
|
|
uint32_t uval = 0;
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
|
|
#if PRINTF_FLOAT_ENABLE
|
|
double fval;
|
|
#endif /* PRINTF_FLOAT_ENABLE */
|
|
|
|
/* Start parsing apart the format string and display appropriate formats and data. */
|
|
for (p = (char *)fmt; (c = *p) != 0; p++)
|
|
{
|
|
/*
|
|
* All formats begin with a '%' marker. Special chars like
|
|
* '\n' or '\t' are normally converted to the appropriate
|
|
* character by the __compiler__. Thus, no need for this
|
|
* routine to account for the '\' character.
|
|
*/
|
|
if (c != '%')
|
|
{
|
|
cb(buf, &count, c, 1);
|
|
/* By using 'continue', the next iteration of the loop is used, skipping the code that follows. */
|
|
continue;
|
|
}
|
|
|
|
use_caps = true;
|
|
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
/* First check for specification modifier flags. */
|
|
flags_used = 0;
|
|
done = false;
|
|
while (!done)
|
|
{
|
|
switch (*++p)
|
|
{
|
|
case '-':
|
|
flags_used |= kPRINTF_Minus;
|
|
break;
|
|
case '+':
|
|
flags_used |= kPRINTF_Plus;
|
|
break;
|
|
case ' ':
|
|
flags_used |= kPRINTF_Space;
|
|
break;
|
|
case '0':
|
|
flags_used |= kPRINTF_Zero;
|
|
break;
|
|
case '#':
|
|
flags_used |= kPRINTF_Pound;
|
|
break;
|
|
default:
|
|
/* We've gone one char too far. */
|
|
--p;
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
|
|
/* Next check for minimum field width. */
|
|
field_width = 0;
|
|
done = false;
|
|
while (!done)
|
|
{
|
|
c = *++p;
|
|
if ((c >= '0') && (c <= '9'))
|
|
{
|
|
field_width = (field_width * 10) + (c - '0');
|
|
}
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
else if (c == '*')
|
|
{
|
|
field_width = (uint32_t)va_arg(ap, uint32_t);
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
else
|
|
{
|
|
/* We've gone one char too far. */
|
|
--p;
|
|
done = true;
|
|
}
|
|
}
|
|
/* Next check for the width and precision field separator. */
|
|
precision_width = 6;
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
valid_precision_width = false;
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
if (*++p == '.')
|
|
{
|
|
/* Must get precision field width, if present. */
|
|
precision_width = 0;
|
|
done = false;
|
|
while (!done)
|
|
{
|
|
c = *++p;
|
|
if ((c >= '0') && (c <= '9'))
|
|
{
|
|
precision_width = (precision_width * 10) + (c - '0');
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
valid_precision_width = true;
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
}
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
else if (c == '*')
|
|
{
|
|
precision_width = (uint32_t)va_arg(ap, uint32_t);
|
|
valid_precision_width = true;
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
else
|
|
{
|
|
/* We've gone one char too far. */
|
|
--p;
|
|
done = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* We've gone one char too far. */
|
|
--p;
|
|
}
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
/*
|
|
* Check for the length modifier.
|
|
*/
|
|
switch (/* c = */ *++p)
|
|
{
|
|
case 'h':
|
|
if (*++p != 'h')
|
|
{
|
|
flags_used |= kPRINTF_LengthShortInt;
|
|
--p;
|
|
}
|
|
else
|
|
{
|
|
flags_used |= kPRINTF_LengthChar;
|
|
}
|
|
break;
|
|
case 'l':
|
|
if (*++p != 'l')
|
|
{
|
|
flags_used |= kPRINTF_LengthLongInt;
|
|
--p;
|
|
}
|
|
else
|
|
{
|
|
flags_used |= kPRINTF_LengthLongLongInt;
|
|
}
|
|
break;
|
|
default:
|
|
/* we've gone one char too far */
|
|
--p;
|
|
break;
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
/* Now we're ready to examine the format. */
|
|
c = *++p;
|
|
{
|
|
if ((c == 'd') || (c == 'i') || (c == 'f') || (c == 'F') || (c == 'x') || (c == 'X') || (c == 'o') ||
|
|
(c == 'b') || (c == 'p') || (c == 'u'))
|
|
{
|
|
if ((c == 'd') || (c == 'i'))
|
|
{
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (flags_used & kPRINTF_LengthLongLongInt)
|
|
{
|
|
ival = (int64_t)va_arg(ap, int64_t);
|
|
}
|
|
else
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
{
|
|
ival = (int32_t)va_arg(ap, int32_t);
|
|
}
|
|
vlen = ConvertRadixNumToString(vstr, &ival, true, 10, use_caps);
|
|
vstrp = &vstr[vlen];
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (ival < 0)
|
|
{
|
|
schar = '-';
|
|
++vlen;
|
|
}
|
|
else
|
|
{
|
|
if (flags_used & kPRINTF_Plus)
|
|
{
|
|
schar = '+';
|
|
++vlen;
|
|
}
|
|
else
|
|
{
|
|
if (flags_used & kPRINTF_Space)
|
|
{
|
|
schar = ' ';
|
|
++vlen;
|
|
}
|
|
else
|
|
{
|
|
schar = 0;
|
|
}
|
|
}
|
|
}
|
|
dschar = false;
|
|
/* Do the ZERO pad. */
|
|
if (flags_used & kPRINTF_Zero)
|
|
{
|
|
if (schar)
|
|
{
|
|
cb(buf, &count, schar, 1);
|
|
}
|
|
dschar = true;
|
|
|
|
cb(buf, &count, '0', field_width - vlen);
|
|
vlen = field_width;
|
|
}
|
|
else
|
|
{
|
|
if (!(flags_used & kPRINTF_Minus))
|
|
{
|
|
cb(buf, &count, ' ', field_width - vlen);
|
|
if (schar)
|
|
{
|
|
cb(buf, &count, schar, 1);
|
|
}
|
|
dschar = true;
|
|
}
|
|
}
|
|
/* The string was built in reverse order, now display in correct order. */
|
|
if ((!dschar) && schar)
|
|
{
|
|
cb(buf, &count, schar, 1);
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
}
|
|
|
|
#if PRINTF_FLOAT_ENABLE
|
|
if ((c == 'f') || (c == 'F'))
|
|
{
|
|
fval = (double)va_arg(ap, double);
|
|
vlen = ConvertFloatRadixNumToString(vstr, &fval, 10, precision_width);
|
|
vstrp = &vstr[vlen];
|
|
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (fval < 0)
|
|
{
|
|
schar = '-';
|
|
++vlen;
|
|
}
|
|
else
|
|
{
|
|
if (flags_used & kPRINTF_Plus)
|
|
{
|
|
schar = '+';
|
|
++vlen;
|
|
}
|
|
else
|
|
{
|
|
if (flags_used & kPRINTF_Space)
|
|
{
|
|
schar = ' ';
|
|
++vlen;
|
|
}
|
|
else
|
|
{
|
|
schar = 0;
|
|
}
|
|
}
|
|
}
|
|
dschar = false;
|
|
if (flags_used & kPRINTF_Zero)
|
|
{
|
|
if (schar)
|
|
{
|
|
cb(buf, &count, schar, 1);
|
|
}
|
|
dschar = true;
|
|
cb(buf, &count, '0', field_width - vlen);
|
|
vlen = field_width;
|
|
}
|
|
else
|
|
{
|
|
if (!(flags_used & kPRINTF_Minus))
|
|
{
|
|
cb(buf, &count, ' ', field_width - vlen);
|
|
if (schar)
|
|
{
|
|
cb(buf, &count, schar, 1);
|
|
}
|
|
dschar = true;
|
|
}
|
|
}
|
|
if ((!dschar) && schar)
|
|
{
|
|
cb(buf, &count, schar, 1);
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
}
|
|
#endif /* PRINTF_FLOAT_ENABLE */
|
|
if ((c == 'X') || (c == 'x'))
|
|
{
|
|
if (c == 'x')
|
|
{
|
|
use_caps = false;
|
|
}
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (flags_used & kPRINTF_LengthLongLongInt)
|
|
{
|
|
uval = (uint64_t)va_arg(ap, uint64_t);
|
|
}
|
|
else
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
{
|
|
uval = (uint32_t)va_arg(ap, uint32_t);
|
|
}
|
|
vlen = ConvertRadixNumToString(vstr, &uval, false, 16, use_caps);
|
|
vstrp = &vstr[vlen];
|
|
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
dschar = false;
|
|
if (flags_used & kPRINTF_Zero)
|
|
{
|
|
if (flags_used & kPRINTF_Pound)
|
|
{
|
|
cb(buf, &count, '0', 1);
|
|
cb(buf, &count, (use_caps ? 'X' : 'x'), 1);
|
|
dschar = true;
|
|
}
|
|
cb(buf, &count, '0', field_width - vlen);
|
|
vlen = field_width;
|
|
}
|
|
else
|
|
{
|
|
if (!(flags_used & kPRINTF_Minus))
|
|
{
|
|
if (flags_used & kPRINTF_Pound)
|
|
{
|
|
vlen += 2;
|
|
}
|
|
cb(buf, &count, ' ', field_width - vlen);
|
|
if (flags_used & kPRINTF_Pound)
|
|
{
|
|
cb(buf, &count, '0', 1);
|
|
cb(buf, &count, (use_caps ? 'X' : 'x'), 1);
|
|
dschar = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((flags_used & kPRINTF_Pound) && (!dschar))
|
|
{
|
|
cb(buf, &count, '0', 1);
|
|
cb(buf, &count, (use_caps ? 'X' : 'x'), 1);
|
|
vlen += 2;
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
}
|
|
if ((c == 'o') || (c == 'b') || (c == 'p') || (c == 'u'))
|
|
{
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (flags_used & kPRINTF_LengthLongLongInt)
|
|
{
|
|
uval = (uint64_t)va_arg(ap, uint64_t);
|
|
}
|
|
else
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
{
|
|
uval = (uint32_t)va_arg(ap, uint32_t);
|
|
}
|
|
|
|
if (c == 'o')
|
|
{
|
|
radix = 8;
|
|
}
|
|
else if (c == 'b')
|
|
{
|
|
radix = 2;
|
|
}
|
|
else if (c == 'p')
|
|
{
|
|
radix = 16;
|
|
}
|
|
else
|
|
{
|
|
radix = 10;
|
|
}
|
|
|
|
vlen = ConvertRadixNumToString(vstr, &uval, false, radix, use_caps);
|
|
vstrp = &vstr[vlen];
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (flags_used & kPRINTF_Zero)
|
|
{
|
|
cb(buf, &count, '0', field_width - vlen);
|
|
vlen = field_width;
|
|
}
|
|
else
|
|
{
|
|
if (!(flags_used & kPRINTF_Minus))
|
|
{
|
|
cb(buf, &count, ' ', field_width - vlen);
|
|
}
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
}
|
|
#if !PRINTF_ADVANCED_ENABLE
|
|
cb(buf, &count, ' ', field_width - vlen);
|
|
#endif /* !PRINTF_ADVANCED_ENABLE */
|
|
if (vstrp != NULL)
|
|
{
|
|
while (*vstrp)
|
|
{
|
|
cb(buf, &count, *vstrp--, 1);
|
|
}
|
|
}
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (flags_used & kPRINTF_Minus)
|
|
{
|
|
cb(buf, &count, ' ', field_width - vlen);
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
}
|
|
else if (c == 'c')
|
|
{
|
|
cval = (char)va_arg(ap, uint32_t);
|
|
cb(buf, &count, cval, 1);
|
|
}
|
|
else if (c == 's')
|
|
{
|
|
sval = (char *)va_arg(ap, char *);
|
|
if (sval)
|
|
{
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (valid_precision_width)
|
|
{
|
|
vlen = precision_width;
|
|
}
|
|
else
|
|
{
|
|
vlen = strlen(sval);
|
|
}
|
|
#else
|
|
vlen = strlen(sval);
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (!(flags_used & kPRINTF_Minus))
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
{
|
|
cb(buf, &count, ' ', field_width - vlen);
|
|
}
|
|
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (valid_precision_width)
|
|
{
|
|
while ((*sval) && (vlen > 0))
|
|
{
|
|
cb(buf, &count, *sval++, 1);
|
|
vlen--;
|
|
}
|
|
/* In case that vlen sval is shorter than vlen */
|
|
vlen = precision_width - vlen;
|
|
}
|
|
else
|
|
{
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
while (*sval)
|
|
{
|
|
cb(buf, &count, *sval++, 1);
|
|
}
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
|
|
#if PRINTF_ADVANCED_ENABLE
|
|
if (flags_used & kPRINTF_Minus)
|
|
{
|
|
cb(buf, &count, ' ', field_width - vlen);
|
|
}
|
|
#endif /* PRINTF_ADVANCED_ENABLE */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cb(buf, &count, c, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
int StrFormatScanf(const char *line_ptr, char *format, va_list args_ptr)
|
|
{
|
|
uint8_t base;
|
|
int8_t neg;
|
|
/* Identifier for the format string. */
|
|
char *c = format;
|
|
char temp;
|
|
char *buf;
|
|
/* Flag telling the conversion specification. */
|
|
uint32_t flag = 0;
|
|
/* Filed width for the matching input streams. */
|
|
uint32_t field_width;
|
|
/* How many arguments are assigned except the suppress. */
|
|
uint32_t nassigned = 0;
|
|
/* How many characters are read from the input streams. */
|
|
uint32_t n_decode = 0;
|
|
|
|
int32_t val;
|
|
|
|
const char *s;
|
|
/* Identifier for the input string. */
|
|
const char *p = line_ptr;
|
|
|
|
/* Return EOF error before any conversion. */
|
|
if (*p == '\0')
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/* Decode directives. */
|
|
while ((*c) && (*p))
|
|
{
|
|
/* Ignore all white-spaces in the format strings. */
|
|
if (ScanIgnoreWhiteSpace((const char **)&c))
|
|
{
|
|
n_decode += ScanIgnoreWhiteSpace(&p);
|
|
}
|
|
else if ((*c != '%') || ((*c == '%') && (*(c + 1) == '%')))
|
|
{
|
|
/* Ordinary characters. */
|
|
c++;
|
|
if (*p == *c)
|
|
{
|
|
n_decode++;
|
|
p++;
|
|
c++;
|
|
}
|
|
else
|
|
{
|
|
/* Match failure. Misalignment with C99, the unmatched characters need to be pushed back to stream.
|
|
* However, it is deserted now. */
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* convernsion specification */
|
|
c++;
|
|
/* Reset. */
|
|
flag = 0;
|
|
field_width = 0;
|
|
base = 0;
|
|
|
|
/* Loop to get full conversion specification. */
|
|
while ((*c) && (!(flag & kSCANF_DestMask)))
|
|
{
|
|
switch (*c)
|
|
{
|
|
#if SCANF_ADVANCED_ENABLE
|
|
case '*':
|
|
if (flag & kSCANF_Suppress)
|
|
{
|
|
/* Match failure. */
|
|
return nassigned;
|
|
}
|
|
flag |= kSCANF_Suppress;
|
|
c++;
|
|
break;
|
|
case 'h':
|
|
if (flag & kSCANF_LengthMask)
|
|
{
|
|
/* Match failure. */
|
|
return nassigned;
|
|
}
|
|
|
|
if (c[1] == 'h')
|
|
{
|
|
flag |= kSCANF_LengthChar;
|
|
c++;
|
|
}
|
|
else
|
|
{
|
|
flag |= kSCANF_LengthShortInt;
|
|
}
|
|
c++;
|
|
break;
|
|
case 'l':
|
|
if (flag & kSCANF_LengthMask)
|
|
{
|
|
/* Match failure. */
|
|
return nassigned;
|
|
}
|
|
|
|
if (c[1] == 'l')
|
|
{
|
|
flag |= kSCANF_LengthLongLongInt;
|
|
c++;
|
|
}
|
|
else
|
|
{
|
|
flag |= kSCANF_LengthLongInt;
|
|
}
|
|
c++;
|
|
break;
|
|
#endif /* SCANF_ADVANCED_ENABLE */
|
|
#if SCANF_FLOAT_ENABLE
|
|
case 'L':
|
|
if (flag & kSCANF_LengthMask)
|
|
{
|
|
/* Match failure. */
|
|
return nassigned;
|
|
}
|
|
flag |= kSCANF_LengthLongLongDouble;
|
|
c++;
|
|
break;
|
|
#endif /* SCANF_FLOAT_ENABLE */
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
if (field_width)
|
|
{
|
|
/* Match failure. */
|
|
return nassigned;
|
|
}
|
|
do
|
|
{
|
|
field_width = field_width * 10 + *c - '0';
|
|
c++;
|
|
} while ((*c >= '0') && (*c <= '9'));
|
|
break;
|
|
case 'd':
|
|
base = 10;
|
|
flag |= kSCANF_TypeSinged;
|
|
flag |= kSCANF_DestInt;
|
|
c++;
|
|
break;
|
|
case 'u':
|
|
base = 10;
|
|
flag |= kSCANF_DestInt;
|
|
c++;
|
|
break;
|
|
case 'o':
|
|
base = 8;
|
|
flag |= kSCANF_DestInt;
|
|
c++;
|
|
break;
|
|
case 'x':
|
|
case 'X':
|
|
base = 16;
|
|
flag |= kSCANF_DestInt;
|
|
c++;
|
|
break;
|
|
case 'i':
|
|
base = 0;
|
|
flag |= kSCANF_DestInt;
|
|
c++;
|
|
break;
|
|
#if SCANF_FLOAT_ENABLE
|
|
case 'a':
|
|
case 'A':
|
|
case 'e':
|
|
case 'E':
|
|
case 'f':
|
|
case 'F':
|
|
case 'g':
|
|
case 'G':
|
|
flag |= kSCANF_DestFloat;
|
|
c++;
|
|
break;
|
|
#endif /* SCANF_FLOAT_ENABLE */
|
|
case 'c':
|
|
flag |= kSCANF_DestChar;
|
|
if (!field_width)
|
|
{
|
|
field_width = 1;
|
|
}
|
|
c++;
|
|
break;
|
|
case 's':
|
|
flag |= kSCANF_DestString;
|
|
c++;
|
|
break;
|
|
default:
|
|
return nassigned;
|
|
}
|
|
}
|
|
|
|
if (!(flag & kSCANF_DestMask))
|
|
{
|
|
/* Format strings are exhausted. */
|
|
return nassigned;
|
|
}
|
|
|
|
if (!field_width)
|
|
{
|
|
/* Large than length of a line. */
|
|
field_width = 99;
|
|
}
|
|
|
|
/* Matching strings in input streams and assign to argument. */
|
|
switch (flag & kSCANF_DestMask)
|
|
{
|
|
case kSCANF_DestChar:
|
|
s = (const char *)p;
|
|
buf = va_arg(args_ptr, char *);
|
|
while ((field_width--) && (*p))
|
|
{
|
|
if (!(flag & kSCANF_Suppress))
|
|
{
|
|
*buf++ = *p++;
|
|
}
|
|
else
|
|
{
|
|
p++;
|
|
}
|
|
n_decode++;
|
|
}
|
|
|
|
if ((!(flag & kSCANF_Suppress)) && (s != p))
|
|
{
|
|
nassigned++;
|
|
}
|
|
break;
|
|
case kSCANF_DestString:
|
|
n_decode += ScanIgnoreWhiteSpace(&p);
|
|
s = p;
|
|
buf = va_arg(args_ptr, char *);
|
|
while ((field_width--) && (*p != '\0') && (*p != ' ') && (*p != '\t') && (*p != '\n') &&
|
|
(*p != '\r') && (*p != '\v') && (*p != '\f'))
|
|
{
|
|
if (flag & kSCANF_Suppress)
|
|
{
|
|
p++;
|
|
}
|
|
else
|
|
{
|
|
*buf++ = *p++;
|
|
}
|
|
n_decode++;
|
|
}
|
|
|
|
if ((!(flag & kSCANF_Suppress)) && (s != p))
|
|
{
|
|
/* Add NULL to end of string. */
|
|
*buf = '\0';
|
|
nassigned++;
|
|
}
|
|
break;
|
|
case kSCANF_DestInt:
|
|
n_decode += ScanIgnoreWhiteSpace(&p);
|
|
s = p;
|
|
val = 0;
|
|
if ((base == 0) || (base == 16))
|
|
{
|
|
if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X')))
|
|
{
|
|
base = 16;
|
|
if (field_width >= 1)
|
|
{
|
|
p += 2;
|
|
n_decode += 2;
|
|
field_width -= 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (base == 0)
|
|
{
|
|
if (s[0] == '0')
|
|
{
|
|
base = 8;
|
|
}
|
|
else
|
|
{
|
|
base = 10;
|
|
}
|
|
}
|
|
|
|
neg = 1;
|
|
switch (*p)
|
|
{
|
|
case '-':
|
|
neg = -1;
|
|
n_decode++;
|
|
p++;
|
|
field_width--;
|
|
break;
|
|
case '+':
|
|
neg = 1;
|
|
n_decode++;
|
|
p++;
|
|
field_width--;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
while ((*p) && (field_width--))
|
|
{
|
|
if ((*p <= '9') && (*p >= '0'))
|
|
{
|
|
temp = *p - '0';
|
|
}
|
|
else if ((*p <= 'f') && (*p >= 'a'))
|
|
{
|
|
temp = *p - 'a' + 10;
|
|
}
|
|
else if ((*p <= 'F') && (*p >= 'A'))
|
|
{
|
|
temp = *p - 'A' + 10;
|
|
}
|
|
else
|
|
{
|
|
temp = base;
|
|
}
|
|
|
|
if (temp >= base)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
val = base * val + temp;
|
|
}
|
|
p++;
|
|
n_decode++;
|
|
}
|
|
val *= neg;
|
|
if (!(flag & kSCANF_Suppress))
|
|
{
|
|
#if SCANF_ADVANCED_ENABLE
|
|
switch (flag & kSCANF_LengthMask)
|
|
{
|
|
case kSCANF_LengthChar:
|
|
if (flag & kSCANF_TypeSinged)
|
|
{
|
|
*va_arg(args_ptr, signed char *) = (signed char)val;
|
|
}
|
|
else
|
|
{
|
|
*va_arg(args_ptr, unsigned char *) = (unsigned char)val;
|
|
}
|
|
break;
|
|
case kSCANF_LengthShortInt:
|
|
if (flag & kSCANF_TypeSinged)
|
|
{
|
|
*va_arg(args_ptr, signed short *) = (signed short)val;
|
|
}
|
|
else
|
|
{
|
|
*va_arg(args_ptr, unsigned short *) = (unsigned short)val;
|
|
}
|
|
break;
|
|
case kSCANF_LengthLongInt:
|
|
if (flag & kSCANF_TypeSinged)
|
|
{
|
|
*va_arg(args_ptr, signed long int *) = (signed long int)val;
|
|
}
|
|
else
|
|
{
|
|
*va_arg(args_ptr, unsigned long int *) = (unsigned long int)val;
|
|
}
|
|
break;
|
|
case kSCANF_LengthLongLongInt:
|
|
if (flag & kSCANF_TypeSinged)
|
|
{
|
|
*va_arg(args_ptr, signed long long int *) = (signed long long int)val;
|
|
}
|
|
else
|
|
{
|
|
*va_arg(args_ptr, unsigned long long int *) = (unsigned long long int)val;
|
|
}
|
|
break;
|
|
default:
|
|
/* The default type is the type int. */
|
|
if (flag & kSCANF_TypeSinged)
|
|
{
|
|
*va_arg(args_ptr, signed int *) = (signed int)val;
|
|
}
|
|
else
|
|
{
|
|
*va_arg(args_ptr, unsigned int *) = (unsigned int)val;
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
/* The default type is the type int. */
|
|
if (flag & kSCANF_TypeSinged)
|
|
{
|
|
*va_arg(args_ptr, signed int *) = (signed int)val;
|
|
}
|
|
else
|
|
{
|
|
*va_arg(args_ptr, unsigned int *) = (unsigned int)val;
|
|
}
|
|
#endif /* SCANF_ADVANCED_ENABLE */
|
|
nassigned++;
|
|
}
|
|
break;
|
|
#if SCANF_FLOAT_ENABLE
|
|
case kSCANF_DestFloat:
|
|
n_decode += ScanIgnoreWhiteSpace(&p);
|
|
fnum = strtod(p, (char **)&s);
|
|
|
|
if ((fnum >= HUGE_VAL) || (fnum <= -HUGE_VAL))
|
|
{
|
|
break;
|
|
}
|
|
|
|
n_decode += (int)(s) - (int)(p);
|
|
p = s;
|
|
if (!(flag & kSCANF_Suppress))
|
|
{
|
|
if (flag & kSCANF_LengthLongLongDouble)
|
|
{
|
|
*va_arg(args_ptr, double *) = fnum;
|
|
}
|
|
else
|
|
{
|
|
*va_arg(args_ptr, float *) = (float)fnum;
|
|
}
|
|
nassigned++;
|
|
}
|
|
break;
|
|
#endif /* SCANF_FLOAT_ENABLE */
|
|
default:
|
|
return nassigned;
|
|
}
|
|
}
|
|
}
|
|
return nassigned;
|
|
}
|