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