| /* |
| * Copyright (c) 2020 Bouffalolab. |
| * |
| * This file is part of |
| * *** Bouffalolab Software Dev Kit *** |
| * (see www.bouffalolab.com). |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. 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. |
| * 3. Neither the name of Bouffalo Lab nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS 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, EXEMPLARY, 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 <async_log.h> |
| #include <limits.h> |
| #include <stdarg.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| //#define CHAR_BIT 8 |
| // FIXME no ugly declare |
| extern int bl_uart_data_send(uint8_t id, uint8_t data); |
| |
| enum flag |
| { |
| FL_ZERO = 0x01, /* Zero modifier */ |
| FL_MINUS = 0x02, /* Minus modifier */ |
| FL_PLUS = 0x04, /* Plus modifier */ |
| FL_TICK = 0x08, /* ' modifier */ |
| FL_SPACE = 0x10, /* Space modifier */ |
| FL_HASH = 0x20, /* # modifier */ |
| FL_SIGNED = 0x40, /* Number is signed */ |
| FL_UPPER = 0x80 /* Upper case digits */ |
| }; |
| |
| /* These may have to be adjusted on certain implementations */ |
| enum ranks |
| { |
| rank_char = -2, |
| rank_short = -1, |
| rank_int = 0, |
| rank_long = 1, |
| rank_longlong = 2 |
| }; |
| |
| #define MIN_RANK rank_char |
| #define MAX_RANK rank_longlong |
| |
| #define INTMAX_RANK rank_longlong |
| #define SIZE_T_RANK rank_long |
| #define PTRDIFF_T_RANK rank_long |
| |
| #define EMIT(x) \ |
| { \ |
| if (o < n) \ |
| { \ |
| *q++ = (x); \ |
| } \ |
| o++; \ |
| } |
| |
| static size_t format_int(char * q, size_t n, uintmax_t val, unsigned int flags, int base, int width, int prec) |
| { |
| char * qq; |
| size_t o = 0, oo; |
| static const char lcdigits[] = "0123456789abcdef"; |
| static const char ucdigits[] = "0123456789ABCDEF"; |
| const char * digits; |
| uintmax_t tmpval; |
| int minus = 0; |
| int ndigits = 0, nchars; |
| int tickskip, b4tick; |
| |
| /* Select type of digits */ |
| digits = (flags & FL_UPPER) ? ucdigits : lcdigits; |
| |
| /* If signed, separate out the minus */ |
| if (flags & FL_SIGNED && (intmax_t) val < 0) |
| { |
| minus = 1; |
| val = (uintmax_t)(-(intmax_t) val); |
| } |
| |
| /* Count the number of digits needed. This returns zero for 0. */ |
| tmpval = val; |
| while (tmpval) |
| { |
| tmpval /= base; |
| ndigits++; |
| } |
| |
| /* Adjust ndigits for size of output */ |
| |
| if (flags & FL_HASH && base == 8) |
| { |
| if (prec < ndigits + 1) |
| prec = ndigits + 1; |
| } |
| |
| if (ndigits < prec) |
| { |
| ndigits = prec; /* Mandatory number padding */ |
| } |
| else if (val == 0) |
| { |
| ndigits = 1; /* Zero still requires space */ |
| } |
| |
| /* For ', figure out what the skip should be */ |
| if (flags & FL_TICK) |
| { |
| tickskip = (base == 16) ? 4 : 3; |
| } |
| else |
| { |
| tickskip = ndigits; /* No tick marks */ |
| } |
| |
| /* Tick marks aren't digits, but generated by the number converter */ |
| ndigits += (ndigits - 1) / tickskip; |
| |
| /* Now compute the number of nondigits */ |
| nchars = ndigits; |
| |
| if (minus || (flags & (FL_PLUS | FL_SPACE))) |
| nchars++; /* Need space for sign */ |
| if ((flags & FL_HASH) && base == 16) |
| { |
| nchars += 2; /* Add 0x for hex */ |
| } |
| |
| /* Emit early space padding */ |
| if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars) |
| { |
| while (width > nchars) |
| { |
| EMIT(' '); |
| width--; |
| } |
| } |
| |
| /* Emit nondigits */ |
| if (minus) |
| { |
| EMIT('-'); |
| } |
| else if (flags & FL_PLUS) |
| { |
| EMIT('+'); |
| } |
| else if (flags & FL_SPACE) |
| { |
| EMIT(' '); |
| } |
| |
| if ((flags & FL_HASH) && base == 16) |
| { |
| EMIT('0'); |
| EMIT((flags & FL_UPPER) ? 'X' : 'x'); |
| } |
| |
| /* Emit zero padding */ |
| if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits) |
| { |
| while (width > nchars) |
| { |
| EMIT('0'); |
| width--; |
| } |
| } |
| |
| /* Generate the number. This is done from right to left. */ |
| q += ndigits; /* Advance the pointer to end of number */ |
| o += ndigits; |
| qq = q; |
| oo = o; /* Temporary values */ |
| |
| b4tick = tickskip; |
| while (ndigits > 0) |
| { |
| if (!b4tick--) |
| { |
| qq--; |
| oo--; |
| ndigits--; |
| if (oo < n) |
| *qq = '_'; |
| b4tick = tickskip - 1; |
| } |
| qq--; |
| oo--; |
| ndigits--; |
| if (oo < n) |
| *qq = digits[val % base]; |
| val /= base; |
| } |
| |
| /* Emit late space padding */ |
| while ((flags & FL_MINUS) && width > nchars) |
| { |
| EMIT(' '); |
| width--; |
| } |
| |
| return o; |
| } |
| |
| #define ZEROPAD (1 << 0) /* Pad with zero */ |
| #define SIGN (1 << 1) /* Unsigned/signed long */ |
| #define PLUS (1 << 2) /* Show plus */ |
| #define SPACE (1 << 3) /* Spacer */ |
| #define LEFT (1 << 4) /* Left justified */ |
| #define HEX_PREP (1 << 5) /* 0x */ |
| #define UPPERCASE (1 << 6) /* 'ABCDEF' */ |
| |
| #include <math.h> |
| #define CVTBUFSIZE 80 |
| |
| static char * cvt(double arg, int ndigits, int * decpt, int * sign, char * buf, int eflag) |
| { |
| int r2; |
| double fi, fj; |
| char *p, *p1; |
| |
| if (ndigits < 0) |
| ndigits = 0; |
| if (ndigits >= CVTBUFSIZE - 1) |
| ndigits = CVTBUFSIZE - 2; |
| r2 = 0; |
| *sign = 0; |
| p = &buf[0]; |
| if (arg < 0) |
| { |
| *sign = 1; |
| arg = -arg; |
| } |
| arg = modf(arg, &fi); |
| p1 = &buf[CVTBUFSIZE]; |
| |
| if (fi != 0) |
| { |
| p1 = &buf[CVTBUFSIZE]; |
| while (fi != 0) |
| { |
| fj = modf(fi / 10, &fi); |
| *--p1 = (int) ((fj + 0.03) * 10) + '0'; |
| r2++; |
| } |
| while (p1 < &buf[CVTBUFSIZE]) |
| *p++ = *p1++; |
| } |
| else if (arg > 0) |
| { |
| while ((fj = arg * 10) < 1) |
| { |
| arg = fj; |
| r2--; |
| } |
| } |
| p1 = &buf[ndigits]; |
| if (eflag == 0) |
| p1 += r2; |
| *decpt = r2; |
| if (p1 < &buf[0]) |
| { |
| buf[0] = '\0'; |
| return buf; |
| } |
| while (p <= p1 && p < &buf[CVTBUFSIZE]) |
| { |
| arg *= 10; |
| arg = modf(arg, &fj); |
| *p++ = (int) fj + '0'; |
| } |
| if (p1 >= &buf[CVTBUFSIZE]) |
| { |
| buf[CVTBUFSIZE - 1] = '\0'; |
| return buf; |
| } |
| p = p1; |
| *p1 += 5; |
| while (*p1 > '9') |
| { |
| *p1 = '0'; |
| if (p1 > buf) |
| ++*--p1; |
| else |
| { |
| *p1 = '1'; |
| (*decpt)++; |
| if (eflag == 0) |
| { |
| if (p > buf) |
| *p = '0'; |
| p++; |
| } |
| } |
| } |
| *p = '\0'; |
| return buf; |
| } |
| |
| char * ecvtbuf(double arg, int ndigits, int * decpt, int * sign, char * buf) |
| { |
| return cvt(arg, ndigits, decpt, sign, buf, 1); |
| } |
| |
| char * fcvtbuf(double arg, int ndigits, int * decpt, int * sign, char * buf) |
| { |
| return cvt(arg, ndigits, decpt, sign, buf, 0); |
| } |
| |
| static void ee_bufcpy(char * d, char * s, int count); |
| |
| void ee_bufcpy(char * pd, char * ps, int count) |
| { |
| char * pe = ps + count; |
| while (ps != pe) |
| *pd++ = *ps++; |
| } |
| |
| static void parse_float(double value, char * buffer, char fmt, int precision) |
| { |
| int decpt, sign, exp, pos; |
| char * digits = NULL; |
| char cvtbuf[80]; |
| int capexp = 0; |
| int magnitude; |
| |
| if (fmt == 'G' || fmt == 'E') |
| { |
| capexp = 1; |
| fmt += 'a' - 'A'; |
| } |
| |
| if (fmt == 'g') |
| { |
| digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); |
| magnitude = decpt - 1; |
| if (magnitude < -4 || magnitude > precision - 1) |
| { |
| fmt = 'e'; |
| precision -= 1; |
| } |
| else |
| { |
| fmt = 'f'; |
| precision -= decpt; |
| } |
| } |
| |
| if (fmt == 'e') |
| { |
| digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); |
| |
| if (sign) |
| *buffer++ = '-'; |
| *buffer++ = *digits; |
| if (precision > 0) |
| *buffer++ = '.'; |
| ee_bufcpy(buffer, digits + 1, precision); |
| buffer += precision; |
| *buffer++ = capexp ? 'E' : 'e'; |
| |
| if (decpt == 0) |
| { |
| if (value == 0.0) |
| exp = 0; |
| else |
| exp = -1; |
| } |
| else |
| exp = decpt - 1; |
| |
| if (exp < 0) |
| { |
| *buffer++ = '-'; |
| exp = -exp; |
| } |
| else |
| *buffer++ = '+'; |
| |
| buffer[2] = (exp % 10) + '0'; |
| exp = exp / 10; |
| buffer[1] = (exp % 10) + '0'; |
| exp = exp / 10; |
| buffer[0] = (exp % 10) + '0'; |
| buffer += 3; |
| } |
| else if (fmt == 'f') |
| { |
| digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); |
| if (sign) |
| *buffer++ = '-'; |
| if (*digits) |
| { |
| if (decpt <= 0) |
| { |
| *buffer++ = '0'; |
| *buffer++ = '.'; |
| for (pos = 0; pos < -decpt; pos++) |
| *buffer++ = '0'; |
| while (*digits) |
| *buffer++ = *digits++; |
| } |
| else |
| { |
| pos = 0; |
| while (*digits) |
| { |
| if (pos++ == decpt) |
| *buffer++ = '.'; |
| *buffer++ = *digits++; |
| } |
| } |
| } |
| else |
| { |
| *buffer++ = '0'; |
| if (precision > 0) |
| { |
| *buffer++ = '.'; |
| for (pos = 0; pos < precision; pos++) |
| *buffer++ = '0'; |
| } |
| } |
| } |
| |
| *buffer = '\0'; |
| } |
| |
| static void decimal_point(char * buffer) |
| { |
| while (*buffer) |
| { |
| if (*buffer == '.') |
| return; |
| if (*buffer == 'e' || *buffer == 'E') |
| break; |
| buffer++; |
| } |
| |
| if (*buffer) |
| { |
| int n = strnlen(buffer, 256); |
| while (n > 0) |
| { |
| buffer[n + 1] = buffer[n]; |
| n--; |
| } |
| |
| *buffer = '.'; |
| } |
| else |
| { |
| *buffer++ = '.'; |
| *buffer = '\0'; |
| } |
| } |
| |
| static void cropzeros(char * buffer) |
| { |
| char * stop; |
| |
| while (*buffer && *buffer != '.') |
| buffer++; |
| if (*buffer++) |
| { |
| while (*buffer && *buffer != 'e' && *buffer != 'E') |
| buffer++; |
| stop = buffer--; |
| while (*buffer == '0') |
| buffer--; |
| if (*buffer == '.') |
| buffer--; |
| while (buffer != stop) |
| *++buffer = 0; |
| } |
| } |
| |
| static char * flt(char * str, double num, int size, int precision, char fmt, int flags) |
| { |
| char tmp[80]; |
| char c, sign; |
| int n, i; |
| |
| // Left align means no zero padding |
| if (flags & LEFT) |
| flags &= ~ZEROPAD; |
| |
| // Determine padding and sign char |
| c = (flags & ZEROPAD) ? '0' : ' '; |
| sign = 0; |
| if (flags & SIGN) |
| { |
| if (num < 0.0) |
| { |
| sign = '-'; |
| num = -num; |
| size--; |
| } |
| else if (flags & PLUS) |
| { |
| sign = '+'; |
| size--; |
| } |
| else if (flags & SPACE) |
| { |
| sign = ' '; |
| size--; |
| } |
| } |
| |
| // Compute the precision value |
| if (precision < 0) |
| precision = 6; // Default precision: 6 |
| |
| // Convert floating point number to text |
| parse_float(num, tmp, fmt, precision); |
| |
| if ((flags & HEX_PREP) && precision == 0) |
| decimal_point(tmp); |
| if (fmt == 'g' && !(flags & HEX_PREP)) |
| cropzeros(tmp); |
| |
| n = strnlen(tmp, 256); |
| |
| // Output number with alignment and padding |
| size -= n; |
| if (!(flags & (ZEROPAD | LEFT))) |
| while (size-- > 0) |
| *str++ = ' '; |
| if (sign) |
| *str++ = sign; |
| if (!(flags & LEFT)) |
| while (size-- > 0) |
| *str++ = c; |
| for (i = 0; i < n; i++) |
| *str++ = tmp[i]; |
| while (size-- > 0) |
| *str++ = ' '; |
| |
| return str; |
| } |
| |
| /*use O0 preventing consuming more stack*/ |
| int __attribute__((optimize("O1"))) vsnprintf(char * buffer, size_t n, const char * format, va_list ap) |
| { |
| const char * p = format; |
| char ch; |
| char * q = buffer; |
| size_t o = 0; /* Number of characters output */ |
| uintmax_t val = 0; |
| int rank = rank_int; /* Default rank */ |
| int width = 0; |
| int prec = -1; |
| int base; |
| size_t sz; |
| unsigned int flags = 0; |
| enum |
| { |
| st_normal, /* Ground state */ |
| st_flags, /* Special flags */ |
| st_width, /* Field width */ |
| st_prec, /* Field precision */ |
| st_modifiers /* Length or conversion modifiers */ |
| } state = st_normal; |
| const char * sarg; /* %s string argument */ |
| char carg; /* %c char argument */ |
| int slen; /* String length */ |
| |
| while ((ch = *p++)) |
| { |
| switch (state) |
| { |
| case st_normal: |
| if (ch == '%') |
| { |
| state = st_flags; |
| flags = 0; |
| rank = rank_int; |
| width = 0; |
| prec = -1; |
| } |
| else |
| { |
| EMIT(ch); |
| } |
| break; |
| |
| case st_flags: |
| switch (ch) |
| { |
| case '-': |
| flags |= FL_MINUS; |
| break; |
| case '+': |
| flags |= FL_PLUS; |
| break; |
| case '\'': |
| flags |= FL_TICK; |
| break; |
| case ' ': |
| flags |= FL_SPACE; |
| break; |
| case '#': |
| flags |= FL_HASH; |
| break; |
| case '0': |
| flags |= FL_ZERO; |
| break; |
| default: |
| state = st_width; |
| p--; /* Process this character again */ |
| break; |
| } |
| break; |
| |
| case st_width: |
| if (ch >= '0' && ch <= '9') |
| { |
| width = width * 10 + (ch - '0'); |
| } |
| else if (ch == '*') |
| { |
| width = va_arg(ap, int); |
| if (width < 0) |
| { |
| width = -width; |
| flags |= FL_MINUS; |
| } |
| } |
| else if (ch == '.') |
| { |
| prec = 0; /* Precision given */ |
| state = st_prec; |
| } |
| else |
| { |
| state = st_modifiers; |
| p--; /* Process this character again */ |
| } |
| break; |
| |
| case st_prec: |
| if (ch >= '0' && ch <= '9') |
| { |
| prec = prec * 10 + (ch - '0'); |
| } |
| else if (ch == '*') |
| { |
| prec = va_arg(ap, int); |
| if (prec < 0) |
| prec = -1; |
| } |
| else |
| { |
| state = st_modifiers; |
| p--; /* Process this character again */ |
| } |
| break; |
| |
| case st_modifiers: |
| switch (ch) |
| { |
| /* Length modifiers - nonterminal sequences */ |
| case 'h': |
| rank--; /* Shorter rank */ |
| break; |
| case 'l': |
| rank++; /* Longer rank */ |
| break; |
| case 'j': |
| rank = INTMAX_RANK; |
| break; |
| case 'z': |
| rank = SIZE_T_RANK; |
| break; |
| case 't': |
| rank = PTRDIFF_T_RANK; |
| break; |
| case 'L': |
| case 'q': |
| rank += 2; |
| break; |
| default: |
| /* Output modifiers - terminal sequences */ |
| |
| /* Next state will be normal */ |
| state = st_normal; |
| |
| /* Canonicalize rank */ |
| if (rank < MIN_RANK) |
| rank = MIN_RANK; |
| else if (rank > MAX_RANK) |
| rank = MAX_RANK; |
| |
| switch (ch) |
| { |
| case 'P': /* Upper case pointer */ |
| flags |= FL_UPPER; |
| __attribute__((fallthrough)); |
| /* fall through */ |
| case 'p': /* Pointer */ |
| base = 16; |
| prec = (CHAR_BIT * sizeof(void *) + 3) / 4; |
| flags |= FL_HASH; |
| val = (uintmax_t)(uintptr_t) va_arg(ap, void *); |
| goto is_integer; |
| |
| case 'd': /* Signed decimal output */ |
| case 'i': |
| base = 10; |
| flags |= FL_SIGNED; |
| switch (rank) |
| { |
| case rank_char: |
| /* Yes, all these casts are |
| needed... */ |
| val = (uintmax_t)(intmax_t)(signed char) va_arg(ap, signed int); |
| break; |
| case rank_short: |
| val = (uintmax_t)(intmax_t)(signed short) va_arg(ap, signed int); |
| break; |
| case rank_int: |
| val = (uintmax_t)(intmax_t) va_arg(ap, signed int); |
| break; |
| case rank_long: |
| val = (uintmax_t)(intmax_t) va_arg(ap, signed long); |
| break; |
| case rank_longlong: |
| val = (uintmax_t)(intmax_t) va_arg(ap, signed long long); |
| break; |
| } |
| goto is_integer; |
| case 'o': /* Octal */ |
| base = 8; |
| goto is_unsigned; |
| case 'u': /* Unsigned decimal */ |
| base = 10; |
| goto is_unsigned; |
| case 'X': /* Upper case hexadecimal */ |
| flags |= FL_UPPER; |
| __attribute__((fallthrough)); |
| /* fall through */ |
| case 'x': /* Hexadecimal */ |
| base = 16; |
| goto is_unsigned; |
| |
| is_unsigned: |
| switch (rank) |
| { |
| case rank_char: |
| val = (uintmax_t)(unsigned char) va_arg(ap, unsigned int); |
| break; |
| case rank_short: |
| val = (uintmax_t)(unsigned short) va_arg(ap, unsigned int); |
| break; |
| case rank_int: |
| val = (uintmax_t) va_arg(ap, unsigned int); |
| break; |
| case rank_long: |
| val = (uintmax_t) va_arg(ap, unsigned long); |
| break; |
| case rank_longlong: |
| val = (uintmax_t) va_arg(ap, unsigned long long); |
| break; |
| } |
| /* fall through */ |
| |
| is_integer: |
| sz = format_int(q, (o < n) ? n - o : 0, val, flags, base, width, prec); |
| q += sz; |
| o += sz; |
| break; |
| |
| case 'c': /* Character */ |
| carg = (char) va_arg(ap, int); |
| sarg = &carg; |
| slen = 1; |
| goto is_string; |
| case 's': /* String */ |
| sarg = va_arg(ap, const char *); |
| sarg = sarg ? sarg : "(null)"; |
| slen = strlen(sarg); |
| goto is_string; |
| |
| is_string : { |
| char sch; |
| int i; |
| |
| if (prec != -1 && slen > prec) |
| slen = prec; |
| |
| if (width > slen && !(flags & FL_MINUS)) |
| { |
| char pad = (flags & FL_ZERO) ? '0' : ' '; |
| while (width > slen) |
| { |
| EMIT(pad); |
| width--; |
| } |
| } |
| for (i = slen; i; i--) |
| { |
| sch = *sarg++; |
| EMIT(sch); |
| } |
| if (width > slen && (flags & FL_MINUS)) |
| { |
| while (width > slen) |
| { |
| EMIT(' '); |
| width--; |
| } |
| } |
| } |
| break; |
| |
| case 'n': { |
| /* Output the number of |
| characters written */ |
| |
| switch (rank) |
| { |
| case rank_char: |
| *va_arg(ap, signed char *) = o; |
| break; |
| case rank_short: |
| *va_arg(ap, signed short *) = o; |
| break; |
| case rank_int: |
| *va_arg(ap, signed int *) = o; |
| break; |
| case rank_long: |
| *va_arg(ap, signed long *) = o; |
| break; |
| case rank_longlong: |
| *va_arg(ap, signed long long *) = o; |
| break; |
| } |
| } |
| break; |
| #ifndef DISABLE_PRINT_FLOAT |
| case 'f': { |
| q = flt(q, va_arg(ap, double), width, prec, ch, SIGN); |
| continue; |
| } |
| #endif |
| default: /* Anything else, including % */ |
| EMIT(ch); |
| break; |
| } |
| } |
| } |
| } |
| |
| /* Null-terminate the string */ |
| if (o < n) |
| *q = '\0'; /* No overflow */ |
| else if (n > 0) |
| buffer[n - 1] = '\0'; /* Overflow - terminate at end of buffer */ |
| |
| return o; |
| } |
| |
| #ifdef SYS_BIG_DEBUG_BUFFER |
| static char string[2048]; |
| #else |
| static char string[512]; |
| #endif |
| |
| int vsprintf(char * buffer, const char * format, va_list ap) |
| { |
| return vsnprintf(buffer, sizeof(string) - 32, format, ap); |
| } |
| |
| extern volatile bool sys_log_all_enable; |
| |
| void vprint(const char * fmt, va_list argp) |
| { |
| char * str; |
| int ch; |
| |
| if (sys_log_all_enable) |
| { |
| str = string; |
| if (0 < vsprintf(string, fmt, argp)) |
| { |
| if (!async_log()) |
| { |
| while ('\0' != (ch = *(str++))) |
| { |
| #if !defined(DISABLE_PRINT) |
| bl_uart_data_send(0, ch); |
| #endif |
| } |
| } |
| else |
| { |
| async_log_push(str, strlen(str) + 1); |
| } |
| } |
| } |
| } |
| |
| int bl_putchar(int c) |
| { |
| #if !defined(DISABLE_PRINT) |
| bl_uart_data_send(0, c); |
| #endif |
| return 0; |
| } |
| |
| int puts(const char * s) |
| { |
| int counter = 0; |
| char c; |
| |
| if (sys_log_all_enable) |
| { |
| while ('\0' != (c = *(s++))) |
| { |
| #if !defined(DISABLE_PRINT) |
| bl_uart_data_send(0, c); |
| #endif |
| counter++; |
| } |
| } |
| return counter; |
| } |
| |
| int printf(const char * fmt, ...) |
| { |
| va_list argp; |
| |
| if (sys_log_all_enable) |
| { |
| va_start(argp, fmt); |
| vprint(fmt, argp); |
| va_end(argp); |
| } |
| |
| return 0; |
| } |
| |
| int sprintf(char * buffer, const char * format, ...) |
| { |
| va_list ap; |
| int rv; |
| |
| va_start(ap, format); |
| rv = vsnprintf(buffer, ~(size_t) 0, format, ap); |
| va_end(ap); |
| |
| return rv; |
| } |
| |
| int snprintf(char * buffer, size_t n, const char * format, ...) |
| { |
| va_list ap; |
| int rv; |
| |
| va_start(ap, format); |
| rv = vsnprintf(buffer, n, format, ap); |
| va_end(ap); |
| return rv; |
| } |
| |
| void vMainUARTPrintString(char * pcString) |
| { |
| puts(pcString); |
| } |