| /* |
| * Copyright 2017, 2020 NXP |
| * All rights reserved. |
| * |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * |
| */ |
| #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 */ |
| |
| #ifndef MAX_FIELD_WIDTH |
| #define MAX_FIELD_WIDTH 99U |
| #endif |
| |
| #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 SCANF_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); |
| |
| /*! |
| * |
| */ |
| double modf(double input_dbl, double *intpart_ptr); |
| #endif /* PRINTF_FLOAT_ENABLE */ |
| |
| /*************Code for process formatted data*******************************/ |
| #if PRINTF_ADVANCED_ENABLE |
| static uint8_t PrintGetSignChar(int32_t ival, uint32_t flags_used, char *schar) |
| { |
| uint8_t len = 1U; |
| if (ival < 0) |
| { |
| *schar = '-'; |
| } |
| else |
| { |
| if (0U != (flags_used & (uint32_t)kPRINTF_Plus)) |
| { |
| *schar = '+'; |
| } |
| else if (0U != (flags_used & (uint32_t)kPRINTF_Space)) |
| { |
| *schar = ' '; |
| } |
| else |
| { |
| *schar = 0; |
| len = 0U; |
| } |
| } |
| return len; |
| } |
| #endif |
| |
| static uint32_t PrintGetWidth(const char **p, va_list *ap) |
| { |
| uint32_t field_width = 0; |
| uint8_t done = 0U; |
| char c; |
| |
| while (0U == done) |
| { |
| c = *(++(*p)); |
| if ((c >= '0') && (c <= '9')) |
| { |
| (field_width) = ((field_width)*10U) + ((uint32_t)c - (uint32_t)'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 = 1U; |
| } |
| } |
| return field_width; |
| } |
| |
| static uint32_t PrintGetPrecision(const char **s, va_list *ap, bool *valid_precision_width) |
| { |
| const char *p = *s; |
| uint32_t precision_width = 6U; |
| uint8_t done = 0U; |
| |
| #if PRINTF_ADVANCED_ENABLE |
| if (NULL != valid_precision_width) |
| { |
| *valid_precision_width = false; |
| } |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| if (*++p == '.') |
| { |
| /* Must get precision field width, if present. */ |
| precision_width = 0U; |
| done = 0U; |
| while (0U == done) |
| { |
| char c = *++p; |
| if ((c >= '0') && (c <= '9')) |
| { |
| precision_width = (precision_width * 10U) + ((uint32_t)c - (uint32_t)'0'); |
| #if PRINTF_ADVANCED_ENABLE |
| if (NULL != valid_precision_width) |
| { |
| *valid_precision_width = true; |
| } |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| } |
| #if PRINTF_ADVANCED_ENABLE |
| else if (c == '*') |
| { |
| precision_width = (uint32_t)va_arg(*ap, uint32_t); |
| if (NULL != valid_precision_width) |
| { |
| *valid_precision_width = true; |
| } |
| } |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| else |
| { |
| /* We've gone one char too far. */ |
| --p; |
| done = 1U; |
| } |
| } |
| } |
| else |
| { |
| /* We've gone one char too far. */ |
| --p; |
| } |
| *s = p; |
| return precision_width; |
| } |
| |
| static uint32_t PrintIsobpu(const char c) |
| { |
| uint32_t ret = 0U; |
| if ((c == 'o') || (c == 'b') || (c == 'p') || (c == 'u')) |
| { |
| ret = 1U; |
| } |
| return ret; |
| } |
| |
| static uint32_t PrintIsdi(const char c) |
| { |
| uint32_t ret = 0U; |
| if ((c == 'd') || (c == 'i')) |
| { |
| ret = 1U; |
| } |
| return ret; |
| } |
| |
| static void PrintOutputdifFobpu(uint32_t flags_used, |
| uint32_t field_width, |
| uint32_t vlen, |
| char schar, |
| char *vstrp, |
| printfCb cb, |
| char *buf, |
| int32_t *count) |
| { |
| #if PRINTF_ADVANCED_ENABLE |
| /* Do the ZERO pad. */ |
| if (0U != (flags_used & (uint32_t)kPRINTF_Zero)) |
| { |
| if ('\0' != schar) |
| { |
| cb(buf, count, schar, 1); |
| schar = '\0'; |
| } |
| cb(buf, count, '0', (int)field_width - (int)vlen); |
| vlen = field_width; |
| } |
| else |
| { |
| if (0U == (flags_used & (uint32_t)kPRINTF_Minus)) |
| { |
| cb(buf, count, ' ', (int)field_width - (int)vlen); |
| if ('\0' != schar) |
| { |
| cb(buf, count, schar, 1); |
| schar = '\0'; |
| } |
| } |
| } |
| /* The string was built in reverse order, now display in correct order. */ |
| if ('\0' != schar) |
| { |
| cb(buf, count, schar, 1); |
| } |
| #else |
| cb(buf, count, ' ', (int)field_width - (int)vlen); |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| while ('\0' != (*vstrp)) |
| { |
| cb(buf, count, *vstrp--, 1); |
| } |
| #if PRINTF_ADVANCED_ENABLE |
| if (0U != (flags_used & (uint32_t)kPRINTF_Minus)) |
| { |
| cb(buf, count, ' ', (int)field_width - (int)vlen); |
| } |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| } |
| |
| static void PrintOutputxX(uint32_t flags_used, |
| uint32_t field_width, |
| uint32_t vlen, |
| bool use_caps, |
| char *vstrp, |
| printfCb cb, |
| char *buf, |
| int32_t *count) |
| { |
| #if PRINTF_ADVANCED_ENABLE |
| uint8_t dschar = 0; |
| if (0U != (flags_used & (uint32_t)kPRINTF_Zero)) |
| { |
| if (0U != (flags_used & (uint32_t)kPRINTF_Pound)) |
| { |
| cb(buf, count, '0', 1); |
| cb(buf, count, (use_caps ? 'X' : 'x'), 1); |
| dschar = 1U; |
| } |
| cb(buf, count, '0', (int)field_width - (int)vlen); |
| vlen = field_width; |
| } |
| else |
| { |
| if (0U == (flags_used & (uint32_t)kPRINTF_Minus)) |
| { |
| if (0U != (flags_used & (uint32_t)kPRINTF_Pound)) |
| { |
| vlen += 2U; |
| } |
| cb(buf, count, ' ', (int)field_width - (int)vlen); |
| if (0U != (flags_used & (uint32_t)kPRINTF_Pound)) |
| { |
| cb(buf, count, '0', 1); |
| cb(buf, count, (use_caps ? 'X' : 'x'), 1); |
| dschar = 1U; |
| } |
| } |
| } |
| |
| if ((0U != (flags_used & (uint32_t)kPRINTF_Pound)) && (0U == dschar)) |
| { |
| cb(buf, count, '0', 1); |
| cb(buf, count, (use_caps ? 'X' : 'x'), 1); |
| vlen += 2U; |
| } |
| #else |
| cb(buf, count, ' ', (int)field_width - (int)vlen); |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| while ('\0' != (*vstrp)) |
| { |
| cb(buf, count, *vstrp--, 1); |
| } |
| #if PRINTF_ADVANCED_ENABLE |
| if (0U != (flags_used & (uint32_t)kPRINTF_Minus)) |
| { |
| cb(buf, count, ' ', (int)field_width - (int)vlen); |
| } |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| } |
| |
| static uint32_t PrintIsfF(const char c) |
| { |
| uint32_t ret = 0U; |
| if ((c == 'f') || (c == 'F')) |
| { |
| ret = 1U; |
| } |
| return ret; |
| } |
| |
| static uint32_t PrintIsxX(const char c) |
| { |
| uint32_t ret = 0U; |
| if ((c == 'x') || (c == 'X')) |
| { |
| ret = 1U; |
| } |
| return ret; |
| } |
| |
| #if PRINTF_ADVANCED_ENABLE |
| static uint32_t PrintCheckFlags(const char **s) |
| { |
| const char *p = *s; |
| /* First check for specification modifier flags. */ |
| uint32_t flags_used = 0U; |
| bool done = false; |
| while (false == done) |
| { |
| switch (*++p) |
| { |
| case '-': |
| flags_used |= (uint32_t)kPRINTF_Minus; |
| break; |
| case '+': |
| flags_used |= (uint32_t)kPRINTF_Plus; |
| break; |
| case ' ': |
| flags_used |= (uint32_t)kPRINTF_Space; |
| break; |
| case '0': |
| flags_used |= (uint32_t)kPRINTF_Zero; |
| break; |
| case '#': |
| flags_used |= (uint32_t)kPRINTF_Pound; |
| break; |
| default: |
| /* We've gone one char too far. */ |
| --p; |
| done = true; |
| break; |
| } |
| } |
| *s = p; |
| return flags_used; |
| } |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| |
| #if PRINTF_ADVANCED_ENABLE |
| /* |
| * Check for the length modifier. |
| */ |
| static uint32_t PrintGetLengthFlag(const char **s) |
| { |
| const char *p = *s; |
| /* First check for specification modifier flags. */ |
| uint32_t flags_used = 0U; |
| |
| switch (/* c = */ *++p) |
| { |
| case 'h': |
| if (*++p != 'h') |
| { |
| flags_used |= (uint32_t)kPRINTF_LengthShortInt; |
| --p; |
| } |
| else |
| { |
| flags_used |= (uint32_t)kPRINTF_LengthChar; |
| } |
| break; |
| case 'l': |
| if (*++p != 'l') |
| { |
| flags_used |= (uint32_t)kPRINTF_LengthLongInt; |
| --p; |
| } |
| else |
| { |
| flags_used |= (uint32_t)kPRINTF_LengthLongLongInt; |
| } |
| break; |
| default: |
| /* we've gone one char too far */ |
| --p; |
| break; |
| } |
| *s = p; |
| return flags_used; |
| } |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| |
| static uint8_t PrintGetRadixFromobpu(const char c) |
| { |
| uint8_t radix; |
| |
| if (c == 'o') |
| { |
| radix = 8U; |
| } |
| else if (c == 'b') |
| { |
| radix = 2U; |
| } |
| else if (c == 'p') |
| { |
| radix = 16U; |
| } |
| else |
| { |
| radix = 10U; |
| } |
| return radix; |
| } |
| |
| static uint32_t ScanIsWhiteSpace(const char c) |
| { |
| uint32_t ret = 0U; |
| if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\v') || (c == '\f')) |
| { |
| ret = 1U; |
| } |
| return ret; |
| } |
| |
| static uint32_t ScanIgnoreWhiteSpace(const char **s) |
| { |
| uint32_t count = 0U; |
| char c; |
| |
| c = **s; |
| while (1U == ScanIsWhiteSpace(c)) |
| { |
| 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; |
| uint64_t uc_param; |
| #else |
| int32_t a; |
| int32_t b; |
| int32_t c; |
| |
| uint32_t ua; |
| uint32_t ub; |
| uint32_t uc; |
| uint32_t uc_param; |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| |
| int32_t nlen; |
| char *nstrp; |
| |
| nlen = 0; |
| nstrp = numstr; |
| *nstrp++ = '\0'; |
| |
| if (0 != 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; |
| uc_param = ~uc; |
| c = (int64_t)uc_param + 1 + (int64_t)'0'; |
| } |
| #else |
| b = a / radix; |
| c = a - (b * radix); |
| if (c < 0) |
| { |
| uc = (uint32_t)c; |
| uc_param = ~uc; |
| c = (int32_t)uc_param + 1 + (int32_t)'0'; |
| } |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| else |
| { |
| c = c + (int32_t)'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 == 0U) |
| { |
| *nstrp = '0'; |
| ++nlen; |
| return nlen; |
| } |
| while (ua != 0U) |
| { |
| #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 < 10U) |
| { |
| uc = uc + (uint32_t)'0'; |
| } |
| else |
| { |
| uc = uc - 10U + (uint32_t)(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 */ |
| |
| /*! |
| * brief This function outputs its parameters according to a formatted string. |
| * |
| * note I/O is performed by calling given function pointer using following |
| * (*func_ptr)(c); |
| * |
| * param[in] fmt_ptr Format string for printf. |
| * param[in] args_ptr Arguments to printf. |
| * param[in] buf pointer to the buffer |
| * param cb print callback function pointer |
| * |
| * return Number of characters to be print |
| */ |
| int StrFormatPrintf(const char *fmt, va_list ap, char *buf, printfCb cb) |
| { |
| /* va_list ap; */ |
| const char *p; |
| char c; |
| |
| char vstr[33]; |
| char *vstrp = NULL; |
| int32_t vlen = 0; |
| |
| 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; |
| char schar; |
| 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. */ |
| p = fmt; |
| while (true) |
| { |
| if ('\0' == *p) |
| { |
| break; |
| } |
| c = *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); |
| p++; |
| /* 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 = PrintCheckFlags(&p); |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| |
| /* Next check for minimum field width. */ |
| field_width = PrintGetWidth(&p, &ap); |
| |
| /* Next check for the width and precision field separator. */ |
| #if PRINTF_ADVANCED_ENABLE |
| precision_width = PrintGetPrecision(&p, &ap, &valid_precision_width); |
| #else |
| precision_width = PrintGetPrecision(&p, &ap, NULL); |
| (void)precision_width; |
| #endif |
| |
| #if PRINTF_ADVANCED_ENABLE |
| /* Check for the length modifier. */ |
| flags_used |= PrintGetLengthFlag(&p); |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| |
| /* Now we're ready to examine the format. */ |
| c = *++p; |
| { |
| if (1U == PrintIsdi(c)) |
| { |
| #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, (void *)&ival, 1, 10, use_caps); |
| vstrp = &vstr[vlen]; |
| #if PRINTF_ADVANCED_ENABLE |
| vlen += PrintGetSignChar(ival, flags_used, &schar); |
| PrintOutputdifFobpu(flags_used, field_width, vlen, schar, vstrp, cb, buf, &count); |
| #else |
| PrintOutputdifFobpu(0U, field_width, (uint32_t)vlen, '\0', vstrp, cb, buf, &count); |
| #endif |
| } |
| else if (1U == PrintIsfF(c)) |
| { |
| #if PRINTF_FLOAT_ENABLE |
| fval = (double)va_arg(ap, double); |
| vlen = ConvertFloatRadixNumToString(vstr, &fval, 10, precision_width); |
| vstrp = &vstr[vlen]; |
| |
| #if PRINTF_ADVANCED_ENABLE |
| vlen += PrintGetSignChar((int32_t)fval, flags_used, &schar); |
| PrintOutputdifFobpu(flags_used, field_width, vlen, schar, vstrp, cb, buf, &count); |
| #else |
| PrintOutputdifFobpu(0, field_width, vlen, '\0', vstrp, cb, buf, &count); |
| #endif |
| |
| #else |
| (void)va_arg(ap, double); |
| #endif /* PRINTF_FLOAT_ENABLE */ |
| } |
| else if (1U == PrintIsxX(c)) |
| { |
| 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, 0, 16, use_caps); |
| vstrp = &vstr[vlen]; |
| #if PRINTF_ADVANCED_ENABLE |
| PrintOutputxX(flags_used, field_width, vlen, use_caps, vstrp, cb, buf, &count); |
| #else |
| PrintOutputxX(0U, field_width, (uint32_t)vlen, use_caps, vstrp, cb, buf, &count); |
| #endif |
| } |
| else if (1U == PrintIsobpu(c)) |
| { |
| #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); |
| } |
| |
| radix = PrintGetRadixFromobpu(c); |
| |
| vlen = ConvertRadixNumToString(vstr, &uval, 0, (int32_t)radix, use_caps); |
| vstrp = &vstr[vlen]; |
| #if PRINTF_ADVANCED_ENABLE |
| PrintOutputdifFobpu(flags_used, field_width, vlen, '\0', vstrp, cb, buf, &count); |
| #else |
| PrintOutputdifFobpu(0U, field_width, (uint32_t)vlen, '\0', vstrp, cb, buf, &count); |
| #endif |
| } |
| else if (c == 'c') |
| { |
| cval = (int32_t)va_arg(ap, uint32_t); |
| cb(buf, &count, cval, 1); |
| } |
| else if (c == 's') |
| { |
| sval = (char *)va_arg(ap, char *); |
| if (NULL != sval) |
| { |
| #if PRINTF_ADVANCED_ENABLE |
| if (valid_precision_width) |
| { |
| vlen = precision_width; |
| } |
| else |
| { |
| vlen = strlen(sval); |
| } |
| #else |
| vlen = (int32_t)strlen(sval); |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| #if PRINTF_ADVANCED_ENABLE |
| if (!(flags_used & kPRINTF_Minus)) |
| #endif /* PRINTF_ADVANCED_ENABLE */ |
| { |
| cb(buf, &count, ' ', (int)field_width - (int)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 ('\0' != (*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); |
| } |
| } |
| p++; |
| } |
| |
| return count; |
| } |
| |
| #if SCANF_FLOAT_ENABLE |
| static uint8_t StrFormatScanIsFloat(char *c) |
| { |
| uint8_t ret = 0U; |
| if (('a' == (*c)) || ('A' == (*c)) || ('e' == (*c)) || ('E' == (*c)) || ('f' == (*c)) || ('F' == (*c)) || |
| ('g' == (*c)) || ('G' == (*c))) |
| { |
| ret = 1U; |
| } |
| return ret; |
| } |
| #endif |
| |
| static uint8_t StrFormatScanIsFormatStarting(char *c) |
| { |
| uint8_t ret = 1U; |
| if ((*c != '%')) |
| { |
| ret = 0U; |
| } |
| else if (*(c + 1) == '%') |
| { |
| ret = 0U; |
| } |
| else |
| { |
| /*MISRA rule 15.7*/ |
| } |
| |
| return ret; |
| } |
| |
| static uint8_t StrFormatScanGetBase(uint8_t base, const char *s) |
| { |
| if (base == 0U) |
| { |
| if (s[0] == '0') |
| { |
| if ((s[1] == 'x') || (s[1] == 'X')) |
| { |
| base = 16; |
| } |
| else |
| { |
| base = 8; |
| } |
| } |
| else |
| { |
| base = 10; |
| } |
| } |
| return base; |
| } |
| |
| static uint8_t StrFormatScanCheckSymbol(const char *p, int8_t *neg) |
| { |
| uint8_t len; |
| switch (*p) |
| { |
| case '-': |
| *neg = -1; |
| len = 1; |
| break; |
| case '+': |
| *neg = 1; |
| len = 1; |
| break; |
| default: |
| *neg = 1; |
| len = 0; |
| break; |
| } |
| return len; |
| } |
| |
| static uint8_t StrFormatScanFillInteger(uint32_t flag, va_list *args_ptr, int32_t val) |
| { |
| #if SCANF_ADVANCED_ENABLE |
| if ((flag & kSCANF_Suppress)) |
| { |
| return 0u; |
| } |
| |
| switch (flag & kSCANF_LengthMask) |
| { |
| case kSCANF_LengthChar: |
| if (0 != (flag & (uint32_t)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 (0 != (flag & (uint32_t)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 (0 != (flag & (uint32_t)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 (0 != (flag & (uint32_t)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 (0 != (flag & (uint32_t)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 (0U != (flag & (uint32_t)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 */ |
| |
| return 1u; |
| } |
| |
| #if SCANF_FLOAT_ENABLE |
| static uint8_t StrFormatScanFillFloat(uint32_t flag, va_list *args_ptr, double fnum) |
| { |
| #if SCANF_ADVANCED_ENABLE |
| if (0U != (flag & (uint32_t)kSCANF_Suppress)) |
| { |
| return 0u; |
| } |
| else |
| #endif /* SCANF_ADVANCED_ENABLE */ |
| { |
| if (0U != (flag & (uint32_t)kSCANF_LengthLongLongDouble)) |
| { |
| *va_arg(*args_ptr, double *) = fnum; |
| } |
| else |
| { |
| *va_arg(*args_ptr, float *) = (float)fnum; |
| } |
| return 1u; |
| } |
| } |
| #endif /* SCANF_FLOAT_ENABLE */ |
| |
| static uint8_t StrFormatScanfStringHandling(char **str, uint32_t *flag, uint32_t *field_width, uint8_t *base) |
| { |
| uint8_t exitPending = 0U; |
| char *c = *str; |
| |
| /* Loop to get full conversion specification. */ |
| while (('\0' != (*c)) && (0U == (*flag & (uint32_t)kSCANF_DestMask))) |
| { |
| #if SCANF_ADVANCED_ENABLE |
| if ('*' == (*c)) |
| { |
| if (0U != ((*flag) & (uint32_t)kSCANF_Suppress)) |
| { |
| /* Match failure. */ |
| exitPending = 1U; |
| } |
| else |
| { |
| (*flag) |= (uint32_t)kSCANF_Suppress; |
| } |
| } |
| else if ('h' == (*c)) |
| { |
| if (0U != ((*flag) & (uint32_t)kSCANF_LengthMask)) |
| { |
| /* Match failure. */ |
| exitPending = 1U; |
| } |
| else |
| { |
| if (c[1] == 'h') |
| { |
| (*flag) |= (uint32_t)kSCANF_LengthChar; |
| c++; |
| } |
| else |
| { |
| (*flag) |= (uint32_t)kSCANF_LengthShortInt; |
| } |
| } |
| } |
| else if ('l' == (*c)) |
| { |
| if (0U != ((*flag) & (uint32_t)kSCANF_LengthMask)) |
| { |
| /* Match failure. */ |
| exitPending = 1U; |
| } |
| else |
| { |
| if (c[1] == 'l') |
| { |
| (*flag) |= (uint32_t)kSCANF_LengthLongLongInt; |
| c++; |
| } |
| else |
| { |
| (*flag) |= (uint32_t)kSCANF_LengthLongInt; |
| } |
| } |
| } |
| else |
| #endif /* SCANF_ADVANCED_ENABLE */ |
| #if SCANF_FLOAT_ENABLE |
| if ('L' == (*c)) |
| { |
| if (0U != ((*flag) & (uint32_t)kSCANF_LengthMask)) |
| { |
| /* Match failure. */ |
| exitPending = 1U; |
| } |
| else |
| { |
| (*flag) |= (uint32_t)kSCANF_LengthLongLongDouble; |
| } |
| } |
| else |
| #endif /* SCANF_FLOAT_ENABLE */ |
| if (((*c) >= '0') && ((*c) <= '9')) |
| { |
| { |
| char *p; |
| (*field_width) = strtoul(c, &p, 10); |
| c = p - 1; |
| } |
| } |
| else if ('d' == (*c)) |
| { |
| (*base) = 10U; |
| (*flag) |= (uint32_t)kSCANF_TypeSinged; |
| (*flag) |= (uint32_t)kSCANF_DestInt; |
| } |
| else if ('u' == (*c)) |
| { |
| (*base) = 10U; |
| (*flag) |= (uint32_t)kSCANF_DestInt; |
| } |
| else if ('o' == (*c)) |
| { |
| (*base) = 8U; |
| (*flag) |= (uint32_t)kSCANF_DestInt; |
| } |
| else if (('x' == (*c))) |
| { |
| (*base) = 16U; |
| (*flag) |= (uint32_t)kSCANF_DestInt; |
| } |
| else if ('X' == (*c)) |
| { |
| (*base) = 16U; |
| (*flag) |= (uint32_t)kSCANF_DestInt; |
| } |
| else if ('i' == (*c)) |
| { |
| (*base) = 0U; |
| (*flag) |= (uint32_t)kSCANF_DestInt; |
| } |
| #if SCANF_FLOAT_ENABLE |
| else if (1 == StrFormatScanIsFloat(c)) |
| { |
| (*flag) |= (uint32_t)kSCANF_DestFloat; |
| } |
| #endif /* SCANF_FLOAT_ENABLE */ |
| else if ('c' == (*c)) |
| { |
| (*flag) |= (uint32_t)kSCANF_DestChar; |
| if (MAX_FIELD_WIDTH == (*field_width)) |
| { |
| (*field_width) = 1; |
| } |
| } |
| else if ('s' == (*c)) |
| { |
| (*flag) |= (uint32_t)kSCANF_DestString; |
| } |
| else |
| { |
| exitPending = 1U; |
| } |
| |
| if (1U == exitPending) |
| { |
| break; |
| } |
| else |
| { |
| c++; |
| } |
| } |
| *str = c; |
| return exitPending; |
| } |
| |
| /*! |
| * brief Converts an input line of ASCII characters based upon a provided |
| * string format. |
| * |
| * param[in] line_ptr The input line of ASCII data. |
| * param[in] format Format first points to the format string. |
| * param[in] args_ptr The list of parameters. |
| * |
| * return Number of input items converted and assigned. |
| * retval IO_EOF When line_ptr is empty string "". |
| */ |
| 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 *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; |
| |
| uint8_t added; |
| |
| uint8_t exitPending = 0; |
| |
| const char *s; |
| /* Identifier for the input string. */ |
| const char *p = line_ptr; |
| |
| #if SCANF_FLOAT_ENABLE |
| double fnum = 0.0; |
| #endif /* SCANF_FLOAT_ENABLE */ |
| /* Return EOF error before any conversion. */ |
| if (*p == '\0') |
| { |
| return -1; |
| } |
| |
| /* Decode directives. */ |
| while (('\0' != (*c)) && ('\0' != (*p))) |
| { |
| /* Ignore all white-spaces in the format strings. */ |
| if (0U != ScanIgnoreWhiteSpace((const char **)((void *)&c))) |
| { |
| n_decode += ScanIgnoreWhiteSpace(&p); |
| } |
| else if (0U == StrFormatScanIsFormatStarting(c)) |
| { |
| /* 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 = MAX_FIELD_WIDTH; |
| base = 0; |
| added = 0U; |
| |
| exitPending = StrFormatScanfStringHandling(&c, &flag, &field_width, &base); |
| |
| if (1U == exitPending) |
| { |
| /* Format strings are exhausted. */ |
| break; |
| } |
| |
| /* Matching strings in input streams and assign to argument. */ |
| if ((flag & (uint32_t)kSCANF_DestMask) == (uint32_t)kSCANF_DestChar) |
| { |
| s = (const char *)p; |
| buf = va_arg(args_ptr, char *); |
| while ((0U != (field_width--)) |
| #if SCANF_ADVANCED_ENABLE |
| && ('\0' != (*p)) |
| #endif |
| ) |
| { |
| #if SCANF_ADVANCED_ENABLE |
| if (flag & kSCANF_Suppress) |
| { |
| p++; |
| } |
| else |
| #endif |
| { |
| *buf++ = *p++; |
| #if SCANF_ADVANCED_ENABLE |
| added = 1u; |
| #endif |
| } |
| n_decode++; |
| } |
| |
| #if SCANF_ADVANCED_ENABLE |
| if (1u == added) |
| #endif |
| { |
| nassigned++; |
| } |
| } |
| else if ((flag & (uint32_t)kSCANF_DestMask) == (uint32_t)kSCANF_DestString) |
| { |
| n_decode += ScanIgnoreWhiteSpace(&p); |
| s = p; |
| buf = va_arg(args_ptr, char *); |
| while ((0U != (field_width--)) && (*p != '\0') && (0U == ScanIsWhiteSpace(*p))) |
| { |
| #if SCANF_ADVANCED_ENABLE |
| if (flag & kSCANF_Suppress) |
| { |
| p++; |
| } |
| else |
| #endif |
| { |
| *buf++ = *p++; |
| #if SCANF_ADVANCED_ENABLE |
| added = 1u; |
| #endif |
| } |
| n_decode++; |
| } |
| |
| #if SCANF_ADVANCED_ENABLE |
| if (1u == added) |
| #endif |
| { |
| /* Add NULL to end of string. */ |
| *buf = '\0'; |
| nassigned++; |
| } |
| } |
| else if ((flag & (uint32_t)kSCANF_DestMask) == (uint32_t)kSCANF_DestInt) |
| { |
| n_decode += ScanIgnoreWhiteSpace(&p); |
| s = p; |
| val = 0; |
| base = StrFormatScanGetBase(base, s); |
| |
| added = StrFormatScanCheckSymbol(p, &neg); |
| n_decode += added; |
| p += added; |
| field_width -= added; |
| |
| s = p; |
| if (strlen(p) > field_width) |
| { |
| char temp[12]; |
| char *tempEnd; |
| (void)memcpy(temp, p, sizeof(temp) - 1U); |
| temp[sizeof(temp) - 1U] = '\0'; |
| val = (int32_t)strtoul(temp, &tempEnd, (int)base); |
| p = p + (tempEnd - temp); |
| } |
| else |
| { |
| char *tempEnd; |
| val = (int32_t)strtoul(p, &tempEnd, (int)base); |
| p = tempEnd; |
| } |
| n_decode += (uint32_t)p - (uint32_t)s; |
| |
| val *= neg; |
| |
| nassigned += StrFormatScanFillInteger(flag, &args_ptr, val); |
| } |
| #if SCANF_FLOAT_ENABLE |
| else if ((flag & kSCANF_DestMask) == kSCANF_DestFloat) |
| { |
| n_decode += ScanIgnoreWhiteSpace(&p); |
| fnum = strtod(p, (char **)&s); |
| |
| if ((fnum < HUGE_VAL) && (fnum > -HUGE_VAL)) |
| { |
| n_decode += (int)(s) - (int)(p); |
| p = s; |
| nassigned += StrFormatScanFillFloat(flag, &args_ptr, fnum); |
| } |
| } |
| #endif /* SCANF_FLOAT_ENABLE */ |
| else |
| { |
| break; |
| } |
| } |
| } |
| return (int)nassigned; |
| } |