maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
uprintf.h
Go to the documentation of this file.
1
2#ifndef UPRINTF_H
3#define UPRINTF_H
4
5#include <mtypes.h>
6
7#ifndef MAUG_NO_LEGACY
8# include <mlegacy.h>
9#endif /* !MAUG_NO_LEGACY */
10
16
20
21/* == Autodetection == */
22
23#define UPRINTF_S16_FMT "%d"
24#define UPRINTF_U16_FMT "%u"
25
26#define UPRINTF_S16_DIGITS 5
27
28#ifndef UPRINTF_S32_FMT
29# if __LONG_WIDTH__ == 64 || __EMSCRIPTEN__
30# define UPRINTF_S32_FMT "%d"
31# elif __LONG_WIDTH__ == 32 || defined( __WATCOMC__ ) || defined( __BORLANDC__ ) || _MSC_VER <= 1200
32# define UPRINTF_S32_FMT "%ld"
33# endif /* __LONG_WIDTH__ */
34#endif /* !UPRINTF_S32_FMT */
35
36#ifndef UPRINTF_U32_FMT
37# if __LONG_WIDTH__ == 64 || __EMSCRIPTEN__
38# define UPRINTF_U32_FMT "%u"
39# elif __LONG_WIDTH__ == 32 || defined( __WATCOMC__ ) || defined( __BORLANDC__ ) || _MSC_VER <= 1200
40# define UPRINTF_U32_FMT "%lu"
41# endif /* __LONG_WIDTH__ */
42#endif /* !UPRINTF_U32_FMT */
43
44#ifndef UPRINTF_X32_FMT
45# if __LONG_WIDTH__ == 64 || __EMSCRIPTEN__
46# define UPRINTF_X32_FMT "%x"
47# elif __LONG_WIDTH__ == 32 || defined( __WATCOMC__ ) || defined( __BORLANDC__ ) || _MSC_VER <= 1200
48# define UPRINTF_X32_FMT "%lx"
49# endif /* __LONG_WIDTH__ */
50#endif /* !UPRINTF_X32_FMT */
51
52#ifndef NEWLINE_STR
53/* TODO: Autodetect. */
54#define NEWLINE_STR "\n"
55#endif /* !NEWLINE_STR */
56
57/* == Manual Config == */
58
59#ifndef UPRINTF_BUFFER_SZ_MAX
60# define UPRINTF_BUFFER_SZ_MAX 1024
61#endif /* !UPRINTF_BUFFER_SZ_MAX */
62
63#ifndef platform_file
64# define platform_file FILE*
65#endif /* !platform_file */
66
67#ifndef platform_fprintf
68# define platform_fprintf fprintf
69#endif /* !platform_fprintf */
70
71#ifndef platform_vfprintf
72# define platform_vfprintf vfprintf
73#endif /* !platform_vfprintf */
74
75#ifndef platform_fopen
76# define platform_fopen fopen
77#endif /* !platform_fopen */
78
79#ifndef platform_fflush
80# define platform_fflush fflush
81#endif /* !platform_fflush */
82
83#ifndef platform_fclose
84# define platform_fclose fclose
85#endif /* !platform_fclose */
86
87#ifdef LOG_TO_FILE
88# ifndef UPRINTF_LOG
89# define UPRINTF_LOG
90# endif /* !UPRINTF_LOG */
91# define LOG_ERR_TARGET g_log_file
92# define LOG_STD_TARGET g_log_file
93#else
94# define LOG_ERR_TARGET stderr
95# define LOG_STD_TARGET stdout
96#endif /* LOG_TO_FILE */
97
98#ifdef __GNUC__
99# ifdef __EMSCRIPTEN__ /* __SIZE_WIDTH__ == 64 */
100# define SIZE_T_FMT "%lu"
101# define SSIZE_T_FMT "%ld"
102# define OFF_T_FMT "%lld"
103# elif defined( _WIN64 ) /* __SIZE_WIDTH__ == 64 */
104# define SIZE_T_FMT "%I64u"
105# define SSIZE_T_FMT "%I64d"
106# define OFF_T_FMT "%I32d"
107# else
108# define SIZE_T_FMT "%lu"
109# define SSIZE_T_FMT "%ld"
110# define OFF_T_FMT "%lu"
111# endif /* __LONG_WIDTH__ */
112#else
113# define SIZE_T_FMT "%u"
114# define SSIZE_T_FMT "%d"
115# define OFF_T_FMT "%lu"
116#endif /* __GNUC__ */
117
118#ifdef MAUG_OS_DOS_REAL
119# define UPRINTF_MS_FMT UPRINTF_U16_FMT
120#else
121# define UPRINTF_MS_FMT UPRINTF_U32_FMT
122#endif /* MAUG_OS_DOS_REAL */
123
124#if !defined( DEBUG_THRESHOLD )
125# define DEBUG_THRESHOLD 1
126#endif /* !DEBUG_THRESHOLD */
127
129 long int d;
130 uint32_t u;
131 char c;
132 void* p;
133 char* s;
134 size_t z;
135};
136
137#if defined( MAUG_OS_NDS )
138
139# include <nds.h>
140
141/* TODO: Figure out a way to get the calling line number for a function. */
142
143static void _internal_debug_printf(
144 const char* src_file, int line, int level, const char* fmt, ...
145) {
146 va_list argp;
147 char buffer[UPRINTF_BUFFER_SZ_MAX + 1];
148 char line_buffer[11] = { 0 };
149
150 if( level >= DEBUG_THRESHOLD ) {
151 va_start( argp, fmt );
152 vsnprintf( buffer, UPRINTF_BUFFER_SZ_MAX, fmt, argp );
153 va_end( argp );
154 snprintf( line_buffer, 10, "%d", line );
155 nocashMessage( src_file );
156 nocashMessage( " (" );
157 nocashMessage( line_buffer );
158 nocashMessage( "): " );
159 nocashMessage( buffer );
160 nocashMessage( "\n" );
161 }
162}
163
164#define debug_printf( lvl, ... ) \
165 _internal_debug_printf( __FILE__, __LINE__, lvl, __VA_ARGS__ )
166
167static void error_printf( const char* fmt, ... ) {
168 va_list argp;
169 char buffer[UPRINTF_BUFFER_SZ_MAX + 1];
170
171 va_start( argp, fmt );
172 vsnprintf( buffer, UPRINTF_BUFFER_SZ_MAX, fmt, argp );
173 va_end( argp );
174
175 nocashMessage( buffer );
176 nocashMessage( "\n" );
177}
178
179# define size_printf( lvl, name, sz ) debug_printf( lvl, name " size is " SIZE_T_FMT " bytes", (sz) );
180
181/* ! */
182#elif defined( UPRINTF_ANCIENT_C )
183/* ! */
184
185/* TODO: Figure out a way to get the calling line number for a function. */
186
187#ifdef RETROFLAT_API_WINCE /* TODO: Use MAUG_OS_WIN */
188
189static void debug_printf( int level, const char* fmt, ... ) {
190 /* TODO: Use maug_vsnprintf() and Windows file APIs. */
191}
192
193static void error_printf( const char* fmt, ... ) {
194 /* TODO: Use maug_vsnprintf() and Windows file APIs. */
195}
196
197#else
198
199static void debug_printf( int level, const char* fmt, ... ) {
200 va_list argp;
201
202 if( level >= DEBUG_THRESHOLD ) {
203 va_start( argp, fmt );
204 vprintf( fmt, argp );
205 va_end( argp );
206 printf( "\n" );
207 }
208}
209
210static void error_printf( const char* fmt, ... ) {
211 va_list argp;
212
213 va_start( argp, fmt );
214 vprintf( fmt, argp );
215 va_end( argp );
216 printf( "\n" );
217}
218
219#endif /* RETROFLAT_API_WINCE */
220
221# define size_printf( lvl, name, sz ) debug_printf( lvl, name " size is " SIZE_T_FMT " bytes", (sz) );
222
223# define size_multi_printf( lvl, name, sz, max ) debug_printf( lvl, "single " name " size is " SIZE_T_FMT " bytes, " name " array size is " SIZE_T_FMT " bytes", (sz), ((sz) * (max)) );
224
225/* ! */
226#elif defined( UPRINTF_LOG )
227/* ! */
228
229# ifdef NO_DEBUG_LINE_NUMBER
230# define LINE_NUMBER() 0
231# else
232# define LINE_NUMBER() __LINE__
233# endif
234
235# define internal_debug_printf( lvl, ... ) if( NULL != LOG_ERR_TARGET && lvl >= DEBUG_THRESHOLD ) { platform_fprintf( LOG_STD_TARGET, "(%d) " __FILE__ ": %d: ", lvl, LINE_NUMBER() ); platform_fprintf( LOG_STD_TARGET, __VA_ARGS__ ); platform_fprintf( LOG_STD_TARGET, NEWLINE_STR ); platform_fflush( LOG_STD_TARGET ); }
236
237# define internal_error_printf( ... ) if( NULL != LOG_ERR_TARGET ) { platform_fprintf( LOG_ERR_TARGET, "(E) " __FILE__ ": %d: ", LINE_NUMBER() ); platform_fprintf( LOG_ERR_TARGET, __VA_ARGS__ ); platform_fprintf( LOG_ERR_TARGET, NEWLINE_STR ); platform_fflush( LOG_ERR_TARGET ); }
238
239# define debug_printf( lvl, ... ) internal_debug_printf( lvl, __VA_ARGS__ )
240
241# define error_printf( ... ) internal_error_printf( __VA_ARGS__ )
242
243# define size_printf( lvl, name, sz ) internal_debug_printf( lvl, name " size is " SIZE_T_FMT " bytes", (sz) );
244
245# define size_multi_printf( lvl, name, sz, max ) internal_debug_printf( lvl, "single " name " size is " SIZE_T_FMT " bytes, " name " array size is " SIZE_T_FMT " bytes", (sz), ((sz) * (max)) );
246
247/* ! */
248#else /* !UPRINTF_LOG, !UPRINTF_ANCIENT_C */
249/* ! */
250
251/* TODO: Stub these without vargarg macros. */
252
253# define debug_printf( ... )
254# define error_printf( ... )
255# define size_printf( ... )
256# define size_multi_printf( ... )
257
258/* ! */
259#endif /* UPRINTF_LOG, UPRINTF_ANCIENT_C */
260/* ! */
261
262#ifdef LOG_TO_FILE
263
264# define logging_init() g_log_file = platform_fopen( LOG_FILE_NAME, "w" );
265# define logging_shutdown() platform_fclose( g_log_file );
266
267# if defined( UPRINTF_C )
268platform_file g_log_file = NULL;
269# else
270extern platform_file g_log_file;
271# endif /* MAIN_C || UPRINTF_C */
272
273#else
274
275# define logging_init()
276# define logging_shutdown()
277
278#endif /* LOG_TO_FILE */
279
280#define maug_bufcat( c, buf, buf_idx, buf_sz, cleanup ) \
281 buf[buf_idx++] = c; \
282 if( buf_idx >= buf_sz ) { goto cleanup; }
283
284#define maug_bufpad( pad_c, pad_sz, i, buf, buf_idx, buf_sz, cleanup ) \
285 i = 0; \
286 while( i < pad_sz ) { \
287 maug_bufcat( pad_c, buffer, buffer_idx, buffer_sz, cleanup ); \
288 i++; \
289 }
290
291int maug_digits( long int num, int base );
292
293int maug_zdigits( size_t num, int base );
294
295#define maug_xtoa( num, base, rem, dest, dest_idx, digits, digits_done, pad ) \
296 dest_idx += digits; \
297 while( 0 != num ) { \
298 /* Get the 1's place. */ \
299 rem = num % base; \
300 dest[--dest_idx] = (9 < rem) ? \
301 /* > 10, so it's a letter. */ \
302 (rem - 10) + 'a' : \
303 /* < 10, so it's a number. */ \
304 rem + '0'; \
305 /* Move the next place value into range. */ \
306 num /= base; \
307 digits_done++; \
308 } \
309 while( digits_done < digits ) { \
310 dest[--dest_idx] = '0'; \
311 digits_done++; \
312 }
313
317#define maug_hctoi( c ) \
318 ('9' > (c) ? (c) - '0' : 'a' > (c) ? 10 + (c) - 'A' : 10 + (c) - 'a')
319
320int maug_is_num( const char* str, size_t str_sz, uint8_t base, uint8_t sign );
321
322int maug_is_float( const char* str, size_t str_sz );
323
324int maug_itoa( long int num, char* dest, int dest_sz, int base );
325
326int maug_utoa( uint32_t num, char* dest, int dest_sz, int base );
327
328int maug_ztoa( size_t num, char* dest, int dest_sz, int base );
329
337uint32_t maug_atou32( const char* buffer, size_t buffer_sz, uint8_t base );
338
346int32_t maug_atos32( const char* buffer, size_t buffer_sz );
347
348float maug_atof( const char* buffer, size_t buffer_sz );
349
350void maug_str_upper( char* line, size_t line_sz );
351
352void maug_str_lower( char* line, size_t line_sz );
353
354MERROR_RETVAL maug_tok_str(
355 size_t idx, const char* line, size_t line_sz, char* out, size_t out_sz );
356
357MERROR_RETVAL maug_tok_int(
358 size_t idx, const char* line, size_t line_sz, int16_t* out );
359
360void maug_vsnprintf(
361 char* buffer, int buffer_sz, const char* fmt, va_list vargs );
362
363void maug_snprintf( char* buffer, int buffer_sz, const char* fmt, ... );
364
365void maug_printf( const char* fmt, ... );
366
367/* TODO: void maug_strtou32( const char* str, */
368
369#ifdef UPRINTF_C
370
371uint32_t g_maug_printf_line = 0;
372int g_maug_uprintf_threshold = DEBUG_THRESHOLD;
373
374int maug_is_num( const char* str, size_t str_sz, uint8_t base, uint8_t sign ) {
375 size_t i = 0;
376
377 if( 0 == str_sz ) {
378 str_sz = maug_strlen( str );
379 }
380
381 for( i = 0 ; str_sz > i ; i++ ) {
382 /* TODO: Base detection. */
383 if( sign && 0 == i && '-' == str[i] ) {
384 continue;
385 } else if( '0' > str[i] || '9' < str[i] ) {
386 return 0;
387 }
388 }
389
390 return 1;
391}
392
393int maug_is_float( const char* str, size_t str_sz ) {
394 size_t i = 0;
395
396 if( 0 == str_sz ) {
397 str_sz = maug_strlen( str );
398 }
399
400 for( i = 0 ; str_sz > i ; i++ ) {
401 if( ('0' > str[i] || '9' < str[i]) && '.' != str[i] ) {
402 return 0;
403 }
404 }
405
406 return 1;
407}
408
409int maug_digits( long int num, int base ) {
410 int digits = 0;
411 int negative = 0;
412
413 if( 0 > num ) {
414 num *= -1;
415 negative = 1;
416 }
417
418 while( 0 < num ) {
419 num /= base;
420 digits++;
421 }
422
423 if( 0 == digits ) {
424 digits = 1; /* 0 */
425 }
426
427 if( negative ) {
428 digits++; /* - symbol */
429 }
430
431 return digits;
432}
433
434/* === */
435
436int maug_zdigits( size_t num, int base ) {
437 int digits = 0;
438 int negative = 0;
439
440 while( 0 < num ) {
441 num /= base;
442 digits++;
443 }
444
445 if( 0 == digits ) {
446 digits = 1; /* 0 */
447 }
448
449 if( negative ) {
450 digits++; /* - symbol */
451 }
452
453 return digits;
454}
455
456/* === */
457
458int maug_itoa( long int num, char* dest, int dest_sz, int base ) {
459 long int rem;
460 int digits;
461 int digits_done = 0;
462 int dest_idx = 0;
463 int negative = 0;
464
465 digits = maug_digits( num, base );
466 assert( (0 == num && 1 == digits) || (0 != num && 0 < digits) );
467 assert( digits < dest_sz );
468
469 /* Handle 0 explicitly, otherwise empty string is printed for 0. */
470 if( 0 == num ) {
471 dest[0] = '0';
472 digits_done++;
473 } else if( 0 > num ) {
474 num *= -1;
475 negative = 1;
476 }
477
478 maug_xtoa( num, base, rem, dest, dest_idx, digits, digits_done, pad );
479
480 if( negative ) {
481 dest[dest_idx] = '-';
482 }
483 dest[digits] = '\0';
484
485 return digits;
486}
487
488/* === */
489
490/* TODO: Seems to force 16-bit in Borland... why? */
491int maug_utoa( uint32_t num, char* dest, int dest_sz, int base ) {
492 uint32_t rem;
493 int digits;
494 int digits_done = 0;
495 int dest_idx = 0;
496
497 digits = maug_digits( num, base );
498 assert( (0 == num && 1 == digits) || (0 != num && 0 < digits) );
499 assert( digits < dest_sz );
500
501 /* Handle 0 explicitly, otherwise empty string is printed for 0. */
502 if( 0 == num ) {
503 dest[0] = '0';
504 digits_done++;
505 }
506
507 maug_xtoa( num, base, rem, dest, dest_idx, digits, digits_done, pad );
508 dest[digits] = '\0';
509
510 return digits;
511}
512
513/* === */
514
515int maug_ztoa( size_t num, char* dest, int dest_sz, int base ) {
516 size_t rem;
517 int digits;
518 int digits_done = 0;
519 int dest_idx = 0;
520
521 digits = maug_zdigits( num, base );
522 assert( (0 == num && 1 == digits) || (0 != num && 0 < digits) );
523 assert( digits < dest_sz );
524
525 /* Handle 0 explicitly, otherwise empty string is printed for 0. */
526 if( 0 == num ) {
527 dest[0] = '0';
528 digits_done++;
529 }
530
531 maug_xtoa( num, base, rem, dest, dest_idx, digits, digits_done, pad );
532 dest[digits] = '\0';
533
534 return digits;
535}
536
537/* === */
538
539uint32_t maug_atou32( const char* buffer, size_t buffer_sz, uint8_t base ) {
540 size_t i = 0;
541 uint32_t u32_out = 0;
542
543 if( 0 == buffer_sz ) {
544 buffer_sz = maug_strlen( buffer );
545 }
546
547 for( i = 0 ; buffer_sz > i ; i++ ) {
548 if( base > 10 && 'a' <= buffer[i] ) {
549 u32_out *= base;
550 u32_out += (buffer[i] - 'a') + 10;
551 } else if( base > 10 && 'A' <= buffer[i] ) {
552 u32_out *= base;
553 u32_out += (buffer[i] - 'A') + 10;
554 } else if( '0' <= buffer[i] ) {
555 u32_out *= base;
556 u32_out += (buffer[i] - '0');
557 } else {
558 break;
559 }
560 }
561
562 return u32_out;
563}
564
565/* === */
566
567int32_t maug_atos32( const char* buffer, size_t buffer_sz ) {
568 size_t i = 0;
569 int32_t s32_out = 0;
570 uint32_t is_neg = 0;
571
572 if( 0 == buffer_sz ) {
573 buffer_sz = maug_strlen( buffer );
574 }
575
576 for( i = 0 ; buffer_sz > i ; i++ ) {
577 if( '-' == buffer[i] && 0 == i ) {
578 is_neg = 1;
579 } else if( '0' <= buffer[i] && '9' >= buffer[i] ) {
580 s32_out *= 10;
581 s32_out += (buffer[i] - '0');
582 } else {
583 break;
584 }
585 }
586
587 if( is_neg ) {
588 s32_out *= -1;
589 }
590
591 return s32_out;
592}
593
594/* === */
595
596float maug_atof( const char* buffer, size_t buffer_sz ) {
597 size_t i = 0;
598 float float_out = 0;
599 float dec_sz = -1;
600
601 if( 0 == buffer_sz ) {
602 buffer_sz = maug_strlen( buffer );
603 }
604
605 for( i = 0 ; buffer_sz > i ; i++ ) {
606 if( '0' <= buffer[i] && '9' >= buffer[i] ) {
607 if( 0 > dec_sz ) {
608 /* Tack the numbers on before the floating point. */
609 float_out *= 10;
610 float_out += (buffer[i] - '0');
611 } else {
612 /* Tack the numbers on after the floating point. */
613 float_out += ((buffer[i] - '0') * dec_sz);
614 dec_sz *= 0.1;
615 }
616 } else if( '.' == buffer[i] ) {
617 /* Start parsing post-point numbers. */
618 dec_sz = 0.1;
619 } else {
620 break;
621 }
622 }
623
624 return float_out;
625}
626
627/* === */
628
629void maug_str_upper( char* line, size_t line_sz ) {
630 size_t i = 0;
631
632 for( i = 0 ; line_sz > i ; i++ ) {
633 if( 0x61 <= line[i] && 0x7a >= line[i] ) {
634 line[i] -= 0x20;
635 }
636 }
637}
638
639/* === */
640
641void maug_str_lower( char* line, size_t line_sz ) {
642 size_t i = 0;
643
644 for( i = 0 ; line_sz > i ; i++ ) {
645 if( 0x41 <= line[i] && 0x5a >= line[i] ) {
646 line[i] += 0x20;
647 }
648 }
649}
650
651/* === */
652
653MERROR_RETVAL maug_tok_str(
654 size_t idx, const char* line, size_t line_sz, char* out, size_t out_sz
655) {
656 MERROR_RETVAL retval = MERROR_OVERFLOW;
657 size_t idx_iter = 0;
658 size_t i_out = 0;
659 size_t i_in = 0;
660
661 if( 0 == line_sz ) {
662 line_sz = maug_strlen( line );
663 assert( 0 < line );
664 }
665
666 for( i_in = 0 ; line_sz >= i_in ; i_in++ ) {
667 if( '\n' == line[i_in] || ' ' == line[i_in] || '\0' == line[i_in] ) {
668 /* TODO: Filter out multi-whitespace. */
669 idx_iter++;
670 if( idx_iter > idx ) {
671 /* All chars copied! */
672 retval = MERROR_OK;
673 out[i_out++] = '\0';
674 assert( i_out < out_sz );
675 goto cleanup;
676 }
677 continue;
678 } else if( idx_iter == idx ) {
679 if( i_out + 1 >= out_sz ) {
680 error_printf(
681 "token " SIZE_T_FMT " would exceed buffer sz: " SIZE_T_FMT,
682 idx, out_sz );
683 goto cleanup;
684 }
685 /* Copy current char over. */
686 out[i_out++] = line[i_in];
687 }
688 }
689
690 error_printf( "token " SIZE_T_FMT " not available in line!", idx );
691
692cleanup:
693
694 return retval;
695}
696
697/* === */
698
699MERROR_RETVAL maug_tok_int(
700 size_t idx, const char* line, size_t line_sz, int16_t* out
701) {
702 MERROR_RETVAL retval = MERROR_OK;
703 char out_str[UPRINTF_S16_DIGITS + 1];
704
705 maug_mzero( out_str, UPRINTF_S16_DIGITS + 1 );
706
707 retval = maug_tok_str(
708 idx, line, line_sz, out_str, UPRINTF_S16_DIGITS + 1 );
709 maug_cleanup_if_not_ok();
710
711 *out = maug_atos32( out_str, UPRINTF_S16_DIGITS );
712
713cleanup:
714
715 return retval;
716}
717
718/* === */
719
720/* TODO: Error checking. */
721void maug_vsnprintf(
722 char* buffer, int buffer_sz, const char* fmt, va_list vargs
723) {
724 int i = 0, j = 0;
725 char last = '\0';
726 union MAUG_FMT_SPEC spec;
727 int pad_len = 0;
728 char c;
729 char pad_char = ' ';
730 int buffer_idx = 0;
731 int spec_is_long = 0;
732
733 for( i = 0 ; '\0' != fmt[i] ; i++ ) {
734 c = fmt[i]; /* Separate so we can play tricks below. */
735
736 if( '%' == last ) {
737 /* Conversion specifier encountered. */
738 switch( fmt[i] ) {
739 case 'l':
740 spec_is_long = 1;
741 /* Skip resetting the last char. */
742 continue;
743
744 case 's':
745 spec.s = va_arg( vargs, char* );
746
747 /* Print string. */
748 j = 0;
749 while( '\0' != spec.s[j] ) {
750 maug_bufcat( spec.s[j++], buffer, buffer_idx,
751 buffer_sz, cleanup );
752 }
753 break;
754
755 case 'u':
756 if( spec_is_long ) {
757 spec.u = va_arg( vargs, uint32_t );
758 } else {
759 spec.u = va_arg( vargs, unsigned int );
760 }
761
762 /* Print padding. */
763 pad_len -= maug_digits( spec.d, 10 );
764 maug_bufpad( pad_char, pad_len, j,
765 buffer, buffer_idx, buffer_sz, cleanup );
766
767 /* Print number. */
768 buffer_idx += maug_utoa(
769 spec.d, &(buffer[buffer_idx]), buffer_sz - buffer_idx, 10 );
770 break;
771
772 case 'd':
773 if( spec_is_long ) {
774 spec.d = va_arg( vargs, long int );
775 } else {
776 spec.d = va_arg( vargs, int );
777 }
778
779 /* Print padding. */
780 pad_len -= maug_digits( spec.d, 10 );
781 maug_bufpad( pad_char, pad_len, j,
782 buffer, buffer_idx, buffer_sz, cleanup );
783
784 /* Print number. */
785 buffer_idx += maug_itoa(
786 spec.d, &(buffer[buffer_idx]), buffer_sz - buffer_idx, 10 );
787 break;
788
789 case 'z':
790 spec.z = va_arg( vargs, size_t );
791
792 /* Print padding. */
793 pad_len -= maug_zdigits( spec.z, 10 );
794 maug_bufpad( pad_char, pad_len, j,
795 buffer, buffer_idx, buffer_sz, cleanup );
796
797 /* Print number. */
798 buffer_idx += maug_ztoa(
799 spec.z, &(buffer[buffer_idx]), buffer_sz - buffer_idx, 10 );
800 break;
801
802 case 'x':
803 spec.d = va_arg( vargs, int );
804
805 /* Print padding. */
806 pad_len -= maug_digits( spec.d, 16 );
807 maug_bufpad( pad_char, pad_len, j,
808 buffer, buffer_idx, buffer_sz, cleanup );
809
810 /* Print number. */
811 buffer_idx += maug_utoa(
812 spec.d, &(buffer[buffer_idx]), buffer_sz - buffer_idx, 16 );
813 break;
814
815 case 'c':
816 spec.c = va_arg( vargs, int );
817
818 /* Print padding. */
819 pad_len -= 1;
820 maug_bufpad( pad_char, pad_len, j,
821 buffer, buffer_idx, buffer_sz, cleanup );
822
823 /* Print char. */
824 maug_bufcat( spec.c, buffer, buffer_idx,
825 buffer_sz, cleanup );
826 break;
827
828 case '%':
829 /* Literal % */
830 last = '\0';
831 maug_bufcat( '%', buffer, buffer_idx, buffer_sz, cleanup );
832 break;
833
834 case '0':
835 /* If we haven't started counting padding with a non-zero number,
836 * this must be a 0-padding signifier.
837 */
838 if( 0 >= pad_len ) {
839 pad_char = '0';
840 c = '%';
841 break;
842 }
843 /* If we've already started parsing padding count digits, then
844 * fall through below as a regular number.
845 */
846 case '1':
847 case '2':
848 case '3':
849 case '4':
850 case '5':
851 case '6':
852 case '7':
853 case '8':
854 case '9':
855 /* Handle multi-digit qty padding. */
856 pad_len *= 10;
857 pad_len += (c - '0'); /* Convert from char to int. */
858 c = '%';
859 break;
860 }
861 } else if( '%' != c ) {
862 pad_char = ' '; /* Reset padding. */
863 pad_len = 0; /* Reset padding. */
864 spec_is_long = 0;
865
866 /* Print non-escape characters verbatim. */
867 maug_bufcat( c, buffer, buffer_idx,
868 buffer_sz, cleanup );
869 }
870
871 last = c;
872 }
873
874 /* Add a terminating null if it'll fit! */
875 maug_bufcat( '\0', buffer, buffer_idx,
876 buffer_sz, cleanup );
877
878cleanup:
879 return;
880}
881
882/* === */
883
884/* TODO: Error checking. */
885void maug_snprintf( char* buffer, int buffer_sz, const char* fmt, ... ) {
886 va_list vargs;
887
888 va_start( vargs, fmt );
889 maug_vsnprintf( buffer, buffer_sz, fmt, vargs );
890 va_end( vargs );
891}
892
893/* === */
894
895void maug_printf( const char* fmt, ... ) {
896 char buffer[UPRINTF_BUFFER_SZ_MAX];
897 va_list vargs;
898
899 va_start( vargs, fmt );
900 maug_vsnprintf( buffer, UPRINTF_BUFFER_SZ_MAX, fmt, vargs );
901 va_end( vargs );
902
903 /* TODO */
904}
905
906/* === */
907
908#ifndef RETROFLAT_API_WINCE /* TODO */
909
910void maug_debug_printf(
911 FILE* out, uint8_t flags, const char* src_name, size_t line, int16_t lvl,
912 const char* fmt, ...
913) {
914 va_list vargs;
915
916 if( NULL == out ) {
917#ifdef MAUG_LOG_FILE
918 out = g_log_file;
919#else
920 out = stdout;
921#endif /* MAUG_LOG_FILE */
922 }
923
924 if( lvl >= g_maug_uprintf_threshold ) {
925 platform_fprintf( out, "(%d) %s : " SIZE_T_FMT ": ",
926 lvl, src_name, line );
927
928 va_start( vargs, fmt );
929 platform_vfprintf( out, fmt, vargs );
930 va_end( vargs );
931
932 platform_fprintf( out, NEWLINE_STR );
933 platform_fflush( out );
934 }
935}
936
937#endif /* !RETROFLAT_API_WINCE */
938
939#else
940
941extern uint32_t g_maug_printf_line;
942
943#endif /* UPRINTF_C */
944 /* maug_uprintf */
946
947#endif /* !UPRINTF_H */
948
int MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
#define maug_mzero(ptr, sz)
Zero the block of memory pointed to by ptr.
Definition mmem.h:62
uint32_t maug_atou32(const char *buffer, size_t buffer_sz, uint8_t base)
int32_t maug_atos32(const char *buffer, size_t buffer_sz)
Definition uprintf.h:128