]> pd.if.org Git - pdclib/blob - functions/_PDCLIB/print.c
Added some functions.
[pdclib] / functions / _PDCLIB / print.c
1 /* $Id$ */
2
3 /* _PDCLIB_print( const char *, struct _PDCLIB_status_t * )
4
5    This file is part of the Public Domain C Library (PDCLib).
6    Permission is granted to use, modify, and / or redistribute at will.
7 */
8
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <stdarg.h>
12 #include <stdlib.h>
13 #include <stddef.h>
14
15 /* Using an integer's bits as flags for both the conversion flags and length
16    modifiers.
17 */
18 #define E_minus    1<<0
19 #define E_plus     1<<1
20 #define E_alt      1<<2
21 #define E_space    1<<3
22 #define E_zero     1<<4
23 #define E_done     1<<5
24 #define E_char     1<<6
25 #define E_short    1<<7
26 #define E_long     1<<8
27 #define E_llong    1<<9
28 #define E_intmax   1<<10
29 #define E_size     1<<11
30 #define E_ptrdiff  1<<12
31 #define E_intptr   1<<13
32 #define E_ldouble  1<<14
33 #define E_lower    1<<15
34 #define E_unsigned 1<<16
35
36 /* This macro delivers a given character to either a memory buffer or a stream,
37    depending on the contents of 'status' (struct _PDCLIB_status_t).
38    x - the character to be delivered
39    i - pointer to number of characters already delivered in this call
40    n - pointer to maximum number of characters to be delivered in this call
41    s - the buffer into which the character shall be delivered
42 */
43 #define DELIVER( x ) do { if ( status->i < status->n ) { if ( status->stream != NULL ) { status->stream->buffer[status->stream->bufidx++] = x; if ( ( status->stream->bufidx == status->stream->bufsize ) || ( ( status->stream->status & _IOLBF ) && ( x == '\n' ) ) || ( status->stream->status & _IONBF ) ) fflush( status->stream ); } else status->s[status->i] = x; } ++(status->i); } while ( 0 )
44
45 /* This function recursively converts a given integer value to a character
46    stream. The conversion is done under the control of a given status struct
47    and written either to a character string or a stream, depending on that
48    same status struct. The status struct also keeps the function from exceeding
49    snprintf() limits, and enables any necessary padding / prefixing of the
50    output once the number of characters to be printed is known, which happens
51    at the lowermost recursion level.
52 */
53 static void int2base( intmax_t value, struct _PDCLIB_status_t * status )
54 {
55     /* Registering the character being printed at the end of the function here
56        already so it will be taken into account when the deepestmost recursion
57        does the prefix / padding stuff.
58     */
59     ++(status->this);
60     if ( ( value / status->base ) != 0 )
61     {
62         /* More digits to be done - recurse deeper */
63         int2base( value / status->base, status );
64     }
65     else
66     {
67         /* We reached the last digit, the deepest point of our recursion, and
68            only now know how long the number to be printed actually is. Now we
69            have to do the sign, prefix, width, and precision padding stuff
70            before printing the numbers while we resurface from the recursion.
71         */
72         /* At worst, we need two prefix characters (hex prefix). */
73         char preface[3] = "\0";
74         size_t preidx = 0;
75         if ( ( status->flags & E_alt ) && ( status->base == 16 || status->base == 8 ) )
76         {
77             /* Octal / hexadecimal prefix for "%#" conversions */
78             preface[ preidx++ ] = '0';
79             if ( status->base == 16 )
80             {
81                 preface[ preidx++ ] = ( status->flags & E_lower ) ? 'x' : 'X';
82             }
83         }
84         if ( value < 0 )
85         {
86             /* Negative sign for negative values - at all times. */
87             preface[ preidx++ ] = '-';
88         }
89         else if ( ! ( status->flags & E_unsigned ) )
90         {
91             /* plus sign / extra space are only for unsigned conversions */
92             if ( status->flags & E_plus )
93             {
94                 preface[ preidx++ ] = '+';
95             }
96             else if ( status->flags & E_space )
97             {
98                 preface[ preidx++ ] = ' ';
99             }
100         }
101         {
102         size_t prec_pads = ( status->prec > status->this ) ? ( status->prec - status->this ) : 0;
103         if ( ! ( status->flags & ( E_minus | E_zero ) ) )
104         {
105             /* Space padding is only done if no zero padding or left alignment
106                is requested. Leave space for any prefixes determined above.
107             */
108             /* The number of characters to be printed, plus prefixes if any. */
109             /* This line contained probably the most stupid, time-wasting bug
110                I've ever perpetrated. Greetings to Samface, DevL, and all
111                sceners at Breakpoint 2006.
112             */
113             size_t characters = preidx + ( ( status->this > status->prec ) ? status->this : status->prec );
114             if ( status->width > characters )
115             {
116                 for ( int i = 0; i < status->width - characters; ++i )
117                 {
118                     DELIVER( ' ' );
119                     /*
120                     do
121                     {
122                         if ( status->i < status->n )
123                         {
124                             if ( status->stream != 0 )
125                                 do
126                                 {
127                                     status->stream->buffer[status->stream->bufidx++] = (char)' ',
128                                     if ( ( status->stream->bufidx == status->stream->bufsize )
129                                       || ( ( status->stream->status & 2 ) && (char)' ' == '\n' )
130                                       || ( status->stream->status & 4 ) )
131                                         fflush( status->stream )
132                                 } while (0),
133                                 ' ';
134                             else status->s[status->i] = ' ';
135                         }
136                         ++(status->i);
137                     } while ( 0 );
138                     */
139                     ++(status->this);
140                 }
141             }
142         }
143         /* Now we did the padding, do the prefixes (if any). */
144         preidx = 0;
145         while ( preface[ preidx ] != '\0' )
146         {
147             DELIVER( preface[ preidx++ ] );
148             ++(status->this);
149         }
150         if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
151         {
152             /* If field is not left aligned, and zero padding is requested, do
153                so.
154             */
155             while ( status->this < status->width )
156             {
157                 DELIVER( '0' );
158                 ++(status->this);
159             }
160         }
161         /* Do the precision padding if necessary. */
162         for ( int i = 0; i < prec_pads; ++i )
163         {
164             DELIVER( '0' );
165         }
166         }
167     }
168     /* Recursion tail - print the current digit. */
169     {
170     int digit = value % status->base;
171     if ( digit < 0 )
172     {
173         digit *= -1;
174     }
175     if ( status->flags & E_lower )
176     {
177         /* Lowercase letters. Same array used for strto...(). */
178         DELIVER( _PDCLIB_digits[ digit ] );
179     }
180     else
181     {
182         /* Uppercase letters. Array only used here, only 0-F. */
183         DELIVER( _PDCLIB_Xdigits[ digit ] );
184     }
185     }
186 }
187
188 const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
189 {
190     const char * orig_spec = spec;
191     if ( *(++spec) == '%' )
192     {
193         /* %% -> print single '%' */
194         DELIVER( *spec );
195         return ++spec;
196     }
197     /* Initializing status structure */
198     status->flags = 0;
199     status->base  = 0;
200     status->this  = 0;
201     status->width = 0;
202     status->prec  = 0;
203
204     /* First come 0..n flags */
205     do
206     {
207         switch ( *spec )
208         {
209             case '-':
210                 /* left-aligned output */
211                 status->flags |= E_minus;
212                 ++spec;
213                 break;
214             case '+':
215                 /* positive numbers prefixed with '+' */
216                 status->flags |= E_plus;
217                 ++spec;
218                 break;
219             case '#':
220                 /* alternative format (leading 0x for hex, 0 for octal) */
221                 status->flags |= E_alt;
222                 ++spec;
223                 break;
224             case ' ':
225                 /* positive numbers prefixed with ' ' */
226                 status->flags |= E_space;
227                 ++spec;
228                 break;
229             case '0':
230                 /* right-aligned padding done with '0' instead of ' ' */
231                 status->flags |= E_zero;
232                 ++spec;
233                 break;
234             default:
235                 /* not a flag, exit flag parsing */
236                 status->flags |= E_done;
237                 break;
238         }
239     } while ( ! ( status->flags & E_done ) );
240
241     /* Optional field width */
242     if ( *spec == '*' )
243     {
244         /* Retrieve width value from argument stack */
245         if ( ( status->width = va_arg( status->arg, int ) ) < 0 )
246         {
247             /* Negative value is '-' flag plus absolute value */
248             status->flags |= E_minus;
249             status->width *= -1;
250         }
251         ++spec;
252     }
253     else
254     {
255         /* If a width is given, strtol() will return its value. If not given,
256            strtol() will return zero. In both cases, endptr will point to the
257            rest of the conversion specifier - just what we need.
258         */
259         status->width = (int)strtol( spec, (char**)&spec, 10 );
260     }
261
262     /* Optional precision */
263     if ( *spec == '.' )
264     {
265         ++spec;
266         if ( *spec == '*' )
267         {
268             /* Retrieve precision value from argument stack. A negative value
269                is as if no precision is given - as precision is initalized to
270                EOF (negative), there is no need for testing for negative here.
271             */
272             status->prec = va_arg( status->arg, int );
273         }
274         else
275         {
276             char * endptr;
277             status->prec = (int)strtol( spec, &endptr, 10 );
278             if ( spec == endptr )
279             {
280                 /* Decimal point but no number - bad conversion specifier. */
281                 return orig_spec;
282             }
283             spec = endptr;
284         }
285         /* Having a precision cancels out any zero flag. */
286         status->flags ^= E_zero;
287     }
288
289     /* Optional length modifier
290        We step one character ahead in any case, and step back only if we find
291        there has been no length modifier (or step ahead another character if it
292        has been "hh" or "ll").
293     */
294     switch ( *(spec++) )
295     {
296         case 'h':
297             if ( *spec == 'h' )
298             {
299                 /* hh -> char */
300                 status->flags |= E_char;
301                 ++spec;
302             }
303             else
304             {
305                 /* h -> short */
306                 status->flags |= E_short;
307             }
308             break;
309         case 'l':
310             if ( *spec == 'l' )
311             {
312                 /* ll -> long long */
313                 status->flags |= E_llong;
314                 ++spec;
315             }
316             else
317             {
318                 /* k -> long */
319                 status->flags |= E_long;
320             }
321             break;
322         case 'j':
323             /* j -> intmax_t, which might or might not be long long */
324             status->flags |= E_intmax;
325             break;
326         case 'z':
327             /* z -> size_t, which might or might not be unsigned int */
328             status->flags |= E_size;
329             break;
330         case 't':
331             /* t -> ptrdiff_t, which might or might not be long */
332             status->flags |= E_ptrdiff;
333             break;
334         case 'L':
335             /* L -> long double */
336             status->flags |= E_ldouble;
337             break;
338         default:
339             --spec;
340             break;
341     }
342
343     /* Conversion specifier */
344     switch ( *spec )
345     {
346         case 'd':
347             /* FALLTHROUGH */
348         case 'i':
349             status->base = 10;
350             break;
351         case 'o':
352             status->base = 8;
353             status->flags |= E_unsigned;
354             break;
355         case 'u':
356             status->base = 10;
357             status->flags |= E_unsigned;
358             break;
359         case 'x':
360             status->base = 16;
361             status->flags |= ( E_lower | E_unsigned );
362             break;
363         case 'X':
364             status->base = 16;
365             status->flags |= E_unsigned;
366             break;
367         case 'f':
368         case 'F':
369         case 'e':
370         case 'E':
371         case 'g':
372         case 'G':
373             break;
374         case 'a':
375         case 'A':
376             break;
377         case 'c':
378             /* TODO: Flags, wide chars. */
379             DELIVER( va_arg( status->arg, int ) );
380             return ++spec;
381         case 's':
382             /* TODO: Flags, wide chars. */
383             {
384                 char * s = va_arg( status->arg, char * );
385                 while ( *s != '\0' )
386                 {
387                     DELIVER( *(s++) );
388                 }
389                 return ++spec;
390             }
391         case 'p':
392             /* TODO: E_long -> E_intptr */
393             status->base = 16;
394             status->flags |= ( E_lower | E_unsigned | E_alt | E_long );
395             break;
396         case 'n':
397            {
398                int * val = va_arg( status->arg, int * );
399                *val = status->i;
400                return ++spec;
401            }
402         default:
403             /* No conversion specifier. Bad conversion. */
404             return orig_spec;
405     }
406
407     /* Do the actual output based on our findings */
408     if ( status->base != 0 )
409     {
410         /* Integer conversions */
411         /* TODO: Check for invalid flag combinations. */
412         if ( status->flags & E_unsigned )
413         {
414             uintmax_t value;
415             switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_size ) )
416             {
417                 case E_char:
418                     value = (uintmax_t)(unsigned char)va_arg( status->arg, int );
419                     break;
420                 case E_short:
421                     value = (uintmax_t)(unsigned short)va_arg( status->arg, int );
422                     break;
423                 case 0:
424                     value = (uintmax_t)va_arg( status->arg, unsigned int );
425                     break;
426                 case E_long:
427                     value = (uintmax_t)va_arg( status->arg, unsigned long );
428                     break;
429                 case E_llong:
430                     value = (uintmax_t)va_arg( status->arg, unsigned long long );
431                     break;
432                 case E_size:
433                     value = (uintmax_t)va_arg( status->arg, size_t );
434                     break;
435             }
436             ++(status->this);
437             if ( ( value / status->base ) != 0 )
438             {
439                 int2base( (intmax_t)(value / status->base), status );
440             }
441             int digit = value % status->base;
442             if ( digit < 0 )
443             {
444                 digit *= -1;
445             }
446             if ( status->flags & E_lower )
447             {
448                 DELIVER( _PDCLIB_digits[ digit ] );
449             }
450             else
451             {
452                 DELIVER( _PDCLIB_Xdigits[ digit ] );
453             }
454         }
455         else
456         {
457             switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax ) )
458             {
459                 case E_char:
460                     int2base( (intmax_t)(char)va_arg( status->arg, int ), status );
461                     break;
462                 case E_short:
463                     int2base( (intmax_t)(short)va_arg( status->arg, int ), status );
464                     break;
465                 case 0:
466                     int2base( (intmax_t)va_arg( status->arg, int ), status );
467                     break;
468                 case E_long:
469                     int2base( (intmax_t)va_arg( status->arg, long ), status );
470                     break;
471                 case E_llong:
472                     int2base( (intmax_t)va_arg( status->arg, long long ), status );
473                     break;
474                 case E_ptrdiff:
475                     int2base( (intmax_t)va_arg( status->arg, ptrdiff_t ), status );
476                     break;
477                 case E_intmax:
478                     int2base( va_arg( status->arg, intmax_t ), status );
479                     break;
480             }
481         }
482         if ( status->flags & E_minus )
483         {
484             while ( status->this < status->width )
485             {
486                 DELIVER( ' ' );
487                 ++(status->this);
488             }
489         }
490         if ( status->i >= status->n )
491         {
492             status->s[status->n - 1] = '\0';
493         }
494     }
495     return ++spec;
496 }
497
498 #ifdef TEST
499 #include <_PDCLIB_test.h>
500
501 #include <limits.h>
502 #include <string.h>
503
504 static int testprintf( char * buffer, size_t n, const char * format, ... )
505 {
506     /* Members: base, flags, n, i, this, s, width, prec, stream, arg         */
507     struct _PDCLIB_status_t status = { 0, 0, n, 0, 0, buffer, 0, 0, NULL, NULL };
508     memset( buffer, '\0', 100 );
509     va_start( status.arg, format );
510     if ( *(_PDCLIB_print( format, &status )) != '\0' )
511     {
512         printf( "_PDCLIB_print() did not return end-of-specifier on '%s'.\n", format );
513         ++rc;
514     }
515     va_end( status.arg );
516     return status.i;
517 }
518
519 int main( void )
520 {
521     char buffer[100];
522     TESTCASE( testprintf( buffer, 100, "%hhd", CHAR_MIN ) == 4 );
523     TESTCASE( strcmp( buffer, "-128" ) == 0 );
524     TESTCASE( testprintf( buffer, 100, "%hhd", CHAR_MAX ) == 3 );
525     TESTCASE( strcmp( buffer, "127" ) == 0 );
526     TESTCASE( testprintf( buffer, 100, "%hhd", 0 ) == 1 );
527     TESTCASE( strcmp( buffer, "0" ) == 0 );
528     TESTCASE( testprintf( buffer, 100, "%hd", SHRT_MIN ) == 6 );
529     TESTCASE( strcmp( buffer, "-32768" ) == 0 );
530     TESTCASE( testprintf( buffer, 100, "%hd", SHRT_MAX ) == 5 );
531     TESTCASE( strcmp( buffer, "32767" ) == 0 );
532     TESTCASE( testprintf( buffer, 100, "%hd", 0 ) == 1 );
533     TESTCASE( strcmp( buffer, "0" ) == 0 );
534     TESTCASE( testprintf( buffer, 100, "%d", INT_MIN ) == 11 );
535     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
536     TESTCASE( testprintf( buffer, 100, "%d", INT_MAX ) == 10 );
537     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
538     TESTCASE( testprintf( buffer, 100, "%d", 0 ) == 1 );
539     TESTCASE( strcmp( buffer, "0" ) == 0 );
540     TESTCASE( testprintf( buffer, 100, "%ld", LONG_MIN ) == 11 );
541     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
542     TESTCASE( testprintf( buffer, 100, "%ld", LONG_MAX ) == 10 );
543     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
544     TESTCASE( testprintf( buffer, 100, "%ld", 0l ) == 1 );
545     TESTCASE( strcmp( buffer, "0" ) == 0 );
546     TESTCASE( testprintf( buffer, 100, "%lld", LLONG_MIN ) == 20 );
547     TESTCASE( strcmp( buffer, "-9223372036854775808" ) == 0 );
548     TESTCASE( testprintf( buffer, 100, "%lld", LLONG_MAX ) == 19 );
549     TESTCASE( strcmp( buffer, "9223372036854775807" ) == 0 );
550     TESTCASE( testprintf( buffer, 100, "%lld", 0ll ) );
551     TESTCASE( strcmp( buffer, "0" ) == 0 );
552     TESTCASE( testprintf( buffer, 100, "%hhu", UCHAR_MAX ) == 3 );
553     TESTCASE( strcmp( buffer, "255" ) == 0 );
554     TESTCASE( testprintf( buffer, 100, "%hhu", (unsigned char)-1 ) == 3 );
555     TESTCASE( strcmp( buffer, "255" ) == 0 );
556     TESTCASE( testprintf( buffer, 100, "%hu", USHRT_MAX ) == 5 );
557     TESTCASE( strcmp( buffer, "65535" ) == 0 );
558     TESTCASE( testprintf( buffer, 100, "%hu", (unsigned short)-1 ) == 5 );
559     TESTCASE( strcmp( buffer, "65535" ) == 0 );
560     TESTCASE( testprintf( buffer, 100, "%u", UINT_MAX ) == 10 );
561     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
562     TESTCASE( testprintf( buffer, 100, "%u", -1u ) == 10 );
563     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
564     TESTCASE( testprintf( buffer, 100, "%lu", ULONG_MAX ) == 10 );
565     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
566     TESTCASE( testprintf( buffer, 100, "%lu", -1ul ) == 10 );
567     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
568     TESTCASE( testprintf( buffer, 100, "%llu", ULLONG_MAX ) == 20 );
569     TESTCASE( strcmp( buffer, "18446744073709551615" ) == 0 );
570     TESTCASE( testprintf( buffer, 100, "%llu", -1ull ) == 20 );
571     TESTCASE( strcmp( buffer, "18446744073709551615" ) == 0 );
572     TESTCASE( testprintf( buffer, 100, "%X", UINT_MAX ) == 8 );
573     TESTCASE( strcmp( buffer, "FFFFFFFF" ) == 0 );
574     TESTCASE( testprintf( buffer, 100, "%#X", -1u ) == 10 );
575     TESTCASE( strcmp( buffer, "0XFFFFFFFF" ) == 0 );
576     TESTCASE( testprintf( buffer, 100, "%x", UINT_MAX ) == 8 );
577     TESTCASE( strcmp( buffer, "ffffffff" ) == 0 );
578     TESTCASE( testprintf( buffer, 100, "%#x", -1u ) == 10 );
579     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
580     TESTCASE( testprintf( buffer, 100, "%o", UINT_MAX ) == 11 );
581     TESTCASE( strcmp( buffer, "37777777777" ) == 0 );
582     TESTCASE( testprintf( buffer, 100, "%#o", -1u ) == 12 );
583     TESTCASE( strcmp( buffer, "037777777777" ) == 0 );
584     TESTCASE( testprintf( buffer, 100, "%+d", INT_MIN ) == 11 );
585     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
586     TESTCASE( testprintf( buffer, 100, "%+d", INT_MAX ) == 11 );
587     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
588     TESTCASE( testprintf( buffer, 100, "%+d", 0 ) == 2 );
589     TESTCASE( strcmp( buffer, "+0" ) == 0 );
590     TESTCASE( testprintf( buffer, 100, "%+u", UINT_MAX ) == 10 );
591     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
592     TESTCASE( testprintf( buffer, 100, "%+u", -1u ) == 10 );
593     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
594     TESTCASE( testprintf( buffer, 100, "% d", INT_MIN ) == 11 );
595     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
596     TESTCASE( testprintf( buffer, 100, "% d", INT_MAX ) == 11 );
597     TESTCASE( strcmp( buffer, " 2147483647" ) == 0 );
598     TESTCASE( testprintf( buffer, 100, "% d", 0 ) == 2 );
599     TESTCASE( strcmp( buffer, " 0" ) == 0 );
600     TESTCASE( testprintf( buffer, 100, "% u", UINT_MAX ) == 10 );
601     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
602     TESTCASE( testprintf( buffer, 100, "% u", -1u ) == 10 );
603     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
604     TESTCASE( testprintf( buffer, 100, "%9d", INT_MIN ) == 11 );
605     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
606     TESTCASE( testprintf( buffer, 100, "%9d", INT_MAX ) == 10 );
607     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
608     TESTCASE( testprintf( buffer, 100, "%10d", INT_MIN ) == 11 );
609     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
610     TESTCASE( testprintf( buffer, 100, "%10d", INT_MAX ) == 10 );
611     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
612     TESTCASE( testprintf( buffer, 100, "%11d", INT_MIN ) == 11 );
613     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
614     TESTCASE( testprintf( buffer, 100, "%11d", INT_MAX ) == 11 );
615     TESTCASE( strcmp( buffer, " 2147483647" ) == 0 );
616     TESTCASE( testprintf( buffer, 100, "%12d", INT_MIN ) == 12 );
617     TESTCASE( strcmp( buffer, " -2147483648" ) == 0 );
618     TESTCASE( testprintf( buffer, 100, "%12d", INT_MAX ) == 12 );
619     TESTCASE( strcmp( buffer, "  2147483647" ) == 0 );
620     TESTCASE( testprintf( buffer, 100, "%-9d", INT_MIN ) == 11 );
621     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
622     TESTCASE( testprintf( buffer, 100, "%-9d", INT_MAX ) == 10 );
623     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
624     TESTCASE( testprintf( buffer, 100, "%-10d", INT_MIN ) == 11 );
625     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
626     TESTCASE( testprintf( buffer, 100, "%-10d", INT_MAX ) == 10 );
627     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
628     TESTCASE( testprintf( buffer, 100, "%-11d", INT_MIN ) == 11 );
629     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
630     TESTCASE( testprintf( buffer, 100, "%-11d", INT_MAX ) == 11 );
631     TESTCASE( strcmp( buffer, "2147483647 " ) == 0 );
632     TESTCASE( testprintf( buffer, 100, "%-12d", INT_MIN ) == 12 );
633     TESTCASE( strcmp( buffer, "-2147483648 " ) == 0 );
634     TESTCASE( testprintf( buffer, 100, "%-12d", INT_MAX ) == 12 );
635     TESTCASE( strcmp( buffer, "2147483647  " ) == 0 );
636     TESTCASE( testprintf( buffer, 100, "%09d", INT_MIN ) == 11 );
637     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
638     TESTCASE( testprintf( buffer, 100, "%09d", INT_MAX ) == 10 );
639     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
640     TESTCASE( testprintf( buffer, 100, "%010d", INT_MIN ) == 11 );
641     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
642     TESTCASE( testprintf( buffer, 100, "%010d", INT_MAX ) == 10 );
643     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
644     TESTCASE( testprintf( buffer, 100, "%011d", INT_MIN ) == 11 );
645     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
646     TESTCASE( testprintf( buffer, 100, "%011d", INT_MAX ) == 11 );
647     TESTCASE( strcmp( buffer, "02147483647" ) == 0 );
648     TESTCASE( testprintf( buffer, 100, "%012d", INT_MIN ) == 12 );
649     TESTCASE( strcmp( buffer, "-02147483648" ) == 0 );
650     TESTCASE( testprintf( buffer, 100, "%012d", INT_MAX ) == 12 );
651     TESTCASE( strcmp( buffer, "002147483647" ) == 0 );
652     TESTCASE( testprintf( buffer, 100, "%-09d", INT_MIN ) == 11 );
653     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
654     TESTCASE( testprintf( buffer, 100, "%-09d", INT_MAX ) == 10 );
655     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
656     TESTCASE( testprintf( buffer, 100, "%-010d", INT_MIN ) == 11 );
657     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
658     TESTCASE( testprintf( buffer, 100, "%-010d", INT_MAX ) == 10 );
659     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
660     TESTCASE( testprintf( buffer, 100, "%-011d", INT_MIN ) == 11 );
661     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
662     TESTCASE( testprintf( buffer, 100, "%-011d", INT_MAX ) == 11 );
663     TESTCASE( strcmp( buffer, "2147483647 " ) == 0 );
664     TESTCASE( testprintf( buffer, 100, "%-012d", INT_MIN ) == 12 );
665     TESTCASE( strcmp( buffer, "-2147483648 " ) == 0 );
666     TESTCASE( testprintf( buffer, 100, "%-012d", INT_MAX ) == 12 );
667     TESTCASE( strcmp( buffer, "2147483647  " ) == 0 );
668     TESTCASE( testprintf( buffer, 8, "%9d", INT_MAX ) == 10 );
669     TESTCASE( strcmp( buffer, "2147483" ) == 0 );
670     TESTCASE( testprintf( buffer, 8, "%9d", INT_MIN ) == 11 );
671     TESTCASE( strcmp( buffer, "-214748" ) == 0 );
672     TESTCASE( testprintf( buffer, 9, "%9d", INT_MAX ) == 10 );
673     TESTCASE( strcmp( buffer, "21474836" ) == 0 );
674     TESTCASE( testprintf( buffer, 9, "%9d", INT_MIN ) == 11 );
675     TESTCASE( strcmp( buffer, "-2147483" ) == 0 );
676     TESTCASE( testprintf( buffer, 10, "%9d", INT_MAX ) == 10 );
677     TESTCASE( strcmp( buffer, "214748364" ) == 0 );
678     TESTCASE( testprintf( buffer, 10, "%9d", INT_MIN ) == 11 );
679     TESTCASE( strcmp( buffer, "-21474836" ) == 0 );
680     TESTCASE( testprintf( buffer, 9, "%10d", INT_MAX ) == 10 );
681     TESTCASE( strcmp( buffer, "21474836" ) == 0 );
682     TESTCASE( testprintf( buffer, 9, "%10d", INT_MIN ) == 11 );
683     TESTCASE( strcmp( buffer, "-2147483" ) == 0 );
684     TESTCASE( testprintf( buffer, 10, "%10d", INT_MAX ) == 10 );
685     TESTCASE( strcmp( buffer, "214748364" ) == 0 );
686     TESTCASE( testprintf( buffer, 10, "%10d", INT_MIN ) == 11 );
687     TESTCASE( strcmp( buffer, "-21474836" ) == 0 );
688     TESTCASE( testprintf( buffer, 11, "%10d", INT_MAX ) == 10 );
689     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
690     TESTCASE( testprintf( buffer, 11, "%10d", INT_MIN ) == 11 );
691     TESTCASE( strcmp( buffer, "-214748364" ) == 0 );
692     TESTCASE( testprintf( buffer, 10, "%11d", INT_MAX ) == 11 );
693     TESTCASE( strcmp( buffer, " 21474836" ) == 0 );
694     TESTCASE( testprintf( buffer, 10, "%11d", INT_MIN ) == 11 );
695     TESTCASE( strcmp( buffer, "-21474836" ) == 0 );
696     TESTCASE( testprintf( buffer, 11, "%11d", INT_MAX ) == 11 );
697     TESTCASE( strcmp( buffer, " 214748364" ) == 0 );
698     TESTCASE( testprintf( buffer, 11, "%11d", INT_MIN ) == 11 );
699     TESTCASE( strcmp( buffer, "-214748364" ) == 0 );
700     TESTCASE( testprintf( buffer, 12, "%11d", INT_MAX ) == 11 );
701     TESTCASE( strcmp( buffer, " 2147483647" ) == 0 );
702     TESTCASE( testprintf( buffer, 12, "%11d", INT_MIN ) == 11 );
703     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
704     TESTCASE( testprintf( buffer, 11, "%12d", INT_MAX ) == 12 );
705     TESTCASE( strcmp( buffer, "  21474836" ) == 0 );
706     TESTCASE( testprintf( buffer, 11, "%12d", INT_MIN ) == 12 );
707     TESTCASE( strcmp( buffer, " -21474836" ) == 0 );
708     TESTCASE( testprintf( buffer, 12, "%12d", INT_MAX ) == 12 );
709     TESTCASE( strcmp( buffer, "  214748364" ) == 0 );
710     TESTCASE( testprintf( buffer, 12, "%12d", INT_MIN ) == 12 );
711     TESTCASE( strcmp( buffer, " -214748364" ) == 0 );
712     TESTCASE( testprintf( buffer, 13, "%12d", INT_MAX ) == 12 );
713     TESTCASE( strcmp( buffer, "  2147483647" ) == 0 );
714     TESTCASE( testprintf( buffer, 13, "%12d", INT_MIN ) == 12 );
715     TESTCASE( strcmp( buffer, " -2147483648" ) == 0 );
716     TESTCASE( testprintf( buffer, 100, "%030.20d", INT_MAX ) == 30 );
717     TESTCASE( strcmp( buffer, "          00000000002147483647" ) == 0 );
718     TESTCASE( testprintf( buffer, 100, "%.6x", UINT_MAX ) == 8 );
719     TESTCASE( strcmp( buffer, "ffffffff" ) == 0 );
720     TESTCASE( testprintf( buffer, 100, "%#6.3x", UINT_MAX ) == 10 );
721     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
722     TESTCASE( testprintf( buffer, 100, "%#3.6x", UINT_MAX ) == 10 );
723     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
724     TESTCASE( testprintf( buffer, 100, "%.6d", INT_MIN ) == 11 );
725     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
726     TESTCASE( testprintf( buffer, 100, "%6.3d", INT_MIN ) == 11 );
727     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
728     TESTCASE( testprintf( buffer, 100, "%3.6d", INT_MIN ) == 11 );
729     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
730     TESTCASE( testprintf( buffer, 100, "%#0.6x", UINT_MAX ) == 10 );
731     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
732     TESTCASE( testprintf( buffer, 100, "%#06.3x", UINT_MAX ) == 10 );
733     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
734     TESTCASE( testprintf( buffer, 100, "%#03.6x", UINT_MAX ) == 10 );
735     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
736     TESTCASE( testprintf( buffer, 100, "%#0.6d", INT_MAX ) == 10 );
737     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
738     TESTCASE( testprintf( buffer, 100, "%#06.3d", INT_MAX ) == 10 );
739     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
740     TESTCASE( testprintf( buffer, 100, "%#03.6d", INT_MAX ) == 10 );
741     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
742     TESTCASE( testprintf( buffer, 100, "%#+.6d", INT_MAX ) == 11 );
743     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
744     TESTCASE( testprintf( buffer, 100, "%#+6.3d", INT_MAX ) == 11 );
745     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
746     TESTCASE( testprintf( buffer, 100, "%#+3.6d", INT_MAX ) == 11 );
747     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
748     TESTCASE( testprintf( buffer, 100, "%+0.6d", INT_MAX ) == 11 );
749     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
750     TESTCASE( testprintf( buffer, 100, "%+06.3d", INT_MAX ) == 11 );
751     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
752     TESTCASE( testprintf( buffer, 100, "%+03.6d", INT_MAX ) == 11 );
753     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
754     TESTCASE( testprintf( buffer, 100, "%c", 'x' ) == 1 );
755     TESTCASE( strcmp( buffer, "x" ) == 0 );
756     TESTCASE( testprintf( buffer, 100, "%s", "abcdef" ) == 6 );
757     TESTCASE( strcmp( buffer, "abcdef" ) == 0 );
758     TESTCASE( testprintf( buffer, 100, "%p", (void *)0xdeadbeef ) == 10 );
759     TESTCASE( strcmp( buffer, "0xdeadbeef" ) == 0 );
760     return TEST_RESULTS;
761 }
762
763 #endif