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
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
330uint32_t maug_atou32( const char* buffer, size_t buffer_sz, uint8_t base );
331
332int32_t maug_atos32( const char* buffer, size_t buffer_sz );
333
334float maug_atof( const char* buffer, size_t buffer_sz );
335
336void maug_str_upper( char* line, size_t line_sz );
337
338void maug_str_lower( char* line, size_t line_sz );
339
340MERROR_RETVAL maug_tok_str(
341 size_t idx, const char* line, size_t line_sz, char* out, size_t out_sz );
342
343MERROR_RETVAL maug_tok_int(
344 size_t idx, const char* line, size_t line_sz, int16_t* out );
345
346void maug_vsnprintf(
347 char* buffer, int buffer_sz, const char* fmt, va_list vargs );
348
349void maug_snprintf( char* buffer, int buffer_sz, const char* fmt, ... );
350
351void maug_printf( const char* fmt, ... );
352
353/* TODO: void maug_strtou32( const char* str, */
354
355#ifdef UPRINTF_C
356
357uint32_t g_maug_printf_line = 0;
358int g_maug_uprintf_threshold = DEBUG_THRESHOLD;
359
360int maug_is_num( const char* str, size_t str_sz, uint8_t base, uint8_t sign ) {
361 size_t i = 0;
362
363 if( 0 == str_sz ) {
364 str_sz = maug_strlen( str );
365 }
366
367 for( i = 0 ; str_sz > i ; i++ ) {
368 /* TODO: Base detection. */
369 if( sign && 0 == i && '-' == str[i] ) {
370 continue;
371 } else if( '0' > str[i] || '9' < str[i] ) {
372 return 0;
373 }
374 }
375
376 return 1;
377}
378
379int maug_is_float( const char* str, size_t str_sz ) {
380 size_t i = 0;
381
382 if( 0 == str_sz ) {
383 str_sz = maug_strlen( str );
384 }
385
386 for( i = 0 ; str_sz > i ; i++ ) {
387 if( ('0' > str[i] || '9' < str[i]) && '.' != str[i] ) {
388 return 0;
389 }
390 }
391
392 return 1;
393}
394
395int maug_digits( long int num, int base ) {
396 int digits = 0;
397 int negative = 0;
398
399 if( 0 > num ) {
400 num *= -1;
401 negative = 1;
402 }
403
404 while( 0 < num ) {
405 num /= base;
406 digits++;
407 }
408
409 if( 0 == digits ) {
410 digits = 1; /* 0 */
411 }
412
413 if( negative ) {
414 digits++; /* - symbol */
415 }
416
417 return digits;
418}
419
420/* === */
421
422int maug_zdigits( size_t num, int base ) {
423 int digits = 0;
424 int negative = 0;
425
426 while( 0 < num ) {
427 num /= base;
428 digits++;
429 }
430
431 if( 0 == digits ) {
432 digits = 1; /* 0 */
433 }
434
435 if( negative ) {
436 digits++; /* - symbol */
437 }
438
439 return digits;
440}
441
442/* === */
443
444int maug_itoa( long int num, char* dest, int dest_sz, int base ) {
445 long int rem;
446 int digits;
447 int digits_done = 0;
448 int dest_idx = 0;
449 int negative = 0;
450
451 digits = maug_digits( num, base );
452 assert( (0 == num && 1 == digits) || (0 != num && 0 < digits) );
453 assert( digits < dest_sz );
454
455 /* Handle 0 explicitly, otherwise empty string is printed for 0. */
456 if( 0 == num ) {
457 dest[0] = '0';
458 digits_done++;
459 } else if( 0 > num ) {
460 num *= -1;
461 negative = 1;
462 }
463
464 maug_xtoa( num, base, rem, dest, dest_idx, digits, digits_done, pad );
465
466 if( negative ) {
467 dest[dest_idx] = '-';
468 }
469 dest[digits] = '\0';
470
471 return digits;
472}
473
474/* === */
475
476/* TODO: Seems to force 16-bit in Borland... why? */
477int maug_utoa( uint32_t num, char* dest, int dest_sz, int base ) {
478 uint32_t rem;
479 int digits;
480 int digits_done = 0;
481 int dest_idx = 0;
482
483 digits = maug_digits( num, base );
484 assert( (0 == num && 1 == digits) || (0 != num && 0 < digits) );
485 assert( digits < dest_sz );
486
487 /* Handle 0 explicitly, otherwise empty string is printed for 0. */
488 if( 0 == num ) {
489 dest[0] = '0';
490 digits_done++;
491 }
492
493 maug_xtoa( num, base, rem, dest, dest_idx, digits, digits_done, pad );
494 dest[digits] = '\0';
495
496 return digits;
497}
498
499/* === */
500
501int maug_ztoa( size_t num, char* dest, int dest_sz, int base ) {
502 size_t rem;
503 int digits;
504 int digits_done = 0;
505 int dest_idx = 0;
506
507 digits = maug_zdigits( num, base );
508 assert( (0 == num && 1 == digits) || (0 != num && 0 < digits) );
509 assert( digits < dest_sz );
510
511 /* Handle 0 explicitly, otherwise empty string is printed for 0. */
512 if( 0 == num ) {
513 dest[0] = '0';
514 digits_done++;
515 }
516
517 maug_xtoa( num, base, rem, dest, dest_idx, digits, digits_done, pad );
518 dest[digits] = '\0';
519
520 return digits;
521}
522
523/* === */
524
525uint32_t maug_atou32( const char* buffer, size_t buffer_sz, uint8_t base ) {
526 size_t i = 0;
527 uint32_t u32_out = 0;
528
529 if( 0 == buffer_sz ) {
530 buffer_sz = maug_strlen( buffer );
531 }
532
533 for( i = 0 ; buffer_sz > i ; i++ ) {
534 if( 'a' <= buffer[i] ) {
535 u32_out *= base;
536 u32_out += (buffer[i] - 'a') + 10;
537 } else if( 'A' <= buffer[i] ) {
538 u32_out *= base;
539 u32_out += (buffer[i] - 'A') + 10;
540 } else if( '0' <= buffer[i] ) {
541 u32_out *= base;
542 u32_out += (buffer[i] - '0');
543 } else {
544 break;
545 }
546 }
547
548 return u32_out;
549}
550
551/* === */
552
553int32_t maug_atos32( const char* buffer, size_t buffer_sz ) {
554 size_t i = 0;
555 int32_t s32_out = 0;
556 uint32_t is_neg = 0;
557
558 if( 0 == buffer_sz ) {
559 buffer_sz = maug_strlen( buffer );
560 }
561
562 for( i = 0 ; buffer_sz > i ; i++ ) {
563 if( '-' == buffer[i] && 0 == i ) {
564 is_neg = 1;
565 } else if( '0' <= buffer[i] && '9' >= buffer[i] ) {
566 s32_out *= 10;
567 s32_out += (buffer[i] - '0');
568 } else {
569 break;
570 }
571 }
572
573 if( is_neg ) {
574 s32_out *= -1;
575 }
576
577 return s32_out;
578}
579
580/* === */
581
582float maug_atof( const char* buffer, size_t buffer_sz ) {
583 size_t i = 0;
584 float float_out = 0;
585 float dec_sz = -1;
586
587 if( 0 == buffer_sz ) {
588 buffer_sz = maug_strlen( buffer );
589 }
590
591 for( i = 0 ; buffer_sz > i ; i++ ) {
592 if( '0' <= buffer[i] && '9' >= buffer[i] ) {
593 if( 0 > dec_sz ) {
594 /* Tack the numbers on before the floating point. */
595 float_out *= 10;
596 float_out += (buffer[i] - '0');
597 } else {
598 /* Tack the numbers on after the floating point. */
599 float_out += ((buffer[i] - '0') * dec_sz);
600 dec_sz *= 0.1;
601 }
602 } else if( '.' == buffer[i] ) {
603 /* Start parsing post-point numbers. */
604 dec_sz = 0.1;
605 } else {
606 break;
607 }
608 }
609
610 return float_out;
611}
612
613/* === */
614
615void maug_str_upper( char* line, size_t line_sz ) {
616 size_t i = 0;
617
618 for( i = 0 ; line_sz > i ; i++ ) {
619 if( 0x61 <= line[i] && 0x7a >= line[i] ) {
620 line[i] -= 0x20;
621 }
622 }
623}
624
625/* === */
626
627void maug_str_lower( char* line, size_t line_sz ) {
628 size_t i = 0;
629
630 for( i = 0 ; line_sz > i ; i++ ) {
631 if( 0x41 <= line[i] && 0x5a >= line[i] ) {
632 line[i] += 0x20;
633 }
634 }
635}
636
637/* === */
638
639MERROR_RETVAL maug_tok_str(
640 size_t idx, const char* line, size_t line_sz, char* out, size_t out_sz
641) {
642 MERROR_RETVAL retval = MERROR_OVERFLOW;
643 size_t idx_iter = 0;
644 size_t i_out = 0;
645 size_t i_in = 0;
646
647 if( 0 == line_sz ) {
648 line_sz = maug_strlen( line );
649 assert( 0 < line );
650 }
651
652 for( i_in = 0 ; line_sz >= i_in ; i_in++ ) {
653 if( '\n' == line[i_in] || ' ' == line[i_in] || '\0' == line[i_in] ) {
654 /* TODO: Filter out multi-whitespace. */
655 idx_iter++;
656 if( idx_iter > idx ) {
657 /* All chars copied! */
658 retval = MERROR_OK;
659 out[i_out++] = '\0';
660 assert( i_out < out_sz );
661 goto cleanup;
662 }
663 continue;
664 } else if( idx_iter == idx ) {
665 if( i_out + 1 >= out_sz ) {
666 error_printf(
667 "token " SIZE_T_FMT " would exceed buffer sz: " SIZE_T_FMT,
668 idx, out_sz );
669 goto cleanup;
670 }
671 /* Copy current char over. */
672 out[i_out++] = line[i_in];
673 }
674 }
675
676 error_printf( "token " SIZE_T_FMT " not available in line!", idx );
677
678cleanup:
679
680 return retval;
681}
682
683/* === */
684
685MERROR_RETVAL maug_tok_int(
686 size_t idx, const char* line, size_t line_sz, int16_t* out
687) {
688 MERROR_RETVAL retval = MERROR_OK;
689 char out_str[UPRINTF_S16_DIGITS + 1];
690
691 maug_mzero( out_str, UPRINTF_S16_DIGITS + 1 );
692
693 retval = maug_tok_str(
694 idx, line, line_sz, out_str, UPRINTF_S16_DIGITS + 1 );
695 maug_cleanup_if_not_ok();
696
697 *out = maug_atos32( out_str, UPRINTF_S16_DIGITS );
698
699cleanup:
700
701 return retval;
702}
703
704/* === */
705
706/* TODO: Error checking. */
707void maug_vsnprintf(
708 char* buffer, int buffer_sz, const char* fmt, va_list vargs
709) {
710 int i = 0, j = 0;
711 char last = '\0';
712 union MAUG_FMT_SPEC spec;
713 int pad_len = 0;
714 char c;
715 char pad_char = ' ';
716 int buffer_idx = 0;
717 int spec_is_long = 0;
718
719 for( i = 0 ; '\0' != fmt[i] ; i++ ) {
720 c = fmt[i]; /* Separate so we can play tricks below. */
721
722 if( '%' == last ) {
723 /* Conversion specifier encountered. */
724 switch( fmt[i] ) {
725 case 'l':
726 spec_is_long = 1;
727 /* Skip resetting the last char. */
728 continue;
729
730 case 's':
731 spec.s = va_arg( vargs, char* );
732
733 /* Print string. */
734 j = 0;
735 while( '\0' != spec.s[j] ) {
736 maug_bufcat( spec.s[j++], buffer, buffer_idx,
737 buffer_sz, cleanup );
738 }
739 break;
740
741 case 'u':
742 if( spec_is_long ) {
743 spec.u = va_arg( vargs, uint32_t );
744 } else {
745 spec.u = va_arg( vargs, unsigned int );
746 }
747
748 /* Print padding. */
749 pad_len -= maug_digits( spec.d, 10 );
750 maug_bufpad( pad_char, pad_len, j,
751 buffer, buffer_idx, buffer_sz, cleanup );
752
753 /* Print number. */
754 buffer_idx += maug_utoa(
755 spec.d, &(buffer[buffer_idx]), buffer_sz - buffer_idx, 10 );
756 break;
757
758 case 'd':
759 if( spec_is_long ) {
760 spec.d = va_arg( vargs, long int );
761 } else {
762 spec.d = va_arg( vargs, int );
763 }
764
765 /* Print padding. */
766 pad_len -= maug_digits( spec.d, 10 );
767 maug_bufpad( pad_char, pad_len, j,
768 buffer, buffer_idx, buffer_sz, cleanup );
769
770 /* Print number. */
771 buffer_idx += maug_itoa(
772 spec.d, &(buffer[buffer_idx]), buffer_sz - buffer_idx, 10 );
773 break;
774
775 case 'z':
776 spec.z = va_arg( vargs, size_t );
777
778 /* Print padding. */
779 pad_len -= maug_zdigits( spec.z, 10 );
780 maug_bufpad( pad_char, pad_len, j,
781 buffer, buffer_idx, buffer_sz, cleanup );
782
783 /* Print number. */
784 buffer_idx += maug_ztoa(
785 spec.z, &(buffer[buffer_idx]), buffer_sz - buffer_idx, 10 );
786 break;
787
788 case 'x':
789 spec.d = va_arg( vargs, int );
790
791 /* Print padding. */
792 pad_len -= maug_digits( spec.d, 16 );
793 maug_bufpad( pad_char, pad_len, j,
794 buffer, buffer_idx, buffer_sz, cleanup );
795
796 /* Print number. */
797 buffer_idx += maug_utoa(
798 spec.d, &(buffer[buffer_idx]), buffer_sz - buffer_idx, 16 );
799 break;
800
801 case 'c':
802 spec.c = va_arg( vargs, int );
803
804 /* Print padding. */
805 pad_len -= 1;
806 maug_bufpad( pad_char, pad_len, j,
807 buffer, buffer_idx, buffer_sz, cleanup );
808
809 /* Print char. */
810 maug_bufcat( spec.c, buffer, buffer_idx,
811 buffer_sz, cleanup );
812 break;
813
814 case '%':
815 /* Literal % */
816 last = '\0';
817 maug_bufcat( '%', buffer, buffer_idx, buffer_sz, cleanup );
818 break;
819
820 case '0':
821 /* If we haven't started counting padding with a non-zero number,
822 * this must be a 0-padding signifier.
823 */
824 if( 0 >= pad_len ) {
825 pad_char = '0';
826 c = '%';
827 break;
828 }
829 /* If we've already started parsing padding count digits, then
830 * fall through below as a regular number.
831 */
832 case '1':
833 case '2':
834 case '3':
835 case '4':
836 case '5':
837 case '6':
838 case '7':
839 case '8':
840 case '9':
841 /* Handle multi-digit qty padding. */
842 pad_len *= 10;
843 pad_len += (c - '0'); /* Convert from char to int. */
844 c = '%';
845 break;
846 }
847 } else if( '%' != c ) {
848 pad_char = ' '; /* Reset padding. */
849 pad_len = 0; /* Reset padding. */
850 spec_is_long = 0;
851
852 /* Print non-escape characters verbatim. */
853 maug_bufcat( c, buffer, buffer_idx,
854 buffer_sz, cleanup );
855 }
856
857 last = c;
858 }
859
860 /* Add a terminating null if it'll fit! */
861 maug_bufcat( '\0', buffer, buffer_idx,
862 buffer_sz, cleanup );
863
864cleanup:
865 return;
866}
867
868/* === */
869
870/* TODO: Error checking. */
871void maug_snprintf( char* buffer, int buffer_sz, const char* fmt, ... ) {
872 va_list vargs;
873
874 va_start( vargs, fmt );
875 maug_vsnprintf( buffer, buffer_sz, fmt, vargs );
876 va_end( vargs );
877}
878
879/* === */
880
881void maug_printf( const char* fmt, ... ) {
882 char buffer[UPRINTF_BUFFER_SZ_MAX];
883 va_list vargs;
884
885 va_start( vargs, fmt );
886 maug_vsnprintf( buffer, UPRINTF_BUFFER_SZ_MAX, fmt, vargs );
887 va_end( vargs );
888
889 /* TODO */
890}
891
892/* === */
893
894#ifndef RETROFLAT_API_WINCE /* TODO */
895
896void maug_debug_printf(
897 FILE* out, uint8_t flags, const char* src_name, size_t line, int16_t lvl,
898 const char* fmt, ...
899) {
900 va_list vargs;
901
902 if( NULL == out ) {
903#ifdef MAUG_LOG_FILE
904 out = g_log_file;
905#else
906 out = stdout;
907#endif /* MAUG_LOG_FILE */
908 }
909
910 if( lvl >= g_maug_uprintf_threshold ) {
911 platform_fprintf( out, "(%d) %s : " SIZE_T_FMT ": ",
912 lvl, src_name, line );
913
914 va_start( vargs, fmt );
915 platform_vfprintf( out, fmt, vargs );
916 va_end( vargs );
917
918 platform_fprintf( out, NEWLINE_STR );
919 platform_fflush( out );
920 }
921}
922
923#endif /* !RETROFLAT_API_WINCE */
924
925#else
926
927extern uint32_t g_maug_printf_line;
928
929#endif /* UPRINTF_C */
930
931 /* maug_uprintf */
932
933#endif /* !UPRINTF_H */
934
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
Definition uprintf.h:128