• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3 */
4 ///////////////////////////////////////////////////////////////////////////////
5 // \author (c) Marco Paland (info@paland.com)
6 //             2014-2019, PALANDesign Hannover, Germany
7 //
8 // \license The MIT License (MIT)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28 // \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
29 //        embedded systems with a very limited resources. These routines are thread
30 //        safe and reentrant!
31 //        Use this instead of the bloated standard/newlib printf cause these use
32 //        malloc for printf (and may not be thread safe).
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 #include <stdbool.h>
37 #include <stdint.h>
38 #include <stdarg.h>
39 #include <stddef.h>
40 #include "usart.h"
41 
42 // define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
43 // printf_config.h header file
44 // default: undefined
45 #ifdef PRINTF_INCLUDE_CONFIG_H
46 #include "printf_config.h"
47 #endif
48 
49 // 'ntoa' conversion buffer size, this must be big enough to hold one converted
50 // numeric number including padded zeros (dynamically created on stack)
51 // default: 32 byte
52 #ifndef PRINTF_NTOA_BUFFER_SIZE
53 #define PRINTF_NTOA_BUFFER_SIZE 32U
54 #endif
55 
56 // 'ftoa' conversion buffer size, this must be big enough to hold one converted
57 // float number including padded zeros (dynamically created on stack)
58 // default: 32 byte
59 #ifndef PRINTF_FTOA_BUFFER_SIZE
60 #define PRINTF_FTOA_BUFFER_SIZE 32U
61 #endif
62 
63 // support for the floating point type (%f)
64 // default: activated
65 #ifndef PRINTF_DISABLE_SUPPORT_FLOAT
66 #define PRINTF_SUPPORT_FLOAT
67 #endif
68 
69 // define the default floating point precision
70 // default: 6 digits
71 #ifndef PRINTF_DEFAULT_FLOAT_PRECISION
72 #define PRINTF_DEFAULT_FLOAT_PRECISION 6U
73 #endif
74 
75 // define the largest float suitable to print with %f
76 // default: 1e9
77 #ifndef PRINTF_MAX_FLOAT
78 #define PRINTF_MAX_FLOAT 1e9
79 #endif
80 
81 // support for the long long types (%llu or %p)
82 // default: activated
83 #ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
84 #define PRINTF_SUPPORT_LONG_LONG
85 #endif
86 
87 // support for the ptrdiff_t type (%t)
88 // ptrdiff_t is normally defined in <stddef.h> as long or long long type
89 // default: activated
90 #ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
91 #define PRINTF_SUPPORT_PTRDIFF_T
92 #endif
93 
94 // internal flag definitions
95 #define FLAGS_ZEROPAD (1U << 0U)
96 #define FLAGS_LEFT (1U << 1U)
97 #define FLAGS_PLUS (1U << 2U)
98 #define FLAGS_SPACE (1U << 3U)
99 #define FLAGS_HASH (1U << 4U)
100 #define FLAGS_UPPERCASE (1U << 5U)
101 #define FLAGS_CHAR (1U << 6U)
102 #define FLAGS_SHORT (1U << 7U)
103 #define FLAGS_LONG (1U << 8U)
104 #define FLAGS_LONG_LONG (1U << 9U)
105 #define FLAGS_PRECISION (1U << 10U)
106 #define FLAGS_ADAPT_EXP (1U << 11U)
107 
108 // import float.h for DBL_MAX
109 #if defined(PRINTF_SUPPORT_FLOAT)
110 #include <float.h>
111 #endif
112 
113 // output function type
114 typedef void (*out_fct_type)(char character, void *buffer, int idx, int maxlen);
115 
116 // wrapper (used as buffer) for output function type
117 typedef struct {
118     void (*fct)(char character, void *arg);
119     void *arg;
120 } out_fct_wrap_type;
121 
122 // internal buffer output
Gd32OutBuffer(char character,void * buffer,int idx,int maxlen)123 static inline void Gd32OutBuffer(char character, void *buffer, int idx, int maxlen)
124 {
125     if (idx < maxlen) {
126         ((char *)buffer)[idx] = character;
127     }
128 }
129 
130 // internal null output
Gd32OutNull(char character,void * buffer,int idx,int maxlen)131 static inline void Gd32OutNull(char character, void *buffer, int idx, int maxlen)
132 {
133     (void)character;
134     (void)buffer;
135     (void)idx;
136     (void)maxlen;
137 }
138 
Gd32OutChar(char character,void * buffer,int idx,int maxlen)139 static inline void Gd32OutChar(char character, void *buffer, int idx, int maxlen)
140 {
141     (void)buffer;
142     (void)idx;
143     (void)maxlen;
144     if (character) {
145         Gd32IoPutChar(character);
146     }
147 }
148 
149 // internal output function wrapper
Gd32OutFct(char character,void * buffer,int idx,int maxlen)150 static inline void Gd32OutFct(char character, void *buffer, int idx, int maxlen)
151 {
152     (void)idx;
153     (void)maxlen;
154     if (character) {
155         // buffer is the output fct pointer
156         ((out_fct_wrap_type *)buffer)->fct(character, ((out_fct_wrap_type *)buffer)->arg);
157     }
158 }
159 
160 // internal secure strlen
161 // \return The length of the string (excluding the terminating 0) limited by 'maxsize'
Gd32Strnlen(const char * str,int maxsizein)162 static inline unsigned int Gd32Strnlen(const char *str, int maxsizein)
163 {
164     int maxsize = maxsizein;
165     const char *s;
166     for (s = str; *s && maxsize--; ++s) { }
167     return (unsigned int)(s - str);
168 }
169 
170 // internal test if char is a digit (0-9)
171 // \return true if char is a digit
_is_digit(char ch)172 static inline bool _is_digit(char ch)
173 {
174     return (ch >= '0') && (ch <= '9');
175 }
176 
177 // internal ASCII string to unsigned int conversion
178 #define INTERVAL_ATOI 10U
_atoi(const char ** str)179 static unsigned int _atoi(const char **str)
180 {
181     unsigned int i = 0U;
182     while (_is_digit(**str)) {
183         i = i * INTERVAL_ATOI + (unsigned int)(*((*str)++) - '0');
184     }
185     return i;
186 }
187 
188 // output the specified string in reverse, taking care of any zero-padding
Gd32OutRev(out_fct_type out,char * buffer,int idxin,int maxlen,const char * buf,int length,unsigned int width,unsigned int flags)189 static int Gd32OutRev(out_fct_type out, char *buffer, int idxin, int maxlen, const char *buf, int length,
190                       unsigned int width, unsigned int flags)
191 {
192     const int start_idx = idxin;
193     int idx = idxin;
194     int len = length;
195     // pad spaces up to given width
196     if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
197         for (int i = len; i < width; i++) {
198             out(' ', buffer, idx++, maxlen);
199         }
200     }
201 
202     // reverse string
203     while (len) {
204         out(buf[--len], buffer, idx++, maxlen);
205     }
206 
207     // append pad spaces up to given width
208     if (flags & FLAGS_LEFT) {
209         while (idx - start_idx < width) {
210             out(' ', buffer, idx++, maxlen);
211         }
212     }
213 
214     return idx;
215 }
216 #define HEXADECIMAL 16U
217 #define OCTONARY 8U
218 #define BINARY 2U
219 
220 // internal itoa format
Gd32NtoaFormat(out_fct_type out,char * buffer,int idx,int maxlen,char * buf,int length,bool negative,unsigned int base,unsigned int prec,unsigned int widthin,unsigned int flags)221 static int Gd32NtoaFormat(out_fct_type out, char *buffer, int idx, int maxlen, char *buf, int length, bool negative,
222                           unsigned int base, unsigned int prec, unsigned int widthin, unsigned int flags)
223 {
224     int len = length;
225     int width = widthin;
226     // pad leading zeros
227     if (!(flags & FLAGS_LEFT)) {
228         if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
229             width--;
230         }
231         while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
232             buf[len++] = '0';
233         }
234         while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
235             buf[len++] = '0';
236         }
237     }
238 
239     // handle hash
240     if (flags & FLAGS_HASH) {
241         if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
242             len--;
243             if (len && (base == HEXADECIMAL)) {
244                 len--;
245             }
246         }
247         if ((base == HEXADECIMAL) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
248             buf[len++] = 'x';
249         } else if ((base == HEXADECIMAL) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
250             buf[len++] = 'X';
251         } else if ((base == BINARY) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
252             buf[len++] = 'b';
253         }
254         if (len < PRINTF_NTOA_BUFFER_SIZE) {
255             buf[len++] = '0';
256         }
257     }
258 
259     if (len < PRINTF_NTOA_BUFFER_SIZE) {
260         if (negative) {
261             buf[len++] = '-';
262         } else if (flags & FLAGS_PLUS) {
263             buf[len++] = '+'; // ignore the space if the '+' exists
264         } else if (flags & FLAGS_SPACE) {
265             buf[len++] = ' ';
266         }
267     }
268 
269     return Gd32OutRev(out, buffer, idx, maxlen, buf, len, width, flags);
270 }
271 
272 // internal itoa for 'long' type
Gd32NtoaLong(out_fct_type out,char * buffer,int idx,int maxlen,unsigned long valuein,bool negative,unsigned long base,unsigned int prec,unsigned int width,unsigned int flagsin)273 static int Gd32NtoaLong(out_fct_type out, char *buffer, int idx, int maxlen, unsigned long valuein, bool negative,
274                         unsigned long base, unsigned int prec, unsigned int width, unsigned int flagsin)
275 {
276     char buf[PRINTF_NTOA_BUFFER_SIZE];
277     int len = 0U;
278     unsigned int flags = flagsin;
279     unsigned long value = valuein;
280     // no hash for 0 values
281     if (!value) {
282         flags &= ~FLAGS_HASH;
283     }
284 
285     // write if precision != 0 and value is != 0
286     if (!(flags & FLAGS_PRECISION) || value) {
287         do {
288             if (base == 0) {
289                 return 0;
290             }
291             const char digit = (char)(value % base);
292             buf[len++] = digit < 0x0A ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 0x0A;
293             value /= base;
294         } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
295     }
296 
297     return Gd32NtoaFormat(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
298 }
299 #define MAX_DIGITS 9
300 
301 // internal itoa for 'long long' type
302 #if defined(PRINTF_SUPPORT_LONG_LONG)
Gd32NtoaLongLong(out_fct_type out,char * buffer,int idx,int maxlen,unsigned long long valuein,bool negative,unsigned long long base,unsigned int prec,unsigned int width,unsigned int flagsin)303 static int Gd32NtoaLongLong(out_fct_type out, char *buffer, int idx, int maxlen, unsigned long long valuein,
304                             bool negative, unsigned long long base, unsigned int prec, unsigned int width,
305                             unsigned int flagsin)
306 {
307     char buf[PRINTF_NTOA_BUFFER_SIZE];
308     int len = 0U;
309     unsigned int flags = flagsin;
310     unsigned long long value = valuein;
311     // no hash for 0 values
312     if (!value) {
313         flags &= ~FLAGS_HASH;
314     }
315 
316     // write if precision != 0 and value is != 0
317     if (!(flags & FLAGS_PRECISION) || value) {
318         do {
319             if (base == 0) {
320                 return 0;
321             }
322             const char digit = (char)(value % base);
323             buf[len++] = digit < (MAX_DIGITS + 1) ? '0' + digit
324                                                   : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - (MAX_DIGITS + 1);
325             value /= base;
326         } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
327     }
328 
329     return Gd32NtoaFormat(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
330 }
331 #endif // PRINTF_SUPPORT_LONG_LONG
332 
333 #if defined(PRINTF_SUPPORT_FLOAT)
334 
335 #define LIMIT_PRECISION 9U
336 // internal ftoa for fixed decimal floating point
Gd32Ftoa(out_fct_type out,char * buffer,int idx,int maxlen,double valuein,unsigned int precin,unsigned int widthin,unsigned int flags)337 static int Gd32Ftoa(out_fct_type out, char *buffer, int idx, int maxlen, double valuein, unsigned int precin,
338                     unsigned int widthin, unsigned int flags)
339 {
340     char buf[PRINTF_FTOA_BUFFER_SIZE];
341     int len = 0U;
342     double diff = 0.0;
343     double value = valuein;
344     unsigned int prec = precin;
345     unsigned int width = widthin;
346     // powers of 10
347     static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
348 
349     // test for special values
350     if (value != value) {
351         return Gd32OutRev(out, buffer, idx, maxlen, "nan", sizeof("nan"), width, flags);
352     }
353     if (value < -DBL_MAX) {
354         return Gd32OutRev(out, buffer, idx, maxlen, "fni-", sizeof("fni-"), width, flags);
355     }
356     if (value > DBL_MAX) {
357         return Gd32OutRev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni",
358                           (flags & FLAGS_PLUS) ? sizeof("fni+") : sizeof("fni"), width, flags);
359     }
360 
361     // test for very large values
362     // standard printf behavior is to print EVERY whole number digit
363     // -- which could be 100s of characters overflowing your buffers == bad
364     if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
365         return 0U;
366     }
367 
368     // test for negative
369     bool negative = false;
370     if (value < 0) {
371         negative = true;
372         value = 0 - value;
373     }
374 
375     // set default precision, if not set explicitly
376     if (!(flags & FLAGS_PRECISION)) {
377         prec = PRINTF_DEFAULT_FLOAT_PRECISION;
378     }
379     // limit precision to 9, cause a prec >= 10 can lead to overflow errors
380     while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > LIMIT_PRECISION)) {
381         buf[len++] = '0';
382         prec--;
383     }
384 
385     int whole = (int)value;
386     double tmp = (value - whole) * pow10[prec];
387     unsigned long frac = (unsigned long)tmp;
388     diff = tmp - frac;
389 #define MIN_PRECISION 0.5
390     if (diff > MIN_PRECISION) {
391         ++frac;
392         // handle rollover, e.g. case 0.99 with prec 1 is 1.0
393         if (frac >= pow10[prec]) {
394             frac = 0;
395             ++whole;
396         }
397     } else if (diff < MIN_PRECISION) {
398     } else if ((frac == 0U) || (frac & 1U)) {
399         // if halfway, round up if odd OR if last digit is 0
400         ++frac;
401     }
402 
403     if (prec == 0U) {
404         diff = value - (double)whole;
405         if ((!(diff < MIN_PRECISION) || (diff > MIN_PRECISION)) && (whole & 1)) {
406             // exactly 0.5 and ODD, then round up
407             // 1.5 -> 2, but 2.5 -> 2
408             ++whole;
409         }
410     } else {
411         unsigned int count = prec;
412         // now do fractional part, as an unsigned number
413         while (len < PRINTF_FTOA_BUFFER_SIZE) {
414             --count;
415             buf[len++] = (char)(0x30 + (frac % 0x0A));
416             if (!(frac /= 0x0A)) {
417                 break;
418             }
419         }
420         // add extra 0s
421         while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
422             buf[len++] = '0';
423         }
424         if (len < PRINTF_FTOA_BUFFER_SIZE) {
425             // add decimal
426             buf[len++] = '.';
427         }
428     }
429 
430     // do whole part, number is reversed
431     while (len < PRINTF_FTOA_BUFFER_SIZE) {
432         buf[len++] = (char)(0x30 + (whole % 0x0A));
433         if (!(whole /= 0x0A)) {
434             break;
435         }
436     }
437 
438     // pad leading zeros
439     if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
440         if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
441             width--;
442         }
443         while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
444             buf[len++] = '0';
445         }
446     }
447 
448     if (len < PRINTF_FTOA_BUFFER_SIZE) {
449         if (negative) {
450             buf[len++] = '-';
451         } else if (flags & FLAGS_PLUS) {
452             buf[len++] = '+'; // ignore the space if the '+' exists
453         } else if (flags & FLAGS_SPACE) {
454             buf[len++] = ' ';
455         }
456     }
457 
458     return Gd32OutRev(out, buffer, idx, maxlen, buf, len, width, flags);
459 }
460 
461 #endif // PRINTF_SUPPORT_FLOAT
462 
463 // internal vsnprintf
Gd32Vsnintf(out_fct_type outin,char * buffer,const int maxlen,const char * formatin,va_list va)464 static int Gd32Vsnintf(out_fct_type outin, char *buffer, const int maxlen, const char *formatin, va_list va)
465 {
466     unsigned int flags, width, precision, n;
467     int idx = 0U;
468     const char *format = formatin;
469     out_fct_type out = outin;
470     if (!buffer) {
471         // use null output function
472         out = Gd32OutNull;
473     }
474 
475     while (*format) {
476         // format specifier?  %[flags][width][.precision][length]
477         if (*format != '%') {
478             // no
479             out(*format, buffer, idx++, maxlen);
480             format++;
481             continue;
482         } else {
483             // yes, evaluate it
484             format++;
485         }
486 
487         // evaluate flags
488         flags = 0U;
489         do {
490             switch (*format) {
491                 case '0':
492                     flags |= FLAGS_ZEROPAD;
493                     format++;
494                     n = 1U;
495                     break;
496                 case '-':
497                     flags |= FLAGS_LEFT;
498                     format++;
499                     n = 1U;
500                     break;
501                 case '+':
502                     flags |= FLAGS_PLUS;
503                     format++;
504                     n = 1U;
505                     break;
506                 case ' ':
507                     flags |= FLAGS_SPACE;
508                     format++;
509                     n = 1U;
510                     break;
511                 case '#':
512                     flags |= FLAGS_HASH;
513                     format++;
514                     n = 1U;
515                     break;
516                 default:
517                     n = 0U;
518                     break;
519             }
520         } while (n);
521 
522         // evaluate width field
523         width = 0U;
524         if (_is_digit(*format)) {
525             width = _atoi(&format);
526         } else if (*format == '*') {
527             const int w = va_arg(va, int);
528             if (w < 0) {
529                 flags |= FLAGS_LEFT; // reverse padding
530                 width = (unsigned int)-w;
531             } else {
532                 width = (unsigned int)w;
533             }
534             format++;
535         }
536 
537         // evaluate precision field
538         precision = 0U;
539         if (*format == '.') {
540             flags |= FLAGS_PRECISION;
541             format++;
542             if (_is_digit(*format)) {
543                 precision = _atoi(&format);
544             } else if (*format == '*') {
545                 const int prec = (int)va_arg(va, int);
546                 precision = prec > 0 ? (unsigned int)prec : 0U;
547                 format++;
548             }
549         }
550 
551         // evaluate length field
552         switch (*format) {
553             case 'l':
554                 flags |= FLAGS_LONG;
555                 format++;
556                 if (*format == 'l') {
557                     flags |= FLAGS_LONG_LONG;
558                     format++;
559                 }
560                 break;
561             case 'h':
562                 flags |= FLAGS_SHORT;
563                 format++;
564                 if (*format == 'h') {
565                     flags |= FLAGS_CHAR;
566                     format++;
567                 }
568                 break;
569 #if defined(PRINTF_SUPPORT_PTRDIFF_T)
570             case 't':
571                 flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
572                 format++;
573                 break;
574 #endif
575             case 'j':
576                 flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
577                 format++;
578                 break;
579             case 'z':
580                 flags |= (sizeof(int) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
581                 format++;
582                 break;
583             default:
584                 break;
585         }
586 
587         // evaluate specifier
588         switch (*format) {
589             case 'd':
590             case 'i':
591             case 'u':
592             case 'x':
593             case 'X':
594             case 'o':
595             case 'b': {
596                 // set the base
597                 unsigned int base;
598                 if (*format == 'x' || *format == 'X') {
599                     base = 16U;
600                 } else if (*format == 'o') {
601                     base = 8U;
602                 } else if (*format == 'b') {
603                     base = 2U;
604                 } else {
605                     base = 10U;
606                     flags &= ~FLAGS_HASH; // no hash for dec format
607                 }
608                 // uppercase
609                 if (*format == 'X') {
610                     flags |= FLAGS_UPPERCASE;
611                 }
612 
613                 // no plus or space flag for u, x, X, o, b
614                 if ((*format != 'i') && (*format != 'd')) {
615                     flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
616                 }
617 
618                 // ignore '0' flag when precision is given
619                 if (flags & FLAGS_PRECISION) {
620                     flags &= ~FLAGS_ZEROPAD;
621                 }
622 
623                 // convert the integer
624                 if ((*format == 'i') || (*format == 'd')) {
625                     // signed
626                     if (flags & FLAGS_LONG_LONG) {
627 #if defined(PRINTF_SUPPORT_LONG_LONG)
628                         const long long value = va_arg(va, long long);
629                         idx = Gd32NtoaLongLong(out, buffer, idx, maxlen,
630                                                (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base,
631                                                precision, width, flags);
632 #endif
633                     } else if (flags & FLAGS_LONG) {
634                         const long value = va_arg(va, long);
635                         idx = Gd32NtoaLong(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value),
636                                            value < 0, base, precision, width, flags);
637                     } else {
638                         const int value = (flags & FLAGS_CHAR)    ? (char)va_arg(va, int)
639                                           : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int)
640                                                                   : va_arg(va, int);
641                         idx = Gd32NtoaLong(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value),
642                                            value < 0, base, precision, width, flags);
643                     }
644                 } else {
645                     // unsigned
646                     if (flags & FLAGS_LONG_LONG) {
647 #if defined(PRINTF_SUPPORT_LONG_LONG)
648                         idx = Gd32NtoaLongLong(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base,
649                                                precision, width, flags);
650 #endif
651                     } else if (flags & FLAGS_LONG) {
652                         idx = Gd32NtoaLong(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision,
653                                            width, flags);
654                     } else {
655                         const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int)
656                                                    : (flags & FLAGS_SHORT)
657                                                        ? (unsigned short int)va_arg(va, unsigned int)
658                                                        : va_arg(va, unsigned int);
659                         idx = Gd32NtoaLong(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
660                     }
661                 }
662                 format++;
663                 break;
664             }
665 #if defined(PRINTF_SUPPORT_FLOAT)
666             case 'f':
667             case 'F':
668                 if (*format == 'F') {
669                     flags |= FLAGS_UPPERCASE;
670                 }
671                 idx = Gd32Ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
672                 format++;
673                 break;
674 #endif // PRINTF_SUPPORT_FLOAT
675             case 'c': {
676                 unsigned int l = 1U;
677                 // pre padding
678                 if (!(flags & FLAGS_LEFT)) {
679                     while (l++ < width) {
680                         out(' ', buffer, idx++, maxlen);
681                     }
682                 }
683                 // char output
684                 out((char)va_arg(va, int), buffer, idx++, maxlen);
685                 // post padding
686                 if (flags & FLAGS_LEFT) {
687                     while (l++ < width) {
688                         out(' ', buffer, idx++, maxlen);
689                     }
690                 }
691                 format++;
692                 break;
693             }
694 
695             case 's': {
696                 const char *p = va_arg(va, char *);
697                 if (!p) {
698                     p = '(null)';
699                 }
700                 unsigned int l = Gd32Strnlen(p, precision ? precision : (int)-1);
701                 // pre padding
702                 if (flags & FLAGS_PRECISION) {
703                     l = (l < precision ? l : precision);
704                 }
705                 if (!(flags & FLAGS_LEFT)) {
706                     while (l++ < width) {
707                         out(' ', buffer, idx++, maxlen);
708                     }
709                 }
710                 // string output
711                 while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
712                     out(*(p++), buffer, idx++, maxlen);
713                 }
714                 // post padding
715                 if (flags & FLAGS_LEFT) {
716                     while (l++ < width) {
717                         out(' ', buffer, idx++, maxlen);
718                     }
719                 }
720                 format++;
721                 break;
722             }
723 
724             case 'p': {
725                 width = sizeof(void *) * 2U;
726                 flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
727 #if defined(PRINTF_SUPPORT_LONG_LONG)
728                 const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
729                 if (is_ll) {
730                     idx = Gd32NtoaLongLong(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void *), false, 16U,
731                                            precision, width, flags);
732                 } else {
733 #endif
734                     idx = Gd32NtoaLong(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void *)), false,
735                                        16U, precision, width, flags);
736 #if defined(PRINTF_SUPPORT_LONG_LONG)
737                 }
738 #endif
739                 format++;
740                 break;
741             }
742 
743             case '%':
744                 out('%', buffer, idx++, maxlen);
745                 format++;
746                 break;
747 
748             default:
749                 out(*format, buffer, idx++, maxlen);
750                 format++;
751                 break;
752         }
753     }
754 
755     // termination
756     out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
757 
758     // return written chars without terminating \0
759     return (int)idx;
760 }
761 
762 #include "cmsis_os2.h"
763 static osMutexId_t g_MuxUart = NULL;
InitUartMutex(void)764 int InitUartMutex(void)
765 {
766     g_MuxUart = osMutexNew(NULL);
767     if (g_MuxUart != NULL) {
768         printf("\ncreat g_MuxUart=%d ok\n", g_MuxUart);
769     }
770 
771     return 0;
772 }
__wrap_printf(const char * format,...)773 int __wrap_printf(const char *format, ...)
774 {
775     va_list va;
776     if (g_MuxUart != NULL) {
777         osMutexAcquire(g_MuxUart, osWaitForever);
778     }
779     va_start(va, format);
780     char buffer[1];
781     const int ret = Gd32Vsnintf(Gd32OutChar, buffer, (int)-1, format, va);
782     va_end(va);
783     if (g_MuxUart != NULL) {
784         osMutexRelease(g_MuxUart);
785     }
786     return ret;
787 }
788 
__wrap_sprintf(char * buffer,const char * format,...)789 int __wrap_sprintf(char *buffer, const char *format, ...)
790 {
791     va_list va;
792     va_start(va, format);
793     const int ret = Gd32Vsnintf(Gd32OutBuffer, buffer, 0x7fffffff, format, va);
794     va_end(va);
795     return ret;
796 }
797 
__wrap_snprintf(char * buffer,int count,const char * format,...)798 int __wrap_snprintf(char *buffer, int count, const char *format, ...)
799 {
800     va_list va;
801     va_start(va, format);
802     const int ret = Gd32Vsnintf(Gd32OutBuffer, buffer, count, format, va);
803     va_end(va);
804     return ret;
805 }
806 
__wrap_vprintf(const char * format,va_list va)807 int __wrap_vprintf(const char *format, va_list va)
808 {
809     char buffer[1];
810     return Gd32Vsnintf(Gd32OutChar, buffer, 0x7fffffff, format, va);
811 }
812 
__wrap_vsnprintf(char * buffer,int count,const char * format,va_list va)813 int __wrap_vsnprintf(char *buffer, int count, const char *format, va_list va)
814 {
815     return Gd32Vsnintf(Gd32OutBuffer, buffer, count, format, va);
816 }
817 
fctprintf(void (* out)(char character,void * arg),void * arg,const char * format,...)818 int fctprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...)
819 {
820     va_list va;
821     va_start(va, format);
822     const out_fct_wrap_type out_fct_wrap = {out, arg};
823     const int ret = Gd32Vsnintf(Gd32OutFct, (char *)(uintptr_t)&out_fct_wrap, (int)-1, format, va);
824     va_end(va);
825     return ret;
826 }
827