]> pd.if.org Git - pdclib/blob - functions/_PDCLIB/print.c
Intermediate freeze.
[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 ) putc( x, 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                     ++(status->this);
120                 }
121             }
122         }
123         /* Now we did the padding, do the prefixes (if any). */
124         preidx = 0;
125         while ( preface[ preidx ] != '\0' )
126         {
127             DELIVER( preface[ preidx++ ] );
128             ++(status->this);
129         }
130         if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
131         {
132             /* If field is not left aligned, and zero padding is requested, do
133                so.
134             */
135             while ( status->this < status->width )
136             {
137                 DELIVER( '0' );
138                 ++(status->this);
139             }
140         }
141         /* Do the precision padding if necessary. */
142         for ( int i = 0; i < prec_pads; ++i )
143         {
144             DELIVER( '0' );
145         }
146         }
147     }
148     /* Recursion tail - print the current digit. */
149     {
150     int digit = value % status->base;
151     if ( digit < 0 )
152     {
153         digit *= -1;
154     }
155     if ( status->flags & E_lower )
156     {
157         /* Lowercase letters. Same array used for strto...(). */
158         DELIVER( _PDCLIB_digits[ digit ] );
159     }
160     else
161     {
162         /* Uppercase letters. Array only used here, only 0-F. */
163         DELIVER( _PDCLIB_Xdigits[ digit ] );
164     }
165     }
166 }
167
168 const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
169 {
170     const char * orig_spec = spec;
171     if ( *(++spec) == '%' )
172     {
173         /* %% -> print single '%' */
174         DELIVER( *spec );
175         return ++spec;
176     }
177     /* Initializing status structure */
178     status->flags = 0;
179     status->base  = 0;
180     status->this  = 0;
181     status->width = 0;
182     status->prec  = 0;
183
184     /* First come 0..n flags */
185     do
186     {
187         switch ( *spec )
188         {
189             case '-':
190                 /* left-aligned output */
191                 status->flags |= E_minus;
192                 ++spec;
193                 break;
194             case '+':
195                 /* positive numbers prefixed with '+' */
196                 status->flags |= E_plus;
197                 ++spec;
198                 break;
199             case '#':
200                 /* alternative format (leading 0x for hex, 0 for octal) */
201                 status->flags |= E_alt;
202                 ++spec;
203                 break;
204             case ' ':
205                 /* positive numbers prefixed with ' ' */
206                 status->flags |= E_space;
207                 ++spec;
208                 break;
209             case '0':
210                 /* right-aligned padding done with '0' instead of ' ' */
211                 status->flags |= E_zero;
212                 ++spec;
213                 break;
214             default:
215                 /* not a flag, exit flag parsing */
216                 status->flags |= E_done;
217                 break;
218         }
219     } while ( ! ( status->flags & E_done ) );
220
221     /* Optional field width */
222     if ( *spec == '*' )
223     {
224         /* Retrieve width value from argument stack */
225         if ( ( status->width = va_arg( status->arg, int ) ) < 0 )
226         {
227             /* Negative value is '-' flag plus absolute value */
228             status->flags |= E_minus;
229             status->width *= -1;
230         }
231         ++spec;
232     }
233     else
234     {
235         /* If a width is given, strtol() will return its value. If not given,
236            strtol() will return zero. In both cases, endptr will point to the
237            rest of the conversion specifier - just what we need.
238         */
239         status->width = (int)strtol( spec, (char**)&spec, 10 );
240     }
241
242     /* Optional precision */
243     if ( *spec == '.' )
244     {
245         ++spec;
246         if ( *spec == '*' )
247         {
248             /* Retrieve precision value from argument stack. A negative value
249                is as if no precision is given - as precision is initalized to
250                EOF (negative), there is no need for testing for negative here.
251             */
252             status->prec = va_arg( status->arg, int );
253         }
254         else
255         {
256             char * endptr;
257             status->prec = (int)strtol( spec, &endptr, 10 );
258             if ( spec == endptr )
259             {
260                 /* Decimal point but no number - bad conversion specifier. */
261                 return orig_spec;
262             }
263             spec = endptr;
264         }
265         /* Having a precision cancels out any zero flag. */
266         status->flags ^= E_zero;
267     }
268
269     /* Optional length modifier
270        We step one character ahead in any case, and step back only if we find
271        there has been no length modifier (or step ahead another character if it
272        has been "hh" or "ll").
273     */
274     switch ( *(spec++) )
275     {
276         case 'h':
277             if ( *spec == 'h' )
278             {
279                 /* hh -> char */
280                 status->flags |= E_char;
281                 ++spec;
282             }
283             else
284             {
285                 /* h -> short */
286                 status->flags |= E_short;
287             }
288             break;
289         case 'l':
290             if ( *spec == 'l' )
291             {
292                 /* ll -> long long */
293                 status->flags |= E_llong;
294                 ++spec;
295             }
296             else
297             {
298                 /* k -> long */
299                 status->flags |= E_long;
300             }
301             break;
302         case 'j':
303             /* j -> intmax_t, which might or might not be long long */
304             status->flags |= E_intmax;
305             break;
306         case 'z':
307             /* z -> size_t, which might or might not be unsigned int */
308             status->flags |= E_size;
309             break;
310         case 't':
311             /* t -> ptrdiff_t, which might or might not be long */
312             status->flags |= E_ptrdiff;
313             break;
314         case 'L':
315             /* L -> long double */
316             status->flags |= E_ldouble;
317             break;
318         default:
319             --spec;
320             break;
321     }
322
323     /* Conversion specifier */
324     switch ( *spec )
325     {
326         case 'd':
327             /* FALLTHROUGH */
328         case 'i':
329             status->base = 10;
330             break;
331         case 'o':
332             status->base = 8;
333             status->flags |= E_unsigned;
334             break;
335         case 'u':
336             status->base = 10;
337             status->flags |= E_unsigned;
338             break;
339         case 'x':
340             status->base = 16;
341             status->flags |= ( E_lower | E_unsigned );
342             break;
343         case 'X':
344             status->base = 16;
345             status->flags |= E_unsigned;
346             break;
347         case 'f':
348         case 'F':
349         case 'e':
350         case 'E':
351         case 'g':
352         case 'G':
353             break;
354         case 'a':
355         case 'A':
356             break;
357         case 'c':
358             /* TODO: Flags, wide chars. */
359             DELIVER( va_arg( status->arg, int ) );
360             return ++spec;
361         case 's':
362             /* TODO: Flags, wide chars. */
363             {
364                 char * s = va_arg( status->arg, char * );
365                 while ( *s != '\0' )
366                 {
367                     DELIVER( *(s++) );
368                 }
369                 return ++spec;
370             }
371         case 'p':
372             /* TODO: E_long -> E_intptr */
373             status->base = 16;
374             status->flags |= ( E_lower | E_unsigned | E_alt | E_long );
375             break;
376         case 'n':
377            {
378                int * val = va_arg( status->arg, int * );
379                *val = status->i;
380                return ++spec;
381            }
382         default:
383             /* No conversion specifier. Bad conversion. */
384             return orig_spec;
385     }
386
387     /* Do the actual output based on our findings */
388     if ( status->base != 0 )
389     {
390         /* Integer conversions */
391         /* TODO: Check for invalid flag combinations. */
392         if ( status->flags & E_unsigned )
393         {
394             uintmax_t value;
395             switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_size ) )
396             {
397                 case E_char:
398                     value = (uintmax_t)(unsigned char)va_arg( status->arg, int );
399                     break;
400                 case E_short:
401                     value = (uintmax_t)(unsigned short)va_arg( status->arg, int );
402                     break;
403                 case 0:
404                     value = (uintmax_t)va_arg( status->arg, unsigned int );
405                     break;
406                 case E_long:
407                     value = (uintmax_t)va_arg( status->arg, unsigned long );
408                     break;
409                 case E_llong:
410                     value = (uintmax_t)va_arg( status->arg, unsigned long long );
411                     break;
412                 case E_size:
413                     value = (uintmax_t)va_arg( status->arg, size_t );
414                     break;
415             }
416             ++(status->this);
417             if ( ( value / status->base ) != 0 )
418             {
419                 int2base( (intmax_t)(value / status->base), status );
420             }
421             int digit = value % status->base;
422             if ( digit < 0 )
423             {
424                 digit *= -1;
425             }
426             if ( status->flags & E_lower )
427             {
428                 DELIVER( _PDCLIB_digits[ digit ] );
429             }
430             else
431             {
432                 DELIVER( _PDCLIB_Xdigits[ digit ] );
433             }
434         }
435         else
436         {
437             switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax ) )
438             {
439                 case E_char:
440                     int2base( (intmax_t)(char)va_arg( status->arg, int ), status );
441                     break;
442                 case E_short:
443                     int2base( (intmax_t)(short)va_arg( status->arg, int ), status );
444                     break;
445                 case 0:
446                     int2base( (intmax_t)va_arg( status->arg, int ), status );
447                     break;
448                 case E_long:
449                     int2base( (intmax_t)va_arg( status->arg, long ), status );
450                     break;
451                 case E_llong:
452                     int2base( (intmax_t)va_arg( status->arg, long long ), status );
453                     break;
454                 case E_ptrdiff:
455                     int2base( (intmax_t)va_arg( status->arg, ptrdiff_t ), status );
456                     break;
457                 case E_intmax:
458                     int2base( va_arg( status->arg, intmax_t ), status );
459                     break;
460             }
461         }
462         if ( status->flags & E_minus )
463         {
464             while ( status->this < status->width )
465             {
466                 DELIVER( ' ' );
467                 ++(status->this);
468             }
469         }
470         if ( status->i >= status->n )
471         {
472             status->s[status->n - 1] = '\0';
473         }
474     }
475     return ++spec;
476 }
477
478 #ifdef TEST
479 #include <_PDCLIB_test.h>
480
481 #include <limits.h>
482 #include <string.h>
483
484 int testprintf( char * buffer, size_t n, const char * format, ... )
485 {
486     /* Members: base, flags, n, i, this, s, width, prec, stream, arg         */
487     struct _PDCLIB_status_t status = { 0, 0, n, 0, 0, buffer, 0, 0, NULL, NULL };
488     va_start( status.arg, format );
489     if ( *(_PDCLIB_print( format, &status )) != '\0' )
490     {
491         printf( "_PDCLIB_print() did not return end-of-specifier on '%s'.\n", format );
492         ++rc;
493     }
494     va_end( status.arg );
495     return status.this;
496 }
497
498 int main( void )
499 {
500     char buffer[100];
501     TESTCASE( testprintf( buffer, 100, "%hhd", CHAR_MIN ) == 4 );
502     TESTCASE( strcmp( buffer, "-128" ) == 0 );
503     puts( buffer );
504     TESTCASE( testprintf( buffer, 100, "%hhd", CHAR_MAX ) == 3 );
505     TESTCASE( strcmp( buffer, "127" ) == 0 );
506     puts( buffer );
507     TESTCASE( testprintf( buffer, 100, "%hhd", 0 ) == 1 );
508     TESTCASE( strcmp( buffer, "0" ) == 0 );
509     puts( buffer );
510     TESTCASE( testprintf( buffer, 100, "%hd", SHRT_MIN ) == 6 );
511     TESTCASE( strcmp( buffer, "-32768" ) == 0 );
512     puts( buffer );
513     TESTCASE( testprintf( buffer, 100, "%hd", SHRT_MAX ) == 5 );
514     TESTCASE( strcmp( buffer, "32767" ) == 0 );
515     puts( buffer );
516     TESTCASE( testprintf( buffer, 100, "%hd", 0 ) == 1 );
517     TESTCASE( strcmp( buffer, "0" ) == 0 );
518     puts( buffer );
519     TESTCASE( testprintf( buffer, 100, "%d", INT_MIN ) == 11 );
520     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
521     puts( buffer );
522     TESTCASE( testprintf( buffer, 100, "%d", INT_MAX ) == 10 );
523     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
524     puts( buffer );
525     TESTCASE( testprintf( buffer, 100, "%d", 0 ) == 1 );
526     TESTCASE( strcmp( buffer, "0" ) == 0 );
527     puts( buffer );
528     TESTCASE( testprintf( buffer, 100, "%ld", LONG_MIN ) == 11 );
529     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
530     puts( buffer );
531     TESTCASE( testprintf( buffer, 100, "%ld", LONG_MAX ) == 10 );
532     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
533     puts( buffer );
534     TESTCASE( testprintf( buffer, 100, "%ld", 0l ) == 1 );
535     TESTCASE( strcmp( buffer, "0" ) == 0 );
536     puts( buffer );
537     TESTCASE( testprintf( buffer, 100, "%lld", LLONG_MIN ) == 20 );
538     TESTCASE( strcmp( buffer, "-9223372036854775808" ) == 0 );
539     puts( buffer );
540     TESTCASE( testprintf( buffer, 100, "%lld", LLONG_MAX ) == 19 );
541     TESTCASE( strcmp( buffer, "9223372036854775807" ) == 0 );
542     puts( buffer );
543     TESTCASE( testprintf( buffer, 100, "%lld", 0ll ) );
544     TESTCASE( strcmp( buffer, "0" ) == 0 );
545     puts( buffer );
546     TESTCASE( testprintf( buffer, 100, "%hhu", UCHAR_MAX ) == 3 );
547     TESTCASE( strcmp( buffer, "255" ) == 0 );
548     puts( buffer );
549     TESTCASE( testprintf( buffer, 100, "%hhu", (unsigned char)-1 ) == 3 );
550     TESTCASE( strcmp( buffer, "255" ) == 0 );
551     puts( buffer );
552     TESTCASE( testprintf( buffer, 100, "%hu", USHRT_MAX ) == 5 );
553     TESTCASE( strcmp( buffer, "65535" ) == 0 );
554     puts( buffer );
555     TESTCASE( testprintf( buffer, 100, "%hu", (unsigned short)-1 ) == 5 );
556     TESTCASE( strcmp( buffer, "65535" ) == 0 );
557     puts( buffer );
558     TESTCASE( testprintf( buffer, 100, "%u", UINT_MAX ) == 10 );
559     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
560     puts( buffer );
561     TESTCASE( testprintf( buffer, 100, "%u", -1u ) == 10 );
562     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
563     puts( buffer );
564     TESTCASE( testprintf( buffer, 100, "%lu", ULONG_MAX ) == 10 );
565     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
566     puts( buffer );
567     TESTCASE( testprintf( buffer, 100, "%lu", -1ul ) == 10 );
568     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
569     puts( buffer );
570     TESTCASE( testprintf( buffer, 100, "%llu", ULLONG_MAX ) == 20 );
571     TESTCASE( strcmp( buffer, "18446744073709551615" ) == 0 );
572     puts( buffer );
573     TESTCASE( testprintf( buffer, 100, "%llu", -1ull ) == 20 );
574     TESTCASE( strcmp( buffer, "18446744073709551615" ) == 0 );
575     puts( buffer );
576     TESTCASE( testprintf( buffer, 100, "%X", UINT_MAX ) == 8 );
577     TESTCASE( strcmp( buffer, "FFFFFFFF" ) == 0 );
578     puts( buffer );
579     TESTCASE( testprintf( buffer, 100, "%#X", -1u ) == 10 );
580     TESTCASE( strcmp( buffer, "0XFFFFFFFF" ) == 0 );
581     puts( buffer );
582     TESTCASE( testprintf( buffer, 100, "%x", UINT_MAX ) == 8 );
583     TESTCASE( strcmp( buffer, "ffffffff" ) == 0 );
584     puts( buffer );
585     TESTCASE( testprintf( buffer, 100, "%#x", -1u ) == 10 );
586     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
587     puts( buffer );
588     TESTCASE( testprintf( buffer, 100, "%o", UINT_MAX ) == 11 );
589     TESTCASE( strcmp( buffer, "37777777777" ) == 0 );
590     puts( buffer );
591     TESTCASE( testprintf( buffer, 100, "%#o", -1u ) == 12 );
592     TESTCASE( strcmp( buffer, "037777777777" ) == 0 );
593     puts( buffer );
594     /* TODO: This test case is broken, doesn't test what it was intended to. */
595     TESTCASE( testprintf( buffer, 100, "%.0#o", 0 ) == 5 );
596     TESTCASE( strcmp( buffer, "%.0#o" ) == 0 );
597     puts( buffer );
598     TESTCASE( testprintf( buffer, 100, "%+d", INT_MIN ) == 11 );
599     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
600     puts( buffer );
601     TESTCASE( testprintf( buffer, 100, "%+d", INT_MAX ) == 11 );
602     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
603     puts( buffer );
604     TESTCASE( testprintf( buffer, 100, "%+d", 0 ) == 2 );
605     TESTCASE( strcmp( buffer, "+0" ) == 0 );
606     puts( buffer );
607     TESTCASE( testprintf( buffer, 100, "%+u", UINT_MAX ) == 10 );
608     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
609     puts( buffer );
610     TESTCASE( testprintf( buffer, 100, "%+u", -1u ) == 10 );
611     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
612     puts( buffer );
613     TESTCASE( testprintf( buffer, 100, "% d", INT_MIN ) == 11 );
614     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
615     puts( buffer );
616     TESTCASE( testprintf( buffer, 100, "% d", INT_MAX ) == 11 );
617     TESTCASE( strcmp( buffer, " 2147483647" ) == 0 );
618     puts( buffer );
619     TESTCASE( testprintf( buffer, 100, "% d", 0 ) == 2 );
620     TESTCASE( strcmp( buffer, " 0" ) == 0 );
621     puts( buffer );
622     TESTCASE( testprintf( buffer, 100, "% u", UINT_MAX ) == 10 );
623     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
624     puts( buffer );
625     TESTCASE( testprintf( buffer, 100, "% u", -1u ) == 10 );
626     TESTCASE( strcmp( buffer, "4294967295" ) == 0 );
627     puts( buffer );
628     TESTCASE( testprintf( buffer, 100, "%9d", INT_MIN ) == 11 );
629     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
630     puts( buffer );
631     TESTCASE( testprintf( buffer, 100, "%9d", INT_MAX ) == 10 );
632     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
633     puts( buffer );
634     TESTCASE( testprintf( buffer, 100, "%10d", INT_MIN ) == 11 );
635     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
636     puts( buffer );
637     TESTCASE( testprintf( buffer, 100, "%10d", INT_MAX ) == 10 );
638     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
639     puts( buffer );
640     TESTCASE( testprintf( buffer, 100, "%11d", INT_MIN ) == 11 );
641     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
642     puts( buffer );
643     TESTCASE( testprintf( buffer, 100, "%11d", INT_MAX ) == 11 );
644     TESTCASE( strcmp( buffer, " 2147483647" ) == 0 );
645     puts( buffer );
646     TESTCASE( testprintf( buffer, 100, "%12d", INT_MIN ) == 12 );
647     TESTCASE( strcmp( buffer, " -2147483648" ) == 0 );
648     puts( buffer );
649     TESTCASE( testprintf( buffer, 100, "%12d", INT_MAX ) == 12 );
650     TESTCASE( strcmp( buffer, "  2147483647" ) == 0 );
651     puts( buffer );
652     TESTCASE( testprintf( buffer, 100, "%-9d", INT_MIN ) == 11 );
653     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
654     puts( buffer );
655     TESTCASE( testprintf( buffer, 100, "%-9d", INT_MAX ) == 10 );
656     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
657     puts( buffer );
658     TESTCASE( testprintf( buffer, 100, "%-10d", INT_MIN ) == 11 );
659     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
660     puts( buffer );
661     TESTCASE( testprintf( buffer, 100, "%-10d", INT_MAX ) == 10 );
662     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
663     puts( buffer );
664     TESTCASE( testprintf( buffer, 100, "%-11d", INT_MIN ) == 11 );
665     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
666     puts( buffer );
667     TESTCASE( testprintf( buffer, 100, "%-11d", INT_MAX ) == 11 );
668     TESTCASE( strcmp( buffer, "2147483647 " ) == 0 );
669     puts( buffer );
670     TESTCASE( testprintf( buffer, 100, "%-12d", INT_MIN ) == 12 );
671     TESTCASE( strcmp( buffer, "-2147483648 " ) == 0 );
672     puts( buffer );
673     TESTCASE( testprintf( buffer, 100, "%-12d", INT_MAX ) == 12 );
674     TESTCASE( strcmp( buffer, "2147483647  " ) == 0 );
675     puts( buffer );
676     TESTCASE( testprintf( buffer, 100, "%09d", INT_MIN ) == 11 );
677     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
678     puts( buffer );
679     TESTCASE( testprintf( buffer, 100, "%09d", INT_MAX ) == 10 );
680     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
681     puts( buffer );
682     TESTCASE( testprintf( buffer, 100, "%010d", INT_MIN ) == 11 );
683     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
684     puts( buffer );
685     TESTCASE( testprintf( buffer, 100, "%010d", INT_MAX ) == 10 );
686     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
687     puts( buffer );
688     TESTCASE( testprintf( buffer, 100, "%011d", INT_MIN ) == 11 );
689     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
690     puts( buffer );
691     TESTCASE( testprintf( buffer, 100, "%011d", INT_MAX ) == 11 );
692     TESTCASE( strcmp( buffer, "02147483647" ) == 0 );
693     puts( buffer );
694     TESTCASE( testprintf( buffer, 100, "%012d", INT_MIN ) == 12 );
695     TESTCASE( strcmp( buffer, "-02147483648" ) == 0 );
696     puts( buffer );
697     TESTCASE( testprintf( buffer, 100, "%012d", INT_MAX ) == 12 );
698     TESTCASE( strcmp( buffer, "002147483647" ) == 0 );
699     puts( buffer );
700     TESTCASE( testprintf( buffer, 100, "%-09d", INT_MIN ) == 11 );
701     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
702     puts( buffer );
703     TESTCASE( testprintf( buffer, 100, "%-09d", INT_MAX ) == 10 );
704     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
705     puts( buffer );
706     TESTCASE( testprintf( buffer, 100, "%-010d", INT_MIN ) == 11 );
707     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
708     puts( buffer );
709     TESTCASE( testprintf( buffer, 100, "%-010d", INT_MAX ) == 10 );
710     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
711     puts( buffer );
712     TESTCASE( testprintf( buffer, 100, "%-011d", INT_MIN ) == 11 );
713     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
714     puts( buffer );
715     TESTCASE( testprintf( buffer, 100, "%-011d", INT_MAX ) == 11 );
716     TESTCASE( strcmp( buffer, "2147483647 " ) == 0 );
717     puts( buffer );
718     TESTCASE( testprintf( buffer, 100, "%-012d", INT_MIN ) == 12 );
719     TESTCASE( strcmp( buffer, "-2147483648 " ) == 0 );
720     puts( buffer );
721     TESTCASE( testprintf( buffer, 100, "%-012d", INT_MAX ) == 12 );
722     TESTCASE( strcmp( buffer, "2147483647  " ) == 0 );
723     puts( buffer );
724     TESTCASE( testprintf( buffer, 8, "%9d", INT_MAX ) == 10 );
725     TESTCASE( strcmp( buffer, "2147483" ) == 0 );
726     puts( buffer );
727     TESTCASE( testprintf( buffer, 8, "%9d", INT_MIN ) == 11 );
728     TESTCASE( strcmp( buffer, "-214748" ) == 0 );
729     puts( buffer );
730     TESTCASE( testprintf( buffer, 9, "%9d", INT_MAX ) == 10 );
731     TESTCASE( strcmp( buffer, "21474836" ) == 0 );
732     puts( buffer );
733     TESTCASE( testprintf( buffer, 9, "%9d", INT_MIN ) == 11 );
734     TESTCASE( strcmp( buffer, "-2147483" ) == 0 );
735     puts( buffer );
736     TESTCASE( testprintf( buffer, 10, "%9d", INT_MAX ) == 10 );
737     TESTCASE( strcmp( buffer, "214748364" ) == 0 );
738     puts( buffer );
739     TESTCASE( testprintf( buffer, 10, "%9d", INT_MIN ) == 11 );
740     TESTCASE( strcmp( buffer, "-21474836" ) == 0 );
741     puts( buffer );
742     TESTCASE( testprintf( buffer, 9, "%10d", INT_MAX ) == 10 );
743     TESTCASE( strcmp( buffer, "21474836" ) == 0 );
744     puts( buffer );
745     TESTCASE( testprintf( buffer, 9, "%10d", INT_MIN ) == 11 );
746     TESTCASE( strcmp( buffer, "-2147483" ) == 0 );
747     puts( buffer );
748     TESTCASE( testprintf( buffer, 10, "%10d", INT_MAX ) == 10 );
749     TESTCASE( strcmp( buffer, "214748364" ) == 0 );
750     puts( buffer );
751     TESTCASE( testprintf( buffer, 10, "%10d", INT_MIN ) == 11 );
752     TESTCASE( strcmp( buffer, "-21474836" ) == 0 );
753     puts( buffer );
754     TESTCASE( testprintf( buffer, 11, "%10d", INT_MAX ) == 10 );
755     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
756     puts( buffer );
757     TESTCASE( testprintf( buffer, 11, "%10d", INT_MIN ) == 11 );
758     TESTCASE( strcmp( buffer, "-214748364" ) == 0 );
759     puts( buffer );
760     TESTCASE( testprintf( buffer, 10, "%11d", INT_MAX ) == 11 );
761     TESTCASE( strcmp( buffer, " 21474836" ) == 0 );
762     puts( buffer );
763     TESTCASE( testprintf( buffer, 10, "%11d", INT_MIN ) == 11 );
764     TESTCASE( strcmp( buffer, "-21474836" ) == 0 );
765     puts( buffer );
766     TESTCASE( testprintf( buffer, 11, "%11d", INT_MAX ) == 11 );
767     TESTCASE( strcmp( buffer, " 214748364" ) == 0 );
768     puts( buffer );
769     TESTCASE( testprintf( buffer, 11, "%11d", INT_MIN ) == 11 );
770     TESTCASE( strcmp( buffer, "-214748364" ) == 0 );
771     puts( buffer );
772     TESTCASE( testprintf( buffer, 12, "%11d", INT_MAX ) == 11 );
773     TESTCASE( strcmp( buffer, " 2147483647" ) == 0 );
774     puts( buffer );
775     TESTCASE( testprintf( buffer, 12, "%11d", INT_MIN ) == 11 );
776     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
777     puts( buffer );
778     TESTCASE( testprintf( buffer, 11, "%12d", INT_MAX ) == 12 );
779     TESTCASE( strcmp( buffer, "  21474836" ) == 0 );
780     puts( buffer );
781     TESTCASE( testprintf( buffer, 11, "%12d", INT_MIN ) == 12 );
782     TESTCASE( strcmp( buffer, " -21474836" ) == 0 );
783     puts( buffer );
784     TESTCASE( testprintf( buffer, 12, "%12d", INT_MAX ) == 12 );
785     TESTCASE( strcmp( buffer, "  214748364" ) == 0 );
786     puts( buffer );
787     TESTCASE( testprintf( buffer, 12, "%12d", INT_MIN ) == 12 );
788     TESTCASE( strcmp( buffer, " -214748364" ) == 0 );
789     puts( buffer );
790     TESTCASE( testprintf( buffer, 13, "%12d", INT_MAX ) == 12 );
791     TESTCASE( strcmp( buffer, "  2147483647" ) == 0 );
792     puts( buffer );
793     TESTCASE( testprintf( buffer, 13, "%12d", INT_MIN ) == 12 );
794     TESTCASE( strcmp( buffer, " -2147483648" ) == 0 );
795     puts( buffer );
796     TESTCASE( testprintf( buffer, 100, "%030.20d", INT_MAX ) == 30 );
797     TESTCASE( strcmp( buffer, "          00000000002147483647" ) == 0 );
798     puts( buffer );
799     TESTCASE( testprintf( buffer, 100, "%.6x", UINT_MAX ) == 8 );
800     TESTCASE( strcmp( buffer, "ffffffff" ) == 0 );
801     puts( buffer );
802     TESTCASE( testprintf( buffer, 100, "%#6.3x", UINT_MAX ) == 10 );
803     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
804     puts( buffer );
805     TESTCASE( testprintf( buffer, 100, "%#3.6x", UINT_MAX ) == 10 );
806     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
807     puts( buffer );
808     TESTCASE( testprintf( buffer, 100, "%.6d", INT_MIN ) == 11 );
809     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
810     puts( buffer );
811     TESTCASE( testprintf( buffer, 100, "%6.3d", INT_MIN ) == 11 );
812     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
813     puts( buffer );
814     TESTCASE( testprintf( buffer, 100, "%3.6d", INT_MIN ) == 11 );
815     TESTCASE( strcmp( buffer, "-2147483648" ) == 0 );
816     puts( buffer );
817     TESTCASE( testprintf( buffer, 100, "%#0.6x", UINT_MAX ) == 10 );
818     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
819     puts( buffer );
820     TESTCASE( testprintf( buffer, 100, "%#06.3x", UINT_MAX ) == 10 );
821     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
822     puts( buffer );
823     TESTCASE( testprintf( buffer, 100, "%#03.6x", UINT_MAX ) == 10 );
824     TESTCASE( strcmp( buffer, "0xffffffff" ) == 0 );
825     puts( buffer );
826     TESTCASE( testprintf( buffer, 100, "%#0.6d", INT_MAX ) == 10 );
827     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
828     puts( buffer );
829     TESTCASE( testprintf( buffer, 100, "%#06.3d", INT_MAX ) == 10 );
830     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
831     puts( buffer );
832     TESTCASE( testprintf( buffer, 100, "%#03.6d", INT_MAX ) == 10 );
833     TESTCASE( strcmp( buffer, "2147483647" ) == 0 );
834     puts( buffer );
835     TESTCASE( testprintf( buffer, 100, "%#+.6d", INT_MAX ) == 11 );
836     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
837     puts( buffer );
838     TESTCASE( testprintf( buffer, 100, "%#+6.3d", INT_MAX ) == 11 );
839     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
840     puts( buffer );
841     TESTCASE( testprintf( buffer, 100, "%#+3.6d", INT_MAX ) == 11 );
842     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
843     puts( buffer );
844     TESTCASE( testprintf( buffer, 100, "%+0.6d", INT_MAX ) == 11 );
845     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
846     puts( buffer );
847     TESTCASE( testprintf( buffer, 100, "%+06.3d", INT_MAX ) == 11 );
848     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
849     puts( buffer );
850     TESTCASE( testprintf( buffer, 100, "%+03.6d", INT_MAX ) == 11 );
851     TESTCASE( strcmp( buffer, "+2147483647" ) == 0 );
852     puts( buffer );
853     TESTCASE( testprintf( buffer, 100, "%c", 'x' ) == 1 );
854     TESTCASE( strcmp( buffer, "x" ) == 0 );
855     puts( buffer );
856     TESTCASE( testprintf( buffer, 100, "%s", "abcdef" ) == 6 );
857     TESTCASE( strcmp( buffer, "abcdef" ) == 0 );
858     puts( buffer );
859     TESTCASE( testprintf( buffer, 100, "%p", (void *)0xdeadbeef ) == 10 );
860     TESTCASE( strcmp( buffer, "0xdeadbeef" ) == 0 );
861     puts( buffer );
862     {
863         int val1, val2;
864         TESTCASE( testprintf( buffer, 100, "123456%n789%n", &val1, &val2 ) == 9 );
865         TESTCASE( strcmp( buffer, "123456789" ) == 0 );
866         puts( buffer );
867         TESTCASE( val1 == 6 );
868         TESTCASE( val2 == 9 );
869     }    return TEST_RESULTS;
870 }
871
872 #endif