1 /*
2  *  Copyright 2001, 2002 Georges Menie (www.menie.org)
3  *  stdarg version contributed by Christian Ettinger
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU Lesser General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  Changes for the FreeRTOS ports:
11  *
12  *  - The dot in "%-8.8s"
13  *  - The specifiers 'l' (long) and 'L' (long long)
14  *  - The specifier 'u' for unsigned
15  *  - Dot notation for IP addresses:
16  *    sprintf("IP = %xip\n", 0xC0A80164);
17  *    will produce "IP = 192.168.1.100\n"
18  *    sprintf("IP = %pip\n", pxIPv6_Address);
19  */
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 
28 #if ( USE_FREERTOS != 0 )
29     #include "FreeRTOS.h"
30 #else
31     #include <stdint.h>
32     typedef int        BaseType_t;
33     typedef uint32_t   TickType_t;
34     #define pdTRUE     1
35     #define pdFALSE    0
36     #define pdMS_TO_TICKS( x )    ( x )
37 #endif
38 
39 #define PAD_RIGHT    1
40 #define PAD_ZERO     2
41 
42 int sprintf( char * apBuf,
43              const char * apFmt,
44              ... );
45 
46 /*
47  * Return 1 for readable, 2 for writable, 3 for both.
48  * Function must be provided by the application.
49  */
50 extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress );
51 extern void vOutputChar( const char cChar,
52                          const TickType_t xTicksToWait );
53 
54 #ifdef __GNUC__
55 
xApplicationMemoryPermissions(uint32_t aAddress)56     __attribute__( ( weak ) ) BaseType_t xApplicationMemoryPermissions( uint32_t aAddress )
57     {
58         ( void ) aAddress;
59         /* Return 1 for readable, 2 for writable, 3 for both. */
60         return 0x03;
61     }
62 
63 
vOutputChar(const char cChar,const TickType_t xTicksToWait)64     __attribute__( ( weak ) ) void vOutputChar( const char cChar,
65                                                 const TickType_t xTicksToWait )
66     {
67         ( void ) cChar;
68         ( void ) xTicksToWait;
69         /* Do nothing. */
70     }
71 
72 #endif /* __GNUC__ */
73 
74 static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 );
75 
76 int tiny_printf( const char * format,
77                  ... );
78 
79 /* Defined here: write a large amount as GB, MB, KB or bytes */
80 const char * mkSize( unsigned long long aSize,
81                      char * apBuf,
82                      int aLen );
83 
84 typedef union
85 {
86     uint8_t ucBytes[ 4 ];
87     uint16_t ucShorts[ 2 ];
88     uint32_t ulWords[ 1 ];
89 } _U32;
90 
91 struct xPrintFlags
92 {
93     int base;
94     int width;
95     int printLimit;
96     unsigned
97         pad : 8,
98         letBase : 8,
99         isSigned : 1,
100         isNumber : 1,
101         long32 : 1,
102         long64 : 1;
103 };
104 
105 struct SStringBuf
106 {
107     char * str;
108     const char * orgStr;
109     const char * nulPos;
110     int curLen;
111     struct xPrintFlags flags;
112 };
113 
114 #ifdef __GNUC__
115     const static _U32 u32 =
116     {
117         ucBytes : { 0, 1, 2, 3 }
118     };
119 #else
120 const static _U32 u32 = { 0, 1, 2, 3 };
121 #endif
122 
strbuf_init(struct SStringBuf * apStr,char * apBuf,const char * apMaxStr)123 static void strbuf_init( struct SStringBuf * apStr,
124                          char * apBuf,
125                          const char * apMaxStr )
126 {
127     apStr->str = apBuf;
128     apStr->orgStr = apBuf;
129     apStr->nulPos = apMaxStr - 1;
130     apStr->curLen = 0;
131 
132     memset( &apStr->flags, '\0', sizeof apStr->flags );
133 }
134 /*-----------------------------------------------------------*/
135 
strbuf_printchar(struct SStringBuf * apStr,int c)136 static BaseType_t strbuf_printchar( struct SStringBuf * apStr,
137                                     int c )
138 {
139     if( apStr->str == NULL )
140     {
141         vOutputChar( ( char ) c, xTicksToWait );
142         apStr->curLen++;
143         return pdTRUE;
144     }
145 
146     if( apStr->str < apStr->nulPos )
147     {
148         *( apStr->str++ ) = c;
149         apStr->curLen++;
150         return pdTRUE;
151     }
152 
153     if( apStr->str == apStr->nulPos )
154     {
155         *( apStr->str++ ) = '\0';
156     }
157 
158     return pdFALSE;
159 }
160 /*-----------------------------------------------------------*/
161 
strbuf_printchar_inline(struct SStringBuf * apStr,int c)162 static __inline BaseType_t strbuf_printchar_inline( struct SStringBuf * apStr,
163                                                     int c )
164 {
165     if( apStr->str == NULL )
166     {
167         vOutputChar( ( char ) c, xTicksToWait );
168 
169         if( c == 0 )
170         {
171             return pdFALSE;
172         }
173 
174         apStr->curLen++;
175         return pdTRUE;
176     }
177 
178     if( apStr->str < apStr->nulPos )
179     {
180         *( apStr->str++ ) = c;
181 
182         if( c == 0 )
183         {
184             return pdFALSE;
185         }
186 
187         apStr->curLen++;
188         return pdTRUE;
189     }
190 
191     if( apStr->str == apStr->nulPos )
192     {
193         *( apStr->str++ ) = '\0';
194     }
195 
196     return pdFALSE;
197 }
198 /*-----------------------------------------------------------*/
199 
i2hex(int aCh)200 static __inline int i2hex( int aCh )
201 {
202     int iResult;
203 
204     if( aCh < 10 )
205     {
206         iResult = '0' + aCh;
207     }
208     else
209     {
210         iResult = 'A' + aCh - 10;
211     }
212 
213     return iResult;
214 }
215 /*-----------------------------------------------------------*/
216 
prints(struct SStringBuf * apBuf,const char * apString)217 static BaseType_t prints( struct SStringBuf * apBuf,
218                           const char * apString )
219 {
220     register int padchar = ' ';
221     int i, len;
222 
223     if( xApplicationMemoryPermissions( ( uint32_t ) apString ) == 0 )
224     {
225         /* The user has probably made a mistake with the parameter
226          * for '%s', the memory is not readable. */
227         apString = "INV_MEM";
228     }
229 
230     if( apBuf->flags.width > 0 )
231     {
232         register int count = 0;
233         register const char * ptr;
234 
235         for( ptr = apString; *ptr; ++ptr )
236         {
237             ++count;
238         }
239 
240         if( count >= apBuf->flags.width )
241         {
242             apBuf->flags.width = 0;
243         }
244         else
245         {
246             apBuf->flags.width -= count;
247         }
248 
249         if( apBuf->flags.pad & PAD_ZERO )
250         {
251             padchar = '0';
252         }
253     }
254 
255     if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 )
256     {
257         for( ; apBuf->flags.width > 0; --apBuf->flags.width )
258         {
259             if( strbuf_printchar( apBuf, padchar ) == 0 )
260             {
261                 return pdFALSE;
262             }
263         }
264     }
265 
266     if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) )
267     {
268         /* The string to print represents an integer number.
269          * In this case, printLimit is the min number of digits to print
270          * If the length of the number to print is less than the min nb of i
271          * digits to display, we add 0 before printing the number
272          */
273         len = strlen( apString );
274 
275         if( len < apBuf->flags.printLimit )
276         {
277             i = apBuf->flags.printLimit - len;
278 
279             for( ; i; i-- )
280             {
281                 if( strbuf_printchar( apBuf, '0' ) == 0 )
282                 {
283                     return pdFALSE;
284                 }
285             }
286         }
287     }
288 
289     /* The string to print is not the result of a number conversion to ascii.
290      * For a string, printLimit is the max number of characters to display
291      */
292     for( ; apBuf->flags.printLimit && *apString; ++apString, --apBuf->flags.printLimit )
293     {
294         if( !strbuf_printchar( apBuf, *apString ) )
295         {
296             return pdFALSE;
297         }
298     }
299 
300     for( ; apBuf->flags.width > 0; --apBuf->flags.width )
301     {
302         if( !strbuf_printchar( apBuf, padchar ) )
303         {
304             return pdFALSE;
305         }
306     }
307 
308     return pdTRUE;
309 }
310 /*-----------------------------------------------------------*/
311 
312 /* the following should be enough for 32 bit int */
313 #define PRINT_BUF_LEN    12 /* to print 4294967296 */
314 
315 #if SPRINTF_LONG_LONG
316     #warning 64-bit libraries will be included as well
printll(struct SStringBuf * apBuf,long long i)317     static BaseType_t printll( struct SStringBuf * apBuf,
318                                long long i )
319     {
320         char print_buf[ 2 * PRINT_BUF_LEN ];
321         register char * s;
322         register int t, neg = 0;
323         register unsigned long long u = i;
324         lldiv_t lldiv_result;
325 
326 /* typedef struct
327  * {
328  *  long long int quot; // quotient
329  *  long long int rem;  // remainder
330  * } lldiv_t;
331  */
332 
333         apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
334 
335         if( i == 0LL )
336         {
337             print_buf[ 0 ] = '0';
338             print_buf[ 1 ] = '\0';
339             return prints( apBuf, print_buf );
340         }
341 
342         if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) )
343         {
344             neg = 1;
345             u = -i;
346         }
347 
348         s = print_buf + sizeof print_buf - 1;
349 
350         *s = '\0';
351 
352         /* 18446744073709551616 */
353         while( u != 0 )
354         {
355             lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base );
356             t = lldiv_result.rem;
357 
358             if( t >= 10 )
359             {
360                 t += apBuf->flags.letBase - '0' - 10;
361             }
362 
363             *( --s ) = t + '0';
364             u = lldiv_result.quot;
365         }
366 
367         if( neg != 0 )
368         {
369             if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) )
370             {
371                 if( !strbuf_printchar( apBuf, '-' ) )
372                 {
373                     return pdFALSE;
374                 }
375 
376                 --apBuf->flags.width;
377             }
378             else
379             {
380                 *( --s ) = '-';
381             }
382         }
383 
384         return prints( apBuf, s );
385     }
386 #endif /* SPRINTF_LONG_LONG */
387 /*-----------------------------------------------------------*/
388 
printi(struct SStringBuf * apBuf,int i)389 static BaseType_t printi( struct SStringBuf * apBuf,
390                           int i )
391 {
392     char print_buf[ PRINT_BUF_LEN ];
393     register char * s;
394     register int t, neg = 0;
395     register unsigned int u = i;
396     register unsigned base = apBuf->flags.base;
397 
398     apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
399 
400     if( i == 0 )
401     {
402         print_buf[ 0 ] = '0';
403         print_buf[ 1 ] = '\0';
404         return prints( apBuf, print_buf );
405     }
406 
407     if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) )
408     {
409         neg = 1;
410         u = -i;
411     }
412 
413     s = print_buf + sizeof print_buf - 1;
414 
415     *s = '\0';
416 
417     switch( base )
418     {
419         case 16:
420 
421             while( u != 0 )
422             {
423                 t = u & 0xF;
424 
425                 if( t >= 10 )
426                 {
427                     t += apBuf->flags.letBase - '0' - 10;
428                 }
429 
430                 *( --s ) = t + '0';
431                 u >>= 4;
432             }
433 
434             break;
435 
436         case 8:
437         case 10:
438 
439             /* GCC compiles very efficient */
440             while( u )
441             {
442                 t = u % base;
443                 *( --s ) = t + '0';
444                 u /= base;
445             }
446 
447             break;
448 
449 /*
450  *  // The generic case, not yet in use
451  *  default:
452  *      while( u )
453  *      {
454  *          t = u % base;
455  *          if( t >= 10)
456  *          {
457  *              t += apBuf->flags.letBase - '0' - 10;
458  *          }
459  *( --s ) = t + '0';
460  *          u /= base;
461  *      }
462  *      break;
463  */
464     }
465 
466     if( neg != 0 )
467     {
468         if( apBuf->flags.width && ( apBuf->flags.pad & PAD_ZERO ) )
469         {
470             if( strbuf_printchar( apBuf, '-' ) == 0 )
471             {
472                 return pdFALSE;
473             }
474 
475             --apBuf->flags.width;
476         }
477         else
478         {
479             *( --s ) = '-';
480         }
481     }
482 
483     return prints( apBuf, s );
484 }
485 /*-----------------------------------------------------------*/
486 
printIp(struct SStringBuf * apBuf,unsigned i)487 static BaseType_t printIp( struct SStringBuf * apBuf,
488                            unsigned i )
489 {
490     char print_buf[ 16 ];
491 
492     sprintf( print_buf, "%u.%u.%u.%u",
493              i >> 24,
494              ( i >> 16 ) & 0xff,
495              ( i >> 8 ) & 0xff,
496              i & 0xff );
497     apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
498     prints( apBuf, print_buf );
499 
500     return pdTRUE;
501 }
502 /*-----------------------------------------------------------*/
503 
usNetToHost(uint16_t usValue)504 static uint16_t usNetToHost( uint16_t usValue )
505 {
506     if( u32.ulWords[ 0 ] == 0x00010203 )
507     {
508         return usValue;
509     }
510     else
511     {
512         return ( usValue << 8 ) | ( usValue >> 8 );
513     }
514 }
515 
printIPv6(struct SStringBuf * apBuf,uint16_t * pusAddress)516 static BaseType_t printIPv6( struct SStringBuf * apBuf,
517                              uint16_t * pusAddress )
518 {
519     int iIndex;
520     int iZeroStart = -1;
521     int iZeroLength = 0;
522     int iCurStart = 0;
523     int iCurLength = 0;
524 
525     for( iIndex = 0; iIndex < 8; iIndex++ )
526     {
527         uint16_t usValue = pusAddress[ iIndex ];
528 
529         if( usValue == 0 )
530         {
531             if( iCurLength == 0 )
532             {
533                 iCurStart = iIndex;
534             }
535 
536             iCurLength++;
537         }
538 
539         if( ( usValue != 0 ) || ( iIndex == 7 ) )
540         {
541             if( iZeroLength < iCurLength )
542             {
543                 iZeroLength = iCurLength;
544                 iZeroStart = iCurStart;
545             }
546 
547             iCurLength = 0;
548         }
549     }
550 
551     apBuf->flags.base = 16;
552     apBuf->flags.letBase = 'a'; /* use lower-case letters 'a' to 'f' */
553 
554     for( iIndex = 0; iIndex < 8; iIndex++ )
555     {
556         if( iIndex == iZeroStart )
557         {
558             iIndex += iZeroLength - 1;
559             strbuf_printchar( apBuf, ':' );
560 
561             if( iIndex == 7 )
562             {
563                 strbuf_printchar( apBuf, ':' );
564             }
565         }
566         else
567         {
568             if( iIndex > 0 )
569             {
570                 strbuf_printchar( apBuf, ':' );
571             }
572 
573             printi( apBuf, ( int ) ( ( uint32_t ) usNetToHost( pusAddress[ iIndex ] ) ) );
574         }
575     }
576 
577     return pdTRUE;
578 }
579 /*-----------------------------------------------------------*/
580 
tiny_print(struct SStringBuf * apBuf,const char * format,va_list args)581 static void tiny_print( struct SStringBuf * apBuf,
582                         const char * format,
583                         va_list args )
584 {
585     char scr[ 2 ];
586 
587     for( ; ; )
588     {
589         int ch = *( format++ );
590 
591         if( ch != '%' )
592         {
593             do
594             {
595                 /* Put the most like flow in a small loop */
596                 if( strbuf_printchar_inline( apBuf, ch ) == 0 )
597                 {
598                     return;
599                 }
600 
601                 ch = *( format++ );
602             } while( ch != '%' );
603         }
604 
605         ch = *( format++ );
606         /* Now ch has character after '%', format pointing to next */
607 
608         if( ch == '\0' )
609         {
610             break;
611         }
612 
613         if( ch == '%' )
614         {
615             if( strbuf_printchar( apBuf, ch ) == 0 )
616             {
617                 return;
618             }
619 
620             continue;
621         }
622 
623         memset( &apBuf->flags, '\0', sizeof apBuf->flags );
624 
625         if( ch == '-' )
626         {
627             ch = *( format++ );
628             apBuf->flags.pad = PAD_RIGHT;
629         }
630 
631         while( ch == '0' )
632         {
633             ch = *( format++ );
634             apBuf->flags.pad |= PAD_ZERO;
635         }
636 
637         if( ch == '*' )
638         {
639             ch = *( format++ );
640             apBuf->flags.width = va_arg( args, int );
641         }
642         else
643         {
644             while( ch >= '0' && ch <= '9' )
645             {
646                 apBuf->flags.width *= 10;
647                 apBuf->flags.width += ch - '0';
648                 ch = *( format++ );
649             }
650         }
651 
652         if( ch == '.' )
653         {
654             ch = *( format++ );
655 
656             if( ch == '*' )
657             {
658                 apBuf->flags.printLimit = va_arg( args, int );
659                 ch = *( format++ );
660             }
661             else
662             {
663                 while( ch >= '0' && ch <= '9' )
664                 {
665                     apBuf->flags.printLimit *= 10;
666                     apBuf->flags.printLimit += ch - '0';
667                     ch = *( format++ );
668                 }
669             }
670         }
671 
672         if( apBuf->flags.printLimit == 0 )
673         {
674             apBuf->flags.printLimit--; /* -1: make it unlimited */
675         }
676 
677         if( ch == 'p' )
678         {
679             if( ( format[ 0 ] == 'i' ) && ( format[ 1 ] == 'p' ) )
680             {
681                 format += 2; /* eat the "pi" of "pip" */
682 
683                 /* Print a IPv6 address */
684                 if( printIPv6( apBuf, va_arg( args, uint16_t * ) ) == 0 )
685                 {
686                     break;
687                 }
688 
689                 continue;
690             }
691         }
692 
693         if( ch == 's' )
694         {
695             register char * s = ( char * ) va_arg( args, int );
696 
697             if( prints( apBuf, s ? s : "(null)" ) == 0 )
698             {
699                 break;
700             }
701 
702             continue;
703         }
704 
705         if( ch == 'c' )
706         {
707             /* char are converted to int then pushed on the stack */
708             scr[ 0 ] = ( char ) va_arg( args, int );
709 
710             if( strbuf_printchar( apBuf, scr[ 0 ] ) == 0 )
711             {
712                 return;
713             }
714 
715             continue;
716         }
717 
718         if( ch == 'l' )
719         {
720             ch = *( format++ );
721             apBuf->flags.long32 = 1;
722             /* Makes not difference as u32 == long */
723         }
724 
725         if( ch == 'L' )
726         {
727             ch = *( format++ );
728             apBuf->flags.long64 = 1;
729             /* Does make a difference */
730         }
731 
732         apBuf->flags.base = 10;
733         apBuf->flags.letBase = 'a';
734 
735         if( ( ch == 'd' ) || ( ch == 'u' ) )
736         {
737             apBuf->flags.isSigned = ( ch == 'd' );
738             #if SPRINTF_LONG_LONG
739                 if( apBuf->flags.long64 != pdFALSE )
740                 {
741                     if( printll( apBuf, va_arg( args, long long ) ) == 0 )
742                     {
743                         break;
744                     }
745                 }
746                 else
747             #endif /* SPRINTF_LONG_LONG */
748 
749             if( printi( apBuf, va_arg( args, int ) ) == 0 )
750             {
751                 break;
752             }
753 
754             continue;
755         }
756 
757         apBuf->flags.base = 16; /* From here all hexadecimal */
758 
759         if( ( ch == 'x' ) && ( format[ 0 ] == 'i' ) && ( format[ 1 ] == 'p' ) )
760         {
761             format += 2; /* eat the "xi" of "xip" */
762 
763             /* Will use base 10 again */
764             if( printIp( apBuf, va_arg( args, int ) ) == 0 )
765             {
766                 break;
767             }
768 
769             continue;
770         }
771 
772         if( ( ch == 'x' ) || ( ch == 'X' ) || ( ch == 'p' ) || ( ch == 'o' ) )
773         {
774             if( ch == 'X' )
775             {
776                 apBuf->flags.letBase = 'A';
777             }
778             else if( ch == 'o' )
779             {
780                 apBuf->flags.base = 8;
781             }
782 
783             #if SPRINTF_LONG_LONG
784                 if( apBuf->flags.long64 != pdFALSE )
785                 {
786                     if( printll( apBuf, va_arg( args, long long ) ) == 0 )
787                     {
788                         break;
789                     }
790                 }
791                 else
792             #endif /* SPRINTF_LONG_LONG */
793 
794             if( printi( apBuf, va_arg( args, int ) ) == 0 )
795             {
796                 break;
797             }
798 
799             continue;
800         }
801     }
802 
803     strbuf_printchar( apBuf, '\0' );
804 }
805 /*-----------------------------------------------------------*/
806 
tiny_printf(const char * format,...)807 int tiny_printf( const char * format,
808                  ... )
809 {
810     va_list args;
811 
812     va_start( args, format );
813     struct SStringBuf strBuf;
814     strbuf_init( &strBuf, NULL, ( const char * ) NULL );
815     tiny_print( &strBuf, format, args );
816     va_end( args );
817 
818     return strBuf.curLen;
819 }
820 /*-----------------------------------------------------------*/
821 
vsnprintf(char * apBuf,size_t aMaxLen,const char * apFmt,va_list args)822 int vsnprintf( char * apBuf,
823                size_t aMaxLen,
824                const char * apFmt,
825                va_list args )
826 {
827     struct SStringBuf strBuf;
828 
829     strbuf_init( &strBuf, apBuf, ( const char * ) apBuf + aMaxLen );
830     tiny_print( &strBuf, apFmt, args );
831 
832     return strBuf.curLen;
833 }
834 /*-----------------------------------------------------------*/
835 
836 /*void timer_start( void ); */
837 /*void timer_stop( void ); */
838 
snprintf(char * apBuf,size_t aMaxLen,const char * apFmt,...)839 int snprintf( char * apBuf,
840               size_t aMaxLen,
841               const char * apFmt,
842               ... )
843 {
844     va_list args;
845 
846 /*timer_stop(); */
847     va_start( args, apFmt );
848     struct SStringBuf strBuf;
849     strbuf_init( &strBuf, apBuf, ( const char * ) apBuf + aMaxLen );
850     tiny_print( &strBuf, apFmt, args );
851     va_end( args );
852 /*timer_start(); */
853 
854     return strBuf.curLen;
855 }
856 /*-----------------------------------------------------------*/
857 
sprintf(char * apBuf,const char * apFmt,...)858 int sprintf( char * apBuf,
859              const char * apFmt,
860              ... )
861 {
862     va_list args;
863 
864     va_start( args, apFmt );
865     struct SStringBuf strBuf;
866     strbuf_init( &strBuf, apBuf, ( const char * ) apBuf + 1024 );
867     tiny_print( &strBuf, apFmt, args );
868     va_end( args );
869 
870     return strBuf.curLen;
871 }
872 /*-----------------------------------------------------------*/
873 
vsprintf(char * apBuf,const char * apFmt,va_list args)874 int vsprintf( char * apBuf,
875               const char * apFmt,
876               va_list args )
877 {
878     struct SStringBuf strBuf;
879 
880     strbuf_init( &strBuf, apBuf, ( const char * ) apBuf + 1024 );
881     tiny_print( &strBuf, apFmt, args );
882 
883     return strBuf.curLen;
884 }
885 /*-----------------------------------------------------------*/
886 
mkSize(unsigned long long aSize,char * apBuf,int aLen)887 const char * mkSize( unsigned long long aSize,
888                      char * apBuf,
889                      int aLen )
890 {
891     static char retString[ 33 ];
892     size_t gb, mb, kb, sb;
893 
894     if( apBuf == NULL )
895     {
896         apBuf = retString;
897         aLen = sizeof retString;
898     }
899 
900     gb = aSize / ( 1024 * 1024 * 1024 );
901     aSize -= gb * ( 1024 * 1024 * 1024 );
902     mb = aSize / ( 1024 * 1024 );
903     aSize -= mb * ( 1024 * 1024 );
904     kb = aSize / ( 1024 );
905     aSize -= kb * ( 1024 );
906     sb = aSize;
907 
908     if( gb )
909     {
910         snprintf( apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) );
911     }
912     else if( mb )
913     {
914         snprintf( apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb ) / 1024ul ) );
915     }
916     else if( kb != 0ul )
917     {
918         snprintf( apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb ) / 1024ul ) );
919     }
920     else
921     {
922         snprintf( apBuf, aLen, "%u bytes", ( unsigned ) sb );
923     }
924 
925     return apBuf;
926 }
927 
928 #ifdef _MSC_VER
929 
930     #if defined( _NO_CRT_STDIO_INLINE )
931 
printf(char const * const _Format,...)932         int printf( char const * const _Format,
933                     ... )
934         {
935             int _Result;
936             va_list _ArgList;
937 
938             __crt_va_start( _ArgList, _Format );
939             _Result = _vfprintf_l( stdout, _Format, NULL, _ArgList );
940             __crt_va_end( _ArgList );
941             return _Result;
942         }
943 
944     #endif /* if defined( _NO_CRT_STDIO_INLINE ) */
945 
946     #if defined( _NO_CRT_STDIO_INLINE )
947 
sscanf(char const * const _Buffer,char const * const _Format,...)948         int sscanf( char const * const _Buffer,
949                     char const * const _Format,
950                     ... )
951         {
952             int _Result;
953             va_list _ArgList;
954 
955             __crt_va_start( _ArgList, _Format );
956             _Result = _vsscanf_l( _Buffer, _Format, NULL, _ArgList );
957             __crt_va_end( _ArgList );
958             return _Result;
959         }
960 
961     #endif /* if defined( _NO_CRT_STDIO_INLINE ) */
962 
963     #if defined( _NO_CRT_STDIO_INLINE )
964 
_vfprintf_l(FILE * const _Stream,char const * const _Format,_locale_t const _Locale,va_list _ArgList)965         int _vfprintf_l( FILE * const _Stream,
966                          char const * const _Format,
967                          _locale_t const _Locale,
968                          va_list _ArgList )
969         {
970             return __stdio_common_vfprintf( _CRT_INTERNAL_LOCAL_PRINTF_OPTIONS, _Stream, _Format, _Locale, _ArgList );
971         }
972 
973     #endif
974 
975     #if defined( _NO_CRT_STDIO_INLINE )
976 
_vsscanf_l(char const * const _Buffer,char const * const _Format,_locale_t const _Locale,va_list _ArgList)977         int _vsscanf_l( char const * const _Buffer,
978                         char const * const _Format,
979                         _locale_t const _Locale,
980                         va_list _ArgList )
981         {
982             return __stdio_common_vsscanf(
983                 _CRT_INTERNAL_LOCAL_SCANF_OPTIONS,
984                 _Buffer, ( size_t ) -1, _Format, _Locale, _ArgList );
985         }
986 
987     #endif /* if defined( _NO_CRT_STDIO_INLINE ) */
988 
989     #if defined( _NO_CRT_STDIO_INLINE )
scanf(char const * const _Format,...)990         int scanf( char const * const _Format,
991                    ... )
992         {
993             int _Result;
994             va_list _ArgList;
995 
996             __crt_va_start( _ArgList, _Format );
997             _Result = _vfscanf_l( stdin, _Format, NULL, _ArgList );
998             __crt_va_end( _ArgList );
999             return _Result;
1000         }
1001     #endif /* if defined( _NO_CRT_STDIO_INLINE ) */
1002 
1003     #if defined( _NO_CRT_STDIO_INLINE )
_vfscanf_l(_Inout_ FILE * const _Stream,char const * const _Format,const _locale_t _Locale,va_list _ArgList)1004         int _vfscanf_l( _Inout_ FILE * const _Stream,
1005                         char const * const _Format,
1006                         const _locale_t _Locale,
1007                         va_list _ArgList )
1008         {
1009             return __stdio_common_vfscanf(
1010                 _CRT_INTERNAL_LOCAL_SCANF_OPTIONS,
1011                 _Stream, _Format, _Locale, _ArgList );
1012         }
1013 
1014     #endif /* if defined( _NO_CRT_STDIO_INLINE ) */
1015 
1016 
1017     #if defined( _NO_CRT_STDIO_INLINE )
vsnprintf_s(char * const _Buffer,size_t const _BufferCount,size_t const _MaxCount,char const * const _Format,va_list _ArgList)1018         int vsnprintf_s( char * const _Buffer,
1019                          size_t const _BufferCount,
1020                          size_t const _MaxCount,
1021                          char const * const _Format,
1022                          va_list _ArgList )
1023         {
1024             return _vsnprintf_s_l( _Buffer, _BufferCount, _MaxCount, _Format, NULL, _ArgList );
1025         }
_vsnprintf_s(char * const _Buffer,size_t const _BufferCount,size_t const _MaxCount,char const * const _Format,va_list _ArgList)1026         int _vsnprintf_s( char * const _Buffer,
1027                           size_t const _BufferCount,
1028                           size_t const _MaxCount,
1029                           char const * const _Format,
1030                           va_list _ArgList )
1031         {
1032             return _vsnprintf_s_l( _Buffer, _BufferCount, _MaxCount, _Format, NULL, _ArgList );
1033         }
1034 
1035     #endif /* if defined( _NO_CRT_STDIO_INLINE ) */
1036 
1037     #if defined( _NO_CRT_STDIO_INLINE )
_vsnprintf_s_l(char * const _Buffer,size_t const _BufferCount,size_t const _MaxCount,char const * const _Format,_locale_t const _Locale,va_list _ArgList)1038         int _vsnprintf_s_l( char * const _Buffer,
1039                             size_t const _BufferCount,
1040                             size_t const _MaxCount,
1041                             char const * const _Format,
1042                             _locale_t const _Locale,
1043                             va_list _ArgList )
1044         {
1045             int const _Result = __stdio_common_vsnprintf_s(
1046                 _CRT_INTERNAL_LOCAL_PRINTF_OPTIONS,
1047                 _Buffer, _BufferCount, _MaxCount, _Format, _Locale, _ArgList );
1048 
1049             return _Result < 0 ? -1 : _Result;
1050         }
1051     #endif /* if defined( _NO_CRT_STDIO_INLINE ) */
1052 
1053 #endif /* __WIN32__ */
1054