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