• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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