1 /*
2 * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /******************************************************************************
18 * @file libc_port.c
19 * @brief libc port
20 * @version V1.0
21 * @date 26. Dec 2017
22 ******************************************************************************/
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <limits.h>
31 #include <csi_config.h>
32 #include "stddef.h"
33 #include "wm_config.h"
34 #include "wm_regs.h"
35 /* Minimum and maximum values a `signed int' can hold. */
36 # ifndef __INT_MAX__
37 # define __INT_MAX__ 2147483647
38 # endif
39 # undef INT_MIN
40 # define INT_MIN (-INT_MAX-1)
41 # undef INT_MAX
42 # define INT_MAX __INT_MAX__
43
44 /* Maximum value an `unsigned int' can hold. (Minimum is 0). */
45 # undef UINT_MAX
46 # define UINT_MAX (INT_MAX * 2U + 1)
47
48 # undef SIZE_MAX
49 # define SIZE_MAX (INT_MAX * 2U + 1)
50 #ifndef CHAR_BIT
51 #define CHAR_BIT 8
52 #endif
53
54 static unsigned char printf_port = 0;
get_printf_port(void)55 unsigned char get_printf_port(void)
56 {
57 return printf_port;
58 }
59
set_printf_port(unsigned char port)60 void set_printf_port(unsigned char port)
61 {
62 if (port == 0) {
63 printf_port = 0;
64 } else if (port == 1) {
65 printf_port = 1;
66 } else {
67 printf_port = 0xff;
68 }
69 }
70
sendchar(int ch)71 int sendchar(int ch)
72 {
73 if (printf_port == 0) {
74 if (ch == '\n') {
75 while (tls_reg_read32(HR_UART0_FIFO_STATUS) & 0x3F);
76 tls_reg_write32(HR_UART0_TX_WIN, '\r');
77 }
78 while (tls_reg_read32(HR_UART0_FIFO_STATUS) & 0x3F);
79 tls_reg_write32(HR_UART0_TX_WIN, (char)ch);
80 } else if (printf_port == 1) {
81 if (ch == '\n') {
82 while (tls_reg_read32(HR_UART1_FIFO_STATUS) & 0x3F);
83 tls_reg_write32(HR_UART1_TX_WIN, '\r');
84 }
85 while (tls_reg_read32(HR_UART1_FIFO_STATUS) & 0x3F);
86 tls_reg_write32(HR_UART1_TX_WIN, (char)ch);
87 }
88 return ch;
89 }
90
fputc(int ch,FILE * stream)91 int fputc(int ch, FILE *stream)
92 {
93 (void)stream;
94 sendchar(ch);
95 return 0;
96 }
97
98 #if 1 // defined(__MINILIBC__)
fgetc(FILE * stream)99 int fgetc(FILE *stream)
100 {
101 (void)stream;
102
103 return 0;
104 }
105 #endif
106
107 #if 1 // defined(_NEWLIB_VERSION_H__)
_write_r(void * r,int file,const void * ptr,size_t len)108 int _write_r(void *r, int file, const void *ptr, size_t len)
109 {
110 size_t i;
111 char *p;
112
113 p = (char*) ptr;
114
115 for (i = 0; i < len; i++) {
116 (void)fputc(*p++, r); /* r: ignore warning */
117 }
118 return len;
119 }
120 #endif
121
__ip2str(unsigned char v4v6,unsigned int * inuint,char * outtxt)122 static int __ip2str(unsigned char v4v6, unsigned int *inuint, char *outtxt)
123 {
124 unsigned char j = 0;
125 unsigned char h;
126 unsigned char m;
127 unsigned char l;
128
129 if (4 == v4v6) {
130 for (unsigned char i = 0; i < 4; i++) { // 4:loop cap
131 unsigned char bit = (*inuint >> (8 * i)) & 0xff; // 8:byte alignment
132 h = bit / 100; // 100:byte alignment
133 if (h) {
134 outtxt[j++] = '0' + h;
135 }
136 m = (bit % 100) / 10; // 100:byte alignment, 10:byte alignment
137 if (m) {
138 outtxt[j++] = '0' + m;
139 } else {
140 if (h) {
141 outtxt[j++] = '0';
142 }
143 }
144 l = (bit % 100) % 10; // 100:byte alignment, 10:byte alignment
145 outtxt[j++] = '0' + l;
146 outtxt[j++] = '.';
147 }
148 } else {
149 for (unsigned char k = 0; k < 4; k++) { // 4:loop cap
150 for (unsigned char i = 0; i < 4; i++) { // 4:loop cap
151 m = (*inuint >> (8 * i)) & 0xff; // 8:byte alignment
152 h = m >> 4; // 4:byte alignment
153 l = m & 0xf;
154 if (h > 9) { // 9:byte alignment
155 outtxt[j++] = 'A' + h - 10; // 10:byte alignment
156 } else {
157 outtxt[j++]= '0' + h;
158 }
159 if (l > 9) { // 9:byte alignment
160 outtxt[j++] = 'A' + l - 10; // 10:byte alignment
161 } else {
162 outtxt[j++] = '0' + l;
163 }
164 if ((i % 2) != 0) { // 2:byte alignment
165 outtxt[j++] = ':';
166 }
167 }
168 inuint++;
169 }
170 }
171
172 outtxt[j - 1] = 0;
173 return j - 1;
174 }
175
__mac2str(unsigned char * inchar,char * outtxt)176 static int __mac2str(unsigned char *inchar, char *outtxt)
177 {
178 unsigned int i;
179 for (i = 0; i < 6; i++) { // 6:loop cap
180 unsigned char hbit = (*(inchar + i) & 0xf0) >> 4; // 4:byte alignment
181 unsigned char lbit = *(inchar + i) & 0x0f;
182 if (hbit > 9) { // 9:byte alignment
183 outtxt[3 * i] = 'A' + hbit - 10; // 10:byte alignment, 3:byte alignment
184 } else {
185 outtxt[3 * i]= '0' + hbit; // 3:byte alignment
186 }
187 if (lbit > 9) { // 9:byte alignment
188 outtxt[3 * i + 1] = 'A' + lbit - 10; // 10:byte alignment, 3:byte alignment
189 } else {
190 outtxt[3 * i + 1] = '0' + lbit; // 3:byte alignment
191 }
192 outtxt[3 * i + 2] = '-'; // 2:byte alignment, 3:byte alignment
193 }
194
195 outtxt[3 * (i - 1) + 2] = 0; // 2:byte alignment, 3:byte alignment
196
197 return 3 * (i - 1) + 2; // 2:byte alignment, 3:byte alignment
198 }
199
digitval(int ch)200 static inline int digitval(int ch)
201 {
202 if (ch >= '0' && ch <= '9') {
203 return ch-'0';
204 } else if (ch >= 'A' && ch <= 'Z') {
205 return ch-'A' + 10; // 10:byte alignment
206 } else if (ch >= 'a' && ch <= 'z') {
207 return ch-'a' + 10; // 10:byte alignment
208 } else {
209 return -1;
210 }
211 }
212
strntoumax(const char * nptr,char ** endptr,int base,size_t n)213 uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n)
214 {
215 int minus = 0;
216 uintmax_t v = 0;
217 int d;
218 int base_tmp = base;
219 size_t n_tmp = n;
220 const char *nptr_tmp = nptr;
221
222 while (n_tmp && isspace((unsigned char)*nptr_tmp)) {
223 nptr_tmp++;
224 n_tmp--;
225 }
226
227 /* Single optional + or - */
228 if (n_tmp && *nptr_tmp == '-') {
229 minus = 1;
230 nptr_tmp++;
231 n_tmp--;
232 } else if (n_tmp && *nptr_tmp == '+') {
233 nptr_tmp++;
234 }
235
236 if (base_tmp == 0) {
237 if (n_tmp >= 2 && nptr_tmp[0] == '0' && // 2:byte alignment
238 (nptr_tmp[1] == 'x' || nptr_tmp[1] == 'X')) {
239 n_tmp -= 2; // 2:byte alignment
240 nptr_tmp += 2; // 2:byte alignment
241 base_tmp = 16; // 16:byte alignment
242 } else if (n_tmp >= 1 && nptr_tmp[0] == '0') {
243 n_tmp--;
244 nptr_tmp++;
245 base_tmp = 8; // 8:byte alignment
246 } else {
247 base_tmp = 10; // 10:byte alignment
248 }
249 } else if (base_tmp == 16) { // 16:byte alignment
250 if (n_tmp >= 2 && nptr_tmp[0] == '0' &&
251 (nptr_tmp[1] == 'x' || nptr_tmp[1] == 'X')) {
252 n_tmp -= 2; // 2:byte alignment
253 nptr_tmp += 2; // 2:byte alignment
254 }
255 }
256
257 while (n_tmp && (d = digitval(*nptr_tmp)) >= 0 && d < base_tmp) {
258 v = v * base_tmp + d;
259 n_tmp--;
260 nptr_tmp++;
261 }
262
263 if (endptr) {
264 *endptr = (char *)nptr_tmp;
265 }
266
267 return minus ? -v : v;
268 }
269
270 #ifndef LONG_BIT
271 #define LONG_BIT (CHAR_BIT*sizeof(long))
272 #endif
273
274 enum flags {
275 FL_SPLAT = 0x01, /* Drop the value, do not assign */
276 FL_INV = 0x02, /* Character-set with inverse */
277 FL_WIDTH = 0x04, /* Field width specified */
278 FL_MINUS = 0x08, /* Negative number */
279 };
280
281 enum ranks {
282 rank_char = -2,
283 rank_short = -1,
284 rank_int = 0,
285 rank_long = 1,
286 rank_longlong = 2,
287 rank_ptr = INT_MAX /* Special value used for pointers */
288 };
289
290 #define MIN_RANK rank_char
291 #define MAX_RANK rank_longlong
292
293 #define INTMAX_RANK rank_longlong
294 #define SIZE_T_RANK rank_long
295 #define PTRDIFF_T_RANK rank_long
296
297 enum bail {
298 bail_none = 0, /* No error condition */
299 bail_eof, /* Hit EOF */
300 bail_err /* Conversion mismatch */
301 };
302
skipspace(const char * p)303 static inline const char *skipspace(const char *p)
304 {
305 const char *p_tmp = p;
306 while (isspace((unsigned char)*p_tmp)) {
307 p_tmp++;
308 }
309 return p_tmp;
310 }
311
312 #undef set_bit
set_bit(unsigned long * bitmap,unsigned int bit)313 static inline void set_bit(unsigned long *bitmap, unsigned int bit)
314 {
315 bitmap[bit/LONG_BIT] |= 1UL << (bit%LONG_BIT);
316 }
317
318 #undef test_bit
test_bit(unsigned long * bitmap,unsigned int bit)319 static inline int test_bit(unsigned long *bitmap, unsigned int bit)
320 {
321 return (int)(bitmap[bit/LONG_BIT] >> (bit%LONG_BIT)) & 1;
322 }
323
wm_vsscanf(const char * buffer,const char * format,va_list ap)324 int wm_vsscanf(const char *buffer, const char *format, va_list ap)
325 {
326 const char *p = format;
327 char ch;
328 const char *q = buffer;
329 const char *qq;
330 uintmax_t val = 0;
331 int rank = rank_int; /* Default rank */
332 unsigned int width = UINT_MAX;
333 int base;
334 enum flags flags = 0;
335 enum {
336 st_normal, /* Ground state */
337 st_flags, /* Special flags */
338 st_width, /* Field width */
339 st_modifiers, /* Length or conversion modifiers */
340 st_match_init, /* Initial state of %[ sequence */
341 st_match, /* Main state of %[ sequence */
342 st_match_range, /* After - in a %[ sequence */
343 } state = st_normal;
344 char *sarg = NULL; /* %s %c or %[ string argument */
345 enum bail bail = bail_none;
346 int sign = 0;
347 int converted = 0; /* Successful conversions */
348 unsigned long matchmap[((1 << CHAR_BIT)+(LONG_BIT-1))/LONG_BIT];
349 int matchinv = 0; /* Is match map inverted? */
350 unsigned char range_start = 0;
351
352 while ((ch = *p++) && !bail) {
353 switch (state) {
354 case st_normal:
355 if (ch == '%') {
356 state = st_flags;
357 flags = 0;
358 rank = rank_int;
359 width = UINT_MAX;
360 } else if (isspace((unsigned char)ch)) {
361 q = skipspace(q);
362 } else {
363 if (*q == ch) {
364 q++;
365 } else {
366 bail = bail_err; /* Match failure */
367 }
368 }
369 break;
370
371 case st_flags:
372 switch (ch) {
373 case '*':
374 flags |= FL_SPLAT;
375 break;
376 case '0' ... '9':
377 width = (ch-'0');
378 state = st_width;
379 flags |= FL_WIDTH;
380 break;
381 default:
382 state = st_modifiers;
383 p--; /* Process this character again */
384 break;
385 }
386 break;
387
388 case st_width:
389 if (ch >= '0' && ch <= '9') {
390 width = width*10+(ch-'0');
391 } else {
392 state = st_modifiers;
393 p--; /* Process this character again */
394 }
395 break;
396 case st_modifiers:
397 switch (ch) {
398 /* Length modifiers - nonterminal sequences */
399 case 'h':
400 rank--; /* Shorter rank */
401 break;
402 case 'l':
403 rank++; /* Longer rank */
404 break;
405 case 'j':
406 rank = INTMAX_RANK;
407 break;
408 case 'z':
409 rank = SIZE_T_RANK;
410 break;
411 case 't':
412 rank = PTRDIFF_T_RANK;
413 break;
414 case 'L':
415 case 'q':
416 rank = rank_longlong; /* long double/long long */
417 break;
418 default:
419 /* Output modifiers - terminal sequences */
420 state = st_normal; /* Next state will be normal */
421 if (rank < MIN_RANK) { /* Canonicalize rank */
422 rank = MIN_RANK;
423 } else if (rank > MAX_RANK) {
424 rank = MAX_RANK;
425 }
426
427 switch (ch) {
428 case 'P': /* Upper case pointer */
429 case 'p': /* Pointer */
430 rank = rank_ptr;
431 base = 0; sign = 0;
432 goto scan_int;
433
434 case 'i': /* Base-independent integer */
435 base = 0; sign = 1;
436 goto scan_int;
437
438 case 'd': /* Decimal integer */
439 base = 10; sign = 1;
440 goto scan_int;
441
442 case 'o': /* Octal integer */
443 base = 8; sign = 0;
444 goto scan_int;
445
446 case 'u': /* Unsigned decimal integer */
447 base = 10; sign = 0;
448 goto scan_int;
449
450 case 'x': /* Hexadecimal integer */
451 case 'X':
452 base = 16; sign = 0;
453 goto scan_int;
454
455 case 'n': /* Number of characters consumed */
456 val = (q-buffer);
457 goto set_integer;
458
459 scan_int:
460 q = skipspace(q);
461 if (!*q) {
462 bail = bail_eof;
463 break;
464 }
465 val = strntoumax(q, (char **)&qq, base, width);
466 if (qq == q) {
467 bail = bail_err;
468 break;
469 }
470 q = qq;
471 converted++;
472 /* fall through */
473
474 set_integer:
475 if (!(flags & FL_SPLAT)) {
476 switch (rank) {
477 case rank_char:
478 *va_arg(ap, unsigned char *) = (unsigned char)val;
479 break;
480 case rank_short:
481 *va_arg(ap, unsigned short *) = (unsigned short)val;
482 break;
483 case rank_int:
484 *va_arg(ap, unsigned int *) = (unsigned int)val;
485 break;
486 case rank_long:
487 *va_arg(ap, unsigned long *) = (unsigned long)val;
488 break;
489 case rank_longlong:
490 *va_arg(ap, unsigned long long *) = (unsigned long long)val;
491 break;
492 case rank_ptr:
493 *va_arg(ap, void **) = (void *)(uintptr_t)val;
494 break;
495 default:
496 break;
497 }
498 }
499 break;
500
501 case 'c': /* Character */
502 width = (flags & FL_WIDTH) ? width : 1; /* Default width == 1 */
503 sarg = va_arg(ap, char *);
504 while (width--) {
505 if (!*q) {
506 bail = bail_eof;
507 break;
508 }
509 *sarg++ = *q++;
510 }
511 if (!bail) {
512 converted++;
513 }
514 break;
515
516 case 's': /* String */
517 {
518 char *sp;
519 sp = sarg = va_arg(ap, char *);
520 while (width-- && *q && !isspace((unsigned char)*q)) {
521 *sp++ = *q++;
522 }
523 if (sarg != sp) {
524 *sp = '\0'; /* Terminate output */
525 converted++;
526 } else {
527 bail = bail_eof;
528 }
529 }
530 break;
531
532 case 'f': /* float */
533 {
534 float *vp = (float *) va_arg(ap, float *);
535 const char *vpq = q;
536 *vp = strtof(vpq, (char **)&q);
537 if (vpq != q) {
538 converted++;
539 } else {
540 bail = bail_err;
541 }
542 }
543 break;
544 case 'g': /* double */
545 {
546 double *vp = (double *) va_arg(ap, double *);
547 const char *vpq = q;
548 *vp = strtod(vpq, (char **)&q);
549 if (vpq != q) {
550 converted++;
551 } else {
552 bail = bail_err;
553 }
554 }
555 break;
556
557 case '[': /* Character range */
558 sarg = va_arg(ap, char *);
559 state = st_match_init;
560 matchinv = 0;
561 memset_s(matchmap, sizeof(matchmap), 0, sizeof matchmap);
562 break;
563
564 case '%': /* %% sequence */
565 if (*q == '%') {
566 q++;
567 } else {
568 bail = bail_err;
569 }
570 break;
571
572 default: /* Anything else */
573 bail = bail_err; /* Unknown sequence */
574 break;
575 }
576 }
577 break;
578
579 case st_match_init: /* Initial state for %[ match */
580 if (ch == '^' && !(flags & FL_INV)) {
581 matchinv = 1;
582 } else {
583 set_bit(matchmap, (unsigned char)ch);
584 state = st_match;
585 }
586 break;
587
588 case st_match: /* Main state for %[ match */
589 if (ch == ']') {
590 goto match_run;
591 } else if (ch == '-') {
592 range_start = (unsigned char)ch;
593 state = st_match_range;
594 } else {
595 set_bit(matchmap, (unsigned char)ch);
596 }
597 break;
598
599 case st_match_range: /* %[ match after - */
600 if (ch == ']') {
601 set_bit(matchmap, (unsigned char)'-'); /* - was last character */
602 goto match_run;
603 } else {
604 int i;
605 for (i = range_start ; i < (unsigned char)ch ; i++) {
606 set_bit(matchmap, i);
607 }
608 state = st_match;
609 }
610 break;
611
612 match_run: /* Match expression finished */
613 qq = q;
614 while (width && *q && (test_bit(matchmap, (unsigned char)*q)^matchinv)) {
615 *sarg++ = *q++;
616 }
617 if (q != qq) {
618 *sarg = '\0';
619 converted++;
620 } else {
621 bail = *q ? bail_err : bail_eof;
622 }
623 break;
624 }
625 }
626
627 if (bail == bail_eof && !converted) {
628 converted = -1; /* Return EOF (-1) */
629 }
630
631 return converted;
632 }
633
634 #define PRINTF_NTOA_BUFFER_SIZE 32U
635 #define PRINTF_FTOA_BUFFER_SIZE 32U
636 #define PRINTF_SUPPORT_FLOAT
637 #define PRINTF_SUPPORT_EXPONENTIAL
638 #define PRINTF_DEFAULT_FLOAT_PRECISION 6U
639 #define PRINTF_MAX_FLOAT 1e9
640 #define PRINTF_SUPPORT_LONG_LONG
641 #define PRINTF_SUPPORT_PTRDIFF_T
642
643 // import float.h for DBL_MAX
644 #if defined(PRINTF_SUPPORT_FLOAT)
645 #include <float.h>
646 #endif
647
648 // internal flag definitions
649 #define FLAGS_ZEROPAD (1U << 0U)
650 #define FLAGS_LEFT (1U << 1U)
651 #define FLAGS_PLUS (1U << 2U)
652 #define FLAGS_SPACE (1U << 3U)
653 #define FLAGS_HASH (1U << 4U)
654 #define FLAGS_UPPERCASE (1U << 5U)
655 #define FLAGS_CHAR (1U << 6U)
656 #define FLAGS_SHORT (1U << 7U)
657 #define FLAGS_LONG (1U << 8U)
658 #define FLAGS_LONG_LONG (1U << 9U)
659 #define FLAGS_PRECISION (1U << 10U)
660 #define FLAGS_ADAPT_EXP (1U << 11U)
661
662 // output function type
663 typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
664
665 // internal buffer output
_out_buffer(char character,void * buffer,size_t idx,size_t maxlen)666 static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
667 {
668 if (idx < maxlen) {
669 ((char*)buffer)[idx] = character;
670 }
671 }
672
_out_uart(char character,void * buffer,size_t idx,size_t maxlen)673 static inline void _out_uart(char character, void* buffer, size_t idx, size_t maxlen)
674 {
675 _write_r(NULL, 0, &character, 1);
676 }
677
678 // internal null output
_out_null(char character,void * buffer,size_t idx,size_t maxlen)679 static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
680 {
681 (void)character;
682 (void)buffer;
683 (void)idx;
684 (void)maxlen;
685 }
686
687 // internal secure strlen
688 // \return The length of the string (excluding the terminating 0) limited by 'maxsize'
_strnlen_s(const char * str,size_t maxsize)689 static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
690 {
691 const char* s;
692 size_t maxsize_tmp = maxsize;
693 for (s = str; *s && maxsize_tmp--; ++s) {
694 }
695 return (unsigned int)(s - str);
696 }
697
698 // internal test if char is a digit (0-9)
699 // \return true if char is a digit
_is_digit(char ch)700 static inline bool _is_digit(char ch)
701 {
702 return (ch >= '0') && (ch <= '9');
703 }
704
705 // internal ASCII string to unsigned int conversion
_atoi(const char ** str)706 static unsigned int _atoi(const char** str)
707 {
708 unsigned int i = 0U;
709 while (_is_digit(**str)) {
710 i = i * 10U + (unsigned int)(*((*str)++) - '0');
711 }
712 return i;
713 }
714
715 // output the specified string in reverse, taking care of any zero-padding
_out_rev(out_fct_type out,char * buffer,size_t idx,size_t maxlen,const char * buf,size_t len,unsigned int width,unsigned int flags)716 static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
717 const char* buf, size_t len, unsigned int width, unsigned int flags)
718 {
719 const size_t start_idx = idx;
720 size_t idx_tmp = idx;
721 size_t len_tmp = len;
722
723 // pad spaces up to given width
724 if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
725 for (size_t i = len_tmp; i < width; i++) {
726 out(' ', buffer, idx_tmp++, maxlen);
727 }
728 }
729
730 // reverse string
731 while (len_tmp) {
732 out(buf[--len_tmp], buffer, idx_tmp++, maxlen);
733 }
734
735 // append pad spaces up to given width
736 if (flags & FLAGS_LEFT) {
737 while (idx_tmp - start_idx < width) {
738 out(' ', buffer, idx_tmp++, maxlen);
739 }
740 }
741
742 return idx_tmp;
743 }
744
745 // internal itoa format
_ntoa_format(out_fct_type out,char * buffer,size_t idx,size_t maxlen,char * buf,size_t len,bool negative,unsigned int base,unsigned int prec,unsigned int width,unsigned int flags)746 static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
747 char* buf, size_t len, bool negative, unsigned int base,
748 unsigned int prec, unsigned int width, unsigned int flags)
749 {
750 size_t len_tmp = len;
751 unsigned int width_tmp = width;
752 // pad leading zeros
753 if (!(flags & FLAGS_LEFT)) {
754 if (width_tmp && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
755 width_tmp--;
756 }
757 while ((len_tmp < prec) && (len_tmp < PRINTF_NTOA_BUFFER_SIZE)) {
758 buf[len_tmp++] = '0';
759 }
760 while ((flags & FLAGS_ZEROPAD) && (len_tmp < width_tmp) && (len_tmp < PRINTF_NTOA_BUFFER_SIZE)) {
761 buf[len_tmp++] = '0';
762 }
763 }
764
765 // handle hash
766 if (flags & FLAGS_HASH) {
767 if (!(flags & FLAGS_PRECISION) && len_tmp && ((len_tmp == prec) || (len_tmp == width_tmp))) {
768 len_tmp--;
769 if (len_tmp && (base == 16U)) {
770 len_tmp--;
771 }
772 }
773 if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len_tmp < PRINTF_NTOA_BUFFER_SIZE)) {
774 buf[len_tmp++] = 'x';
775 } else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len_tmp < PRINTF_NTOA_BUFFER_SIZE)) {
776 buf[len_tmp++] = 'X';
777 } else if ((base == 2U) && (len_tmp < PRINTF_NTOA_BUFFER_SIZE)) {
778 buf[len_tmp++] = 'b';
779 }
780 if (len_tmp < PRINTF_NTOA_BUFFER_SIZE) {
781 buf[len_tmp++] = '0';
782 }
783 }
784
785 if (len_tmp < PRINTF_NTOA_BUFFER_SIZE) {
786 if (negative) {
787 buf[len_tmp++] = '-';
788 } else if (flags & FLAGS_PLUS) {
789 buf[len_tmp++] = '+'; // ignore the space if the '+' exists
790 } else if (flags & FLAGS_SPACE) {
791 buf[len_tmp++] = ' ';
792 }
793 }
794
795 return _out_rev(out, buffer, idx, maxlen, buf, len_tmp, width_tmp, flags);
796 }
797
798 // internal itoa for 'long' type
_ntoa_long(out_fct_type out,char * buffer,size_t idx,size_t maxlen,unsigned long value,bool negative,unsigned long base,unsigned int prec,unsigned int width,unsigned int flags)799 static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
800 unsigned long value, bool negative, unsigned long base,
801 unsigned int prec, unsigned int width, unsigned int flags)
802 {
803 unsigned int flags_tmp = flags;
804 unsigned long value_tmp = value;
805 char buf[PRINTF_NTOA_BUFFER_SIZE];
806 size_t len = 0U;
807
808 // no hash for 0 values
809 if (!value_tmp) {
810 flags_tmp &= ~FLAGS_HASH;
811 }
812
813 // write if precision != 0 and value is != 0
814 if (!(flags_tmp & FLAGS_PRECISION) || value_tmp) {
815 do {
816 if (base == 0) {
817 }
818 const char digit = (char)(value_tmp % base);
819 buf[len++] = digit < 10 ? '0' + digit : ((flags_tmp & FLAGS_UPPERCASE) ? 'A' : 'a') + digit - 10;
820 if (value_tmp == 0) {
821 }
822 value_tmp /= base;
823 } while (value_tmp && (len < PRINTF_NTOA_BUFFER_SIZE));
824 }
825
826 return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags_tmp);
827 }
828
829 // internal itoa for 'long long' type
830 #if defined(PRINTF_SUPPORT_LONG_LONG)
_ntoa_long_long(out_fct_type out,char * buffer,size_t idx,size_t maxlen,unsigned long long value,bool negative,unsigned long long base,unsigned int prec,unsigned int width,unsigned int flags)831 static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
832 unsigned long long value, bool negative, unsigned long long base,
833 unsigned int prec, unsigned int width, unsigned int flags)
834 {
835 unsigned int flags_tmp = flags;
836 unsigned long value_tmp = value;
837 char buf[PRINTF_NTOA_BUFFER_SIZE];
838 size_t len = 0U;
839
840 // no hash for 0 values
841 if (!value_tmp) {
842 flags_tmp &= ~FLAGS_HASH;
843 }
844
845 // write if precision != 0 and value is != 0
846 if (!(flags_tmp & FLAGS_PRECISION) || value_tmp) {
847 do {
848 if (base == 0) {
849 }
850 const char digit = (char)(value_tmp % base);
851 buf[len++] = (digit < 10) ? ('0' + digit) : (((flags_tmp & FLAGS_UPPERCASE) ? 'A' : 'a') + digit - 10);
852 if (value_tmp == 0) {
853 }
854 value_tmp /= base;
855 } while (value_tmp && (len < PRINTF_NTOA_BUFFER_SIZE));
856 }
857
858 return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags_tmp);
859 }
860 #endif // PRINTF_SUPPORT_LONG_LONG
861
862 #if defined(PRINTF_SUPPORT_FLOAT)
863
864 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
865 // forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
866 static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
867 double value, unsigned int prec, unsigned int width, unsigned int flags);
868 #endif
869
870 // internal ftoa for fixed decimal floating point
_ftoa(out_fct_type out,char * buffer,size_t idx,size_t maxlen,double value,unsigned int prec,unsigned int width,unsigned int flags)871 static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
872 double value, unsigned int prec, unsigned int width, unsigned int flags)
873 {
874 unsigned int prec_tmp = prec;
875 char buf[PRINTF_FTOA_BUFFER_SIZE];
876 size_t len = 0U;
877 double diff = 0.0;
878 double value_tmp = value;
879 unsigned int width_tmp = width;
880
881 // powers of 10
882 static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
883
884 // test for special values
885 if (value_tmp != value_tmp) {
886 return _out_rev(out, buffer, idx, maxlen, "nan", 3, width_tmp, flags); // 3:len
887 }
888 if (value_tmp < -DBL_MAX) {
889 return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width_tmp, flags); // 4:len
890 }
891 if (value_tmp > DBL_MAX) {
892 return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni",
893 (flags & FLAGS_PLUS) ? 4U : 3U, width_tmp, flags);
894 }
895
896 // test for very large values
897 // standard printf behavior is to print EVERY whole number digit --
898 // which could be 100s of characters overflowing your buffers == bad
899 if ((value_tmp > PRINTF_MAX_FLOAT) || (value_tmp < -PRINTF_MAX_FLOAT)) {
900 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
901 return _etoa(out, buffer, idx, maxlen, value_tmp, prec_tmp, width_tmp, flags);
902 #else
903 return 0U;
904 #endif
905 }
906 // test for negative
907 bool negative = false;
908 if (value_tmp < 0) {
909 negative = true;
910 value_tmp = 0 - value_tmp;
911 }
912
913 // set default precision, if not set explicitly
914 if (!(flags & FLAGS_PRECISION)) {
915 prec_tmp = PRINTF_DEFAULT_FLOAT_PRECISION;
916 }
917 // limit precision to 9, cause a prec >= 10 can lead to overflow errors
918 while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec_tmp > 9U)) {
919 buf[len++] = '0';
920 prec_tmp--;
921 }
922
923 int whole = (int)value_tmp;
924 double tmp = (value_tmp - whole) * pow10[prec_tmp];
925 unsigned long frac = (unsigned long)tmp;
926 diff = tmp - frac;
927
928 if (diff > 0.5) {
929 ++frac;
930 // handle rollover, e.g. case 0.99 with prec 1 is 1.0
931 if (frac >= pow10[prec_tmp]) {
932 frac = 0;
933 ++whole;
934 }
935 } else if (diff < 0.5) {
936 } else if ((frac == 0U) || (frac & 1U)) {
937 // if halfway, round up if odd OR if last digit is 0
938 ++frac;
939 }
940
941 if (prec_tmp == 0U) {
942 diff = value_tmp - (double)whole;
943 if ((diff > 0.5) && (whole & 1)) {
944 // exactly 0.5 and ODD, then round up
945 // 1.5 -> 2, but 2.5 -> 2
946 ++whole;
947 }
948 } else {
949 unsigned int count = prec_tmp;
950 // now do fractional part, as an unsigned number
951 while (len < PRINTF_FTOA_BUFFER_SIZE) {
952 --count;
953 buf[len++] = (char)(48U + (frac % 10U));
954 if (!(frac /= 10U)) {
955 break;
956 }
957 }
958 // add extra 0s
959 while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
960 buf[len++] = '0';
961 }
962 if (len < PRINTF_FTOA_BUFFER_SIZE) {
963 // add decimal
964 buf[len++] = '.';
965 }
966 }
967
968 // do whole part, number is reversed
969 while (len < PRINTF_FTOA_BUFFER_SIZE) {
970 buf[len++] = (char)(48 + (whole % 10));
971 if (!(whole /= 10)) {
972 break;
973 }
974 }
975
976 // pad leading zeros
977 if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
978 if (width_tmp && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
979 width_tmp--;
980 }
981 while ((len < width_tmp) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
982 buf[len++] = '0';
983 }
984 }
985
986 if (len < PRINTF_FTOA_BUFFER_SIZE) {
987 if (negative) {
988 buf[len++] = '-';
989 } else if (flags & FLAGS_PLUS) {
990 buf[len++] = '+'; // ignore the space if the '+' exists
991 } else if (flags & FLAGS_SPACE) {
992 buf[len++] = ' ';
993 }
994 }
995
996 return _out_rev(out, buffer, idx, maxlen, buf, len, width_tmp, flags);
997 }
998
999 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
1000 // internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
_etoa(out_fct_type out,char * buffer,size_t idx,size_t maxlen,double value,unsigned int prec,unsigned int width,unsigned int flags)1001 static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value,
1002 unsigned int prec, unsigned int width, unsigned int flags)
1003 {
1004 unsigned int prec_tmp = prec;
1005 double value_tmp = value;
1006 unsigned int flags_tmp = flags;
1007 size_t idx_tmp = idx;
1008 char* buffer_tmp = buffer;
1009 // check for NaN and special values
1010 if ((value_tmp != value_tmp) || (value_tmp > DBL_MAX) || (value_tmp < -DBL_MAX)) {
1011 return _ftoa(out, buffer_tmp, idx_tmp, maxlen, value_tmp, prec_tmp, width, flags_tmp);
1012 }
1013
1014 // determine the sign
1015 const bool negative = value_tmp < 0;
1016 if (negative) {
1017 value_tmp = -value_tmp;
1018 }
1019
1020 // default precision
1021 if (!(flags_tmp & FLAGS_PRECISION)) {
1022 prec_tmp = PRINTF_DEFAULT_FLOAT_PRECISION;
1023 }
1024
1025 // determine the decimal exponent
1026 // based on the algorithm by David Gay (https:// www.ampl.com/netlib/fp/dtoa.c)
1027 union {
1028 uint64_t U;
1029 double F;
1030 } conv;
1031
1032 conv.F = value_tmp;
1033 int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
1034 conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
1035 // now approximate log10 from the log2 integer part and an expansion of ln around 1.5
1036 int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
1037 // now we want to compute 10^expval but we want to be sure it won't overflow
1038 exp2 = (int)(expval * 3.321928094887362 + 0.5);
1039 const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
1040 const double z2 = z * z;
1041 conv.U = (uint64_t)(exp2 + 1023) << 52U;
1042 /* compute exp(z) using continued fractions,
1043 * see https:// en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
1044 */
1045 conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + // 2:byte alignment, 6:byte alignment
1046 (z2 / (10 + z2 / 14))))); // 10:byte alignment, 14:byte alignment
1047 // correct for rounding errors
1048 if (value_tmp < conv.F) {
1049 expval--;
1050 conv.F /= 10; // 10:byte alignment
1051 }
1052
1053 // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
1054 unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
1055
1056 // in "%g" mode, "prec" is the number of *significant figures* not decimals
1057 if (flags_tmp & FLAGS_ADAPT_EXP) {
1058 // do we want to fall-back to "%f" mode?
1059 if ((value_tmp >= 1e-4) && (value_tmp < 1e6)) {
1060 if ((int)prec_tmp > expval) {
1061 prec_tmp = (unsigned)((int)prec_tmp - expval - 1);
1062 } else {
1063 prec_tmp = 0;
1064 }
1065 flags_tmp |= FLAGS_PRECISION; // make sure _ftoa respects precision
1066 // no characters in exponent
1067 minwidth = 0U;
1068 expval = 0;
1069 } else {
1070 // we use one sigfig for the whole part
1071 if ((prec_tmp > 0) && (flags_tmp & FLAGS_PRECISION)) {
1072 --prec_tmp;
1073 }
1074 }
1075 }
1076
1077 // will everything fit?
1078 unsigned int fwidth = width;
1079 if (width > minwidth) {
1080 // we didn't fall-back so subtract the characters required for the exponent
1081 fwidth -= minwidth;
1082 } else {
1083 // not enough characters, so go back to default sizing
1084 fwidth = 0U;
1085 }
1086 if ((flags_tmp & FLAGS_LEFT) && minwidth) {
1087 // if we're padding on the right, DON'T pad the floating part
1088 fwidth = 0U;
1089 }
1090
1091 // rescale the float value
1092 if (expval) {
1093 value_tmp /= conv.F;
1094 }
1095
1096 // output the floating part
1097 const size_t start_idx = idx_tmp;
1098 idx_tmp = _ftoa(out, buffer_tmp, idx_tmp, maxlen,
1099 negative ? -value_tmp : value_tmp, prec_tmp, fwidth, flags_tmp & ~FLAGS_ADAPT_EXP);
1100
1101 // output the exponent part
1102 if (!prec_tmp && minwidth) {
1103 // output the exponential symbol
1104 out((flags_tmp & FLAGS_UPPERCASE) ? 'E' : 'e', buffer_tmp, idx_tmp++, maxlen);
1105 // output the exponent value
1106 idx_tmp = _ntoa_long(out, buffer_tmp, idx_tmp, maxlen, (expval < 0) ? -expval : expval,
1107 expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
1108 // might need to right-pad spaces
1109 if (flags_tmp & FLAGS_LEFT) {
1110 while (idx_tmp - start_idx < width) {
1111 out(' ', buffer_tmp, idx_tmp++, maxlen);
1112 }
1113 }
1114 }
1115 return idx_tmp;
1116 }
1117 #endif // PRINTF_SUPPORT_EXPONENTIAL
1118 #endif // PRINTF_SUPPORT_FLOAT
1119
1120 // internal vsnprintf
_vsnprintf(out_fct_type out,char * buffer,const size_t maxlen,const char * format,va_list va)1121 static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
1122 {
1123 unsigned int flags, width, precision, n;
1124 size_t idx = 0U;
1125 out_fct_type out_tmp = out;
1126 const char* format_tmp = format;
1127
1128 if (!buffer) {
1129 // use null output function
1130 out_tmp = _out_null;
1131 }
1132
1133 while (*format_tmp) {
1134 // format specifier? %[flags][width][.precision][length]
1135 if (*format_tmp != '%') {
1136 // no
1137 out_tmp(*format_tmp, buffer, idx++, maxlen);
1138 format_tmp++;
1139 continue;
1140 } else {
1141 // yes, evaluate it
1142 format_tmp++;
1143 }
1144
1145 // evaluate flags
1146 flags = 0U;
1147 do {
1148 switch (*format_tmp) {
1149 case '0': flags |= FLAGS_ZEROPAD; format_tmp++; n = 1U; break;
1150 case '-': flags |= FLAGS_LEFT; format_tmp++; n = 1U; break;
1151 case '+': flags |= FLAGS_PLUS; format_tmp++; n = 1U; break;
1152 case ' ': flags |= FLAGS_SPACE; format_tmp++; n = 1U; break;
1153 case '#': flags |= FLAGS_HASH; format_tmp++; n = 1U; break;
1154 default : n = 0U; break;
1155 }
1156 } while (n);
1157
1158 // evaluate width field
1159 width = 0U;
1160 if (_is_digit(*format_tmp)) {
1161 width = _atoi(&format_tmp);
1162 } else if (*format_tmp == '*') {
1163 const int w = va_arg(va, int);
1164 if (w < 0) {
1165 flags |= FLAGS_LEFT; // reverse padding
1166 width = (unsigned int)-w;
1167 } else {
1168 width = (unsigned int)w;
1169 }
1170 format_tmp++;
1171 }
1172
1173 // evaluate precision field
1174 precision = 0U;
1175 if (*format_tmp == '.') {
1176 flags |= FLAGS_PRECISION;
1177 format_tmp++;
1178 if (_is_digit(*format_tmp)) {
1179 precision = _atoi(&format_tmp);
1180 } else if (*format_tmp == '*') {
1181 const int prec = (int)va_arg(va, int);
1182 precision = prec > 0 ? (unsigned int)prec : 0U;
1183 format_tmp++;
1184 }
1185 }
1186
1187 // evaluate length field
1188 switch (*format_tmp) {
1189 case 'l' :
1190 flags |= FLAGS_LONG;
1191 format_tmp++;
1192 if (*format_tmp == 'l') {
1193 flags |= FLAGS_LONG_LONG;
1194 format_tmp++;
1195 }
1196 break;
1197 case 'h' :
1198 flags |= FLAGS_SHORT;
1199 format_tmp++;
1200 if (*format_tmp == 'h') {
1201 flags |= FLAGS_CHAR;
1202 format_tmp++;
1203 }
1204 break;
1205 #if defined(PRINTF_SUPPORT_PTRDIFF_T)
1206 case 't' :
1207 flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
1208 format_tmp++;
1209 break;
1210 #endif
1211 case 'j' :
1212 flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
1213 format_tmp++;
1214 break;
1215 case 'z' :
1216 flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
1217 format_tmp++;
1218 break;
1219 default :
1220 break;
1221 }
1222
1223 // evaluate specifier
1224 switch (*format_tmp) {
1225 case 'd' :
1226 case 'i' :
1227 case 'u' :
1228 case 'x' :
1229 case 'X' :
1230 case 'o' :
1231 case 'b' : {
1232 // set the base
1233 unsigned int base;
1234 if (*format_tmp == 'x' || *format_tmp == 'X') {
1235 base = 16U;
1236 } else if (*format_tmp == 'o') {
1237 base = 8U;
1238 } else if (*format_tmp == 'b') {
1239 base = 2U;
1240 } else {
1241 base = 10U;
1242 flags &= ~FLAGS_HASH; // no hash for dec format
1243 }
1244 // uppercase
1245 if (*format_tmp == 'X') {
1246 flags |= FLAGS_UPPERCASE;
1247 }
1248
1249 // no plus or space flag for u, x, X, o, b
1250 if ((*format_tmp != 'i') && (*format_tmp != 'd')) {
1251 flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
1252 }
1253
1254 // ignore '0' flag when precision is given
1255 if (flags & FLAGS_PRECISION) {
1256 flags &= ~FLAGS_ZEROPAD;
1257 }
1258
1259 // convert the integer
1260 if ((*format_tmp == 'i') || (*format_tmp == 'd')) {
1261 // signed
1262 if (flags & FLAGS_LONG_LONG) {
1263 #if defined(PRINTF_SUPPORT_LONG_LONG)
1264 const long long value = va_arg(va, long long);
1265 idx = _ntoa_long_long(out_tmp, buffer, idx, maxlen,
1266 (unsigned long long)(value > 0 ? value : 0 - value),
1267 value < 0, base, precision, width, flags);
1268 #endif
1269 } else if (flags & FLAGS_LONG) {
1270 const long value = va_arg(va, long);
1271 idx = _ntoa_long(out_tmp, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value),
1272 value < 0, base, precision, width, flags);
1273 } else {
1274 const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : \
1275 (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
1276 idx = _ntoa_long(out_tmp, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value),
1277 value < 0, base, precision, width, flags);
1278 }
1279 } else {
1280 // unsigned
1281 if (flags & FLAGS_LONG_LONG) {
1282 #if defined(PRINTF_SUPPORT_LONG_LONG)
1283 idx = _ntoa_long_long(out_tmp, buffer, idx, maxlen, va_arg(va, unsigned long long),
1284 false, base, precision, width, flags);
1285 #endif
1286 } else if (flags & FLAGS_LONG) {
1287 idx = _ntoa_long(out_tmp, buffer, idx, maxlen, va_arg(va, unsigned long),
1288 false, base, precision, width, flags);
1289 } else {
1290 const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : \
1291 (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : \
1292 va_arg(va, unsigned int);
1293 idx = _ntoa_long(out_tmp, buffer, idx, maxlen, value, false, base, precision, width, flags);
1294 }
1295 }
1296 format_tmp++;
1297 break;
1298 }
1299 #if defined(PRINTF_SUPPORT_FLOAT)
1300 case 'f' :
1301 case 'F' :
1302 if (*format_tmp == 'F') {
1303 flags |= FLAGS_UPPERCASE;
1304 }
1305 idx = _ftoa(out_tmp, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
1306 format_tmp++;
1307 break;
1308 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
1309 case 'e':
1310 case 'E':
1311 case 'g':
1312 case 'G':
1313 if ((*format_tmp == 'g')||(*format_tmp == 'G')) {
1314 flags |= FLAGS_ADAPT_EXP;
1315 }
1316 if ((*format_tmp == 'E')||(*format_tmp == 'G')) {
1317 flags |= FLAGS_UPPERCASE;
1318 }
1319 idx = _etoa(out_tmp, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
1320 format_tmp++;
1321 break;
1322 #endif // PRINTF_SUPPORT_EXPONENTIAL
1323 #endif // PRINTF_SUPPORT_FLOAT
1324 case 'c' : {
1325 unsigned int l = 1U;
1326 // pre padding
1327 if (!(flags & FLAGS_LEFT)) {
1328 while (l++ < width) {
1329 out_tmp(' ', buffer, idx++, maxlen);
1330 }
1331 }
1332 // char output
1333 out_tmp((char)va_arg(va, int), buffer, idx++, maxlen);
1334 // post padding
1335 if (flags & FLAGS_LEFT) {
1336 while (l++ < width) {
1337 out_tmp(' ', buffer, idx++, maxlen);
1338 }
1339 }
1340 format_tmp++;
1341 break;
1342 }
1343
1344 case 's' : {
1345 const char* p = va_arg(va, char*);
1346 unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
1347 // pre padding
1348 if (flags & FLAGS_PRECISION) {
1349 l = (l < precision ? l : precision);
1350 }
1351 if (!(flags & FLAGS_LEFT)) {
1352 while (l++ < width) {
1353 out_tmp(' ', buffer, idx++, maxlen);
1354 }
1355 }
1356 // string output
1357 while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
1358 out_tmp(*(p++), buffer, idx++, maxlen);
1359 }
1360 // post padding
1361 if (flags & FLAGS_LEFT) {
1362 while (l++ < width) {
1363 out_tmp(' ', buffer, idx++, maxlen);
1364 }
1365 }
1366 format_tmp++;
1367 break;
1368 }
1369
1370 case 'p' : {
1371 width = sizeof(void*) * 2U;
1372 flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
1373 #if defined(PRINTF_SUPPORT_LONG_LONG)
1374 bool is_ll = false;
1375 if (sizeof(uintptr_t) == sizeof(long long)) {
1376 is_ll = true;
1377 }
1378 if (is_ll) {
1379 idx = _ntoa_long_long(out_tmp, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*),
1380 false, 16U, precision, width, flags);
1381 } else {
1382 #endif
1383 idx = _ntoa_long(out_tmp, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)),
1384 false, 16U, precision, width, flags);
1385 #if defined(PRINTF_SUPPORT_LONG_LONG)
1386 }
1387 #endif
1388 format_tmp++;
1389 break;
1390 }
1391
1392 case 'M' : {
1393 const char* p = va_arg(va, char*);
1394 char store[40];
1395 unsigned int l = __mac2str((unsigned char *)p, store);
1396 const char* pstr = &store[0];
1397 // pre padding
1398 if (flags & FLAGS_PRECISION) {
1399 l = (l < precision ? l : precision);
1400 }
1401 if (!(flags & FLAGS_LEFT)) {
1402 while (l++ < width) {
1403 out_tmp(' ', buffer, idx++, maxlen);
1404 }
1405 }
1406 // string output
1407 while ((*pstr != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
1408 out_tmp(*(pstr++), buffer, idx++, maxlen);
1409 }
1410 // post padding
1411 if (flags & FLAGS_LEFT) {
1412 while (l++ < width) {
1413 out_tmp(' ', buffer, idx++, maxlen);
1414 }
1415 }
1416 format_tmp++;
1417 break;
1418 }
1419 case 'v' : {
1420 uint32_t ipv4 = va_arg(va, uint32_t);
1421 char store[40];
1422 unsigned int l = __ip2str(4, &ipv4, store);
1423 const char* pstr = &store[0];
1424 // pre padding
1425 if (flags & FLAGS_PRECISION) {
1426 l = (l < precision ? l : precision);
1427 }
1428 if (!(flags & FLAGS_LEFT)) {
1429 while (l++ < width) {
1430 out_tmp(' ', buffer, idx++, maxlen);
1431 }
1432 }
1433 // string output
1434 while ((*pstr != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
1435 out_tmp(*(pstr++), buffer, idx++, maxlen);
1436 }
1437 // post padding
1438 if (flags & FLAGS_LEFT) {
1439 while (l++ < width) {
1440 out_tmp(' ', buffer, idx++, maxlen);
1441 }
1442 }
1443 format_tmp++;
1444 break;
1445 }
1446 case 'V' : {
1447 char *ipv6 = va_arg(va, char*);
1448 char store[40];
1449 unsigned int l = __ip2str(6, (unsigned int *)ipv6, store);
1450 const char* pstr = &store[0];
1451 // pre padding
1452 if (flags & FLAGS_PRECISION) {
1453 l = (l < precision ? l : precision);
1454 }
1455 if (!(flags & FLAGS_LEFT)) {
1456 while (l++ < width) {
1457 out_tmp(' ', buffer, idx++, maxlen);
1458 }
1459 }
1460 // string output
1461 while ((*pstr != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
1462 out_tmp(*(pstr++), buffer, idx++, maxlen);
1463 }
1464 // post padding
1465 if (flags & FLAGS_LEFT) {
1466 while (l++ < width) {
1467 out_tmp(' ', buffer, idx++, maxlen);
1468 }
1469 }
1470 format_tmp++;
1471 break;
1472 }
1473
1474 case '%' :
1475 out_tmp('%', buffer, idx++, maxlen);
1476 format_tmp++;
1477 break;
1478
1479 default :
1480 out_tmp(*format_tmp, buffer, idx++, maxlen);
1481 format_tmp++;
1482 break;
1483 }
1484 }
1485
1486 // return written chars without terminating \0
1487 return (int)idx;
1488 }
1489
wm_vsnprintf(char * buffer,size_t count,const char * format,va_list va)1490 int wm_vsnprintf(char* buffer, size_t count, const char* format, va_list va)
1491 {
1492 return _vsnprintf(_out_buffer, buffer, count, format, va);
1493 }
1494
1495 #if defined(TLS_OS_LITEOS) && TLS_OS_LITEOS
printf(const char * restrict fmt,...)1496 int printf(const char *restrict fmt, ...)
1497 {
1498 va_list args;
1499 size_t length;
1500
1501 va_start(args, fmt);
1502 length = _vsnprintf(_out_uart, (char*)fmt, (size_t) - 1, fmt, args);
1503 va_end(args);
1504
1505 return length;
1506 }
1507 #endif
1508
wm_printf(const char * fmt,...)1509 int wm_printf(const char *fmt, ...)
1510 {
1511 va_list args;
1512 size_t length;
1513
1514 va_start(args, fmt);
1515 length = _vsnprintf(_out_uart, (char*)fmt, (size_t) - 1, fmt, args);
1516 va_end(args);
1517
1518 return length;
1519 }
1520
wm_vprintf(const char * fmt,va_list arg_ptr)1521 int wm_vprintf(const char *fmt, va_list arg_ptr)
1522 {
1523 size_t length;
1524
1525 length = _vsnprintf(_out_uart, (char*)fmt, (size_t) - 1, fmt, arg_ptr);
1526
1527 return length;
1528 }
1529
1530 #if 1 // defined(_NEWLIB_VERSION_H__)
sscanf(const char * str,const char * format,...)1531 __attribute__((__weak__)) int sscanf(const char *str, const char *format, ...) /* bug: replace 3.10.21 newlib */
1532 {
1533 va_list args;
1534 int i;
1535
1536 va_start(args, format);
1537 i = wm_vsscanf(str, format, args);
1538 va_end(args);
1539
1540 return i;
1541 }
1542
__cskyvscanfsscanf(const char * str,const char * format,...)1543 __attribute__((__weak__)) int __cskyvscanfsscanf(const char *str, const char *format, ...)
1544 {
1545 va_list args;
1546 int i;
1547
1548 va_start(args, format);
1549 i = wm_vsscanf(str, format, args);
1550 va_end(args);
1551
1552 return i;
1553 }
1554
__cskyvprintfsprintf(char * str,const char * format,...)1555 __attribute__((__weak__)) int __cskyvprintfsprintf(char *str, const char *format, ...)
1556 {
1557 va_list ap;
1558 int i;
1559
1560 va_start(ap, format);
1561 i = wm_vsnprintf(str, (size_t) - 1, format, ap);
1562 va_end(ap);
1563
1564 return i;
1565 }
1566
__cskyvprintfsnprintf(char * str,size_t size,const char * format,...)1567 __attribute__((__weak__)) int __cskyvprintfsnprintf(char *str, size_t size, const char *format, ...)
1568 {
1569 va_list ap;
1570 int i;
1571
1572 va_start(ap, format);
1573 i = wm_vsnprintf(str, size, format, ap);
1574 va_end(ap);
1575
1576 return i;
1577 }
1578
__cskyvprintfvsnprintf(char * str,size_t size,const char * format,va_list ap)1579 __attribute__((__weak__)) int __cskyvprintfvsnprintf(char *str, size_t size, const char *format, va_list ap)
1580 {
1581 return wm_vsnprintf(str, size, format, ap);
1582 }
1583
__cskyvprintfvsprintf(char * str,const char * format,va_list ap)1584 __attribute__((__weak__)) int __cskyvprintfvsprintf(char *str, const char *format, va_list ap)
1585 {
1586 return wm_vsnprintf(str, (size_t) - 1, format, ap);
1587 }
1588
1589 int __cskyvprintfprintf(const char *fmt, ...) __attribute__((__weak__, alias("wm_printf")));
1590
__assert_fail(const char * file,int line,const char * func,const char * failedexpr)1591 __attribute__((__weak__)) void __assert_fail(const char *file,
1592 int line,
1593 const char *func,
1594 const char *failedexpr)
1595 {
1596 wm_printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\r\n",
1597 failedexpr, file, line,
1598 func ? ", function: " : "", func ? func : "");
1599 while (1) {
1600 }
1601 }
1602
1603 /* For CPP type used, you first call this function in main entry */
1604 extern int __dtor_end__;
1605 extern int __ctor_end__;
1606 extern int __ctor_start__;
1607 typedef void (*func_ptr)(void);
cxx_system_init(void)1608 __attribute__((__weak__)) void cxx_system_init(void)
1609 {
1610 func_ptr *p;
1611 for (p = (func_ptr *)&__ctor_end__ -1; p >= (func_ptr *)&__ctor_start__; p--) {
1612 (*p)();
1613 }
1614 }
1615 #endif