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