port-work; won't compile or even work
[ppcskel.git] / printf.c
1 /*
2  * Copyright (c) 1995 Patrick Powell.
3  *
4  * This code is based on code written by Patrick Powell <papowell@astart.com>.
5  * It may be used for any purpose as long as this notice remains intact on all
6  * source code distributions.
7  */
8
9 /*
10  * Copyright (c) 2008 Holger Weiss.
11  *
12  * This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
13  * My changes to the code may freely be used, modified and/or redistributed for
14  * any purpose.  It would be nice if additions and fixes to this file (including
15  * trivial code cleanups) would be sent back in order to let me include them in
16  * the version available at <http://www.jhweiss.de/software/snprintf.html>.
17  * However, this is not a requirement for using or redistributing (possibly
18  * modified) versions of this file, nor is leaving this notice intact mandatory.
19  */
20
21 /*
22  * History
23  *
24  * 2009-03-05 Hector Martin <hector@marcansoft.com>
25  *
26  *      Hacked up and removed a lot of stuff including floating-point support,
27  *      a bunch of ifs and defines, locales, and tests
28  *
29  * 2008-01-20 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.1:
30  *
31  *      Fixed the detection of infinite floating point values on IRIX (and
32  *      possibly other systems) and applied another few minor cleanups.
33  *
34  * 2008-01-06 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.0:
35  *
36  *      Added a lot of new features, fixed many bugs, and incorporated various
37  *      improvements done by Andrew Tridgell <tridge@samba.org>, Russ Allbery
38  *      <rra@stanford.edu>, Hrvoje Niksic <hniksic@xemacs.org>, Damien Miller
39  *      <djm@mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH
40  *      projects.  The additions include: support the "e", "E", "g", "G", and
41  *      "F" conversion specifiers (and use conversion style "f" or "F" for the
42  *      still unsupported "a" and "A" specifiers); support the "hh", "ll", "j",
43  *      "t", and "z" length modifiers; support the "#" flag and the (non-C99)
44  *      "'" flag; use localeconv(3) (if available) to get both the current
45  *      locale's decimal point character and the separator between groups of
46  *      digits; fix the handling of various corner cases of field width and
47  *      precision specifications; fix various floating point conversion bugs;
48  *      handle infinite and NaN floating point values; don't attempt to write to
49  *      the output buffer (which may be NULL) if a size of zero was specified;
50  *      check for integer overflow of the field width, precision, and return
51  *      values and during the floating point conversion; use the OUTCHAR() macro
52  *      instead of a function for better performance; provide asprintf(3) and
53  *      vasprintf(3) functions; add new test cases.  The replacement functions
54  *      have been renamed to use an "rpl_" prefix, the function calls in the
55  *      main project (and in this file) must be redefined accordingly for each
56  *      replacement function which is needed (by using Autoconf or other means).
57  *      Various other minor improvements have been applied and the coding style
58  *      was cleaned up for consistency.
59  *
60  * 2007-07-23 Holger Weiss <holger@jhweiss.de> for Mutt 1.5.13:
61  *
62  *      C99 compliant snprintf(3) and vsnprintf(3) functions return the number
63  *      of characters that would have been written to a sufficiently sized
64  *      buffer (excluding the '\0').  The original code simply returned the
65  *      length of the resulting output string, so that's been fixed.
66  *
67  * 1998-03-05 Michael Elkins <me@mutt.org> for Mutt 0.90.8:
68  *
69  *      The original code assumed that both snprintf(3) and vsnprintf(3) were
70  *      missing.  Some systems only have snprintf(3) but not vsnprintf(3), so
71  *      the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
72  *
73  * 1998-01-27 Thomas Roessler <roessler@does-not-exist.org> for Mutt 0.89i:
74  *
75  *      The PGP code was using unsigned hexadecimal formats.  Unfortunately,
76  *      unsigned formats simply didn't work.
77  *
78  * 1997-10-22 Brandon Long <blong@fiction.net> for Mutt 0.87.1:
79  *
80  *      Ok, added some minimal floating point support, which means this probably
81  *      requires libm on most operating systems.  Don't yet support the exponent
82  *      (e,E) and sigfig (g,G).  Also, fmtint() was pretty badly broken, it just
83  *      wasn't being exercised in ways which showed it, so that's been fixed.
84  *      Also, formatted the code to Mutt conventions, and removed dead code left
85  *      over from the original.  Also, there is now a builtin-test, run with:
86  *      gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf
87  *
88  * 2996-09-15 Brandon Long <blong@fiction.net> for Mutt 0.43:
89  *
90  *      This was ugly.  It is still ugly.  I opted out of floating point
91  *      numbers, but the formatter understands just about everything from the
92  *      normal C string format, at least as far as I can tell from the Solaris
93  *      2.5 printf(3S) man page.
94  */
95
96 #include "types.h"
97
98 #include <limits.h>
99 #include <stdarg.h>
100
101 #define VA_START(ap, last) va_start(ap, last)
102 #define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */
103
104 #if HAVE_INTTYPES_H
105 #include <inttypes.h>   /* For intmax_t (if not defined in <stdint.h>). */
106 #endif  /* HAVE_INTTYPES_H */
107
108 #if HAVE_STDDEF_H
109 #include <stddef.h>     /* For ptrdiff_t. */
110 #endif  /* HAVE_STDDEF_H */
111
112 #if HAVE_STDINT_H
113 #include <stdint.h>     /* For intmax_t. */
114 #endif  /* HAVE_STDINT_H */
115
116 /* Support for unsigned long long int.  We may also need ULLONG_MAX. */
117 #ifndef ULONG_MAX       /* We may need ULONG_MAX as a fallback. */
118 #ifdef UINT_MAX
119 #define ULONG_MAX UINT_MAX
120 #else
121 #define ULONG_MAX INT_MAX
122 #endif  /* defined(UINT_MAX) */
123 #endif  /* !defined(ULONG_MAX) */
124 #ifdef ULLONG
125 #undef ULLONG
126 #endif  /* defined(ULLONG) */
127 #if HAVE_UNSIGNED_LONG_LONG_INT
128 #define ULLONG unsigned long long int
129 #ifndef ULLONG_MAX
130 #define ULLONG_MAX ULONG_MAX
131 #endif  /* !defined(ULLONG_MAX) */
132 #else
133 #define ULLONG unsigned long int
134 #ifdef ULLONG_MAX
135 #undef ULLONG_MAX
136 #endif  /* defined(ULLONG_MAX) */
137 #define ULLONG_MAX ULONG_MAX
138 #endif  /* HAVE_LONG_LONG_INT */
139
140 /* Support for uintmax_t.  We also need UINTMAX_MAX. */
141 #ifdef UINTMAX_T
142 #undef UINTMAX_T
143 #endif  /* defined(UINTMAX_T) */
144 #if HAVE_UINTMAX_T || defined(uintmax_t)
145 #define UINTMAX_T uintmax_t
146 #ifndef UINTMAX_MAX
147 #define UINTMAX_MAX ULLONG_MAX
148 #endif  /* !defined(UINTMAX_MAX) */
149 #else
150 #define UINTMAX_T ULLONG
151 #ifdef UINTMAX_MAX
152 #undef UINTMAX_MAX
153 #endif  /* defined(UINTMAX_MAX) */
154 #define UINTMAX_MAX ULLONG_MAX
155 #endif  /* HAVE_UINTMAX_T || defined(uintmax_t) */
156
157 /* Support for long long int. */
158 #ifndef LLONG
159 #if HAVE_LONG_LONG_INT
160 #define LLONG long long int
161 #else
162 #define LLONG long int
163 #endif  /* HAVE_LONG_LONG_INT */
164 #endif  /* !defined(LLONG) */
165
166 /* Support for intmax_t. */
167 #ifndef INTMAX_T
168 #if HAVE_INTMAX_T || defined(intmax_t)
169 #define INTMAX_T intmax_t
170 #else
171 #define INTMAX_T LLONG
172 #endif  /* HAVE_INTMAX_T || defined(intmax_t) */
173 #endif  /* !defined(INTMAX_T) */
174
175 /* Support for uintptr_t. */
176 #ifndef UINTPTR_T
177 #if HAVE_UINTPTR_T || defined(uintptr_t)
178 #define UINTPTR_T uintptr_t
179 #else
180 #define UINTPTR_T unsigned long int
181 #endif  /* HAVE_UINTPTR_T || defined(uintptr_t) */
182 #endif  /* !defined(UINTPTR_T) */
183
184 /* Support for ptrdiff_t. */
185 #ifndef PTRDIFF_T
186 #if HAVE_PTRDIFF_T || defined(ptrdiff_t)
187 #define PTRDIFF_T ptrdiff_t
188 #else
189 #define PTRDIFF_T long int
190 #endif  /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */
191 #endif  /* !defined(PTRDIFF_T) */
192
193 /*
194  * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99:
195  * 7.19.6.1, 7).  However, we'll simply use PTRDIFF_T and convert it to an
196  * unsigned type if necessary.  This should work just fine in practice.
197  */
198 #ifndef UPTRDIFF_T
199 #define UPTRDIFF_T PTRDIFF_T
200 #endif  /* !defined(UPTRDIFF_T) */
201
202 /*
203  * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7).
204  * However, we'll simply use size_t and convert it to a signed type if
205  * necessary.  This should work just fine in practice.
206  */
207 #ifndef SSIZE_T
208 #define SSIZE_T size_t
209 #endif  /* !defined(SSIZE_T) */
210
211
212 /*
213  * Buffer size to hold the octal string representation of UINT128_MAX without
214  * nul-termination ("3777777777777777777777777777777777777777777").
215  */
216 #ifdef MAX_CONVERT_LENGTH
217 #undef MAX_CONVERT_LENGTH
218 #endif  /* defined(MAX_CONVERT_LENGTH) */
219 #define MAX_CONVERT_LENGTH      43
220
221 /* Format read states. */
222 #define PRINT_S_DEFAULT         0
223 #define PRINT_S_FLAGS           1
224 #define PRINT_S_WIDTH           2
225 #define PRINT_S_DOT             3
226 #define PRINT_S_PRECISION       4
227 #define PRINT_S_MOD             5
228 #define PRINT_S_CONV            6
229
230 /* Format flags. */
231 #define PRINT_F_MINUS           (1 << 0)
232 #define PRINT_F_PLUS            (1 << 1)
233 #define PRINT_F_SPACE           (1 << 2)
234 #define PRINT_F_NUM             (1 << 3)
235 #define PRINT_F_ZERO            (1 << 4)
236 #define PRINT_F_QUOTE           (1 << 5)
237 #define PRINT_F_UP              (1 << 6)
238 #define PRINT_F_UNSIGNED        (1 << 7)
239 #define PRINT_F_TYPE_G          (1 << 8)
240 #define PRINT_F_TYPE_E          (1 << 9)
241
242 /* Conversion flags. */
243 #define PRINT_C_CHAR            1
244 #define PRINT_C_SHORT           2
245 #define PRINT_C_LONG            3
246 #define PRINT_C_LLONG           4
247 //#define PRINT_C_LDOUBLE         5
248 #define PRINT_C_SIZE            6
249 #define PRINT_C_PTRDIFF         7
250 #define PRINT_C_INTMAX          8
251
252 #ifndef MAX
253 #define MAX(x, y) ((x >= y) ? x : y)
254 #endif  /* !defined(MAX) */
255 #ifndef CHARTOINT
256 #define CHARTOINT(ch) (ch - '0')
257 #endif  /* !defined(CHARTOINT) */
258 #ifndef ISDIGIT
259 #define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9')
260 #endif  /* !defined(ISDIGIT) */
261
262 #define OUTCHAR(str, len, size, ch)                                          \
263 do {                                                                         \
264         if (len + 1 < size)                                                  \
265                 str[len] = ch;                                               \
266         (len)++;                                                             \
267 } while (/* CONSTCOND */ 0)
268
269 static void fmtstr(char *, size_t *, size_t, const char *, int, int, int);
270 static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int);
271 static void printsep(char *, size_t *, size_t);
272 static int getnumsep(int);
273 static int convert(UINTMAX_T, char *, size_t, int, int);
274
275 int vsnprintf(char *str, size_t size, const char *format, va_list args)
276 {
277         INTMAX_T value;
278         unsigned char cvalue;
279         const char *strvalue;
280         INTMAX_T *intmaxptr;
281         PTRDIFF_T *ptrdiffptr;
282         SSIZE_T *sizeptr;
283         LLONG *llongptr;
284         long int *longptr;
285         int *intptr;
286         short int *shortptr;
287         signed char *charptr;
288         size_t len = 0;
289         int overflow = 0;
290         int base = 0;
291         int cflags = 0;
292         int flags = 0;
293         int width = 0;
294         int precision = -1;
295         int state = PRINT_S_DEFAULT;
296         char ch = *format++;
297
298         /*
299          * C99 says: "If `n' is zero, nothing is written, and `s' may be a null
300          * pointer." (7.19.6.5, 2)  We're forgiving and allow a NULL pointer
301          * even if a size larger than zero was specified.  At least NetBSD's
302          * snprintf(3) does the same, as well as other versions of this file.
303          * (Though some of these versions will write to a non-NULL buffer even
304          * if a size of zero was specified, which violates the standard.)
305          */
306         if (str == NULL && size != 0)
307                 size = 0;
308
309         while (ch != '\0')
310                 switch (state) {
311                 case PRINT_S_DEFAULT:
312                         if (ch == '%')
313                                 state = PRINT_S_FLAGS;
314                         else
315                                 OUTCHAR(str, len, size, ch);
316                         ch = *format++;
317                         break;
318                 case PRINT_S_FLAGS:
319                         switch (ch) {
320                         case '-':
321                                 flags |= PRINT_F_MINUS;
322                                 ch = *format++;
323                                 break;
324                         case '+':
325                                 flags |= PRINT_F_PLUS;
326                                 ch = *format++;
327                                 break;
328                         case ' ':
329                                 flags |= PRINT_F_SPACE;
330                                 ch = *format++;
331                                 break;
332                         case '#':
333                                 flags |= PRINT_F_NUM;
334                                 ch = *format++;
335                                 break;
336                         case '0':
337                                 flags |= PRINT_F_ZERO;
338                                 ch = *format++;
339                                 break;
340                         case '\'':      /* SUSv2 flag (not in C99). */
341                                 flags |= PRINT_F_QUOTE;
342                                 ch = *format++;
343                                 break;
344                         default:
345                                 state = PRINT_S_WIDTH;
346                                 break;
347                         }
348                         break;
349                 case PRINT_S_WIDTH:
350                         if (ISDIGIT(ch)) {
351                                 ch = CHARTOINT(ch);
352                                 if (width > (INT_MAX - ch) / 10) {
353                                         overflow = 1;
354                                         goto out;
355                                 }
356                                 width = 10 * width + ch;
357                                 ch = *format++;
358                         } else if (ch == '*') {
359                                 /*
360                                  * C99 says: "A negative field width argument is
361                                  * taken as a `-' flag followed by a positive
362                                  * field width." (7.19.6.1, 5)
363                                  */
364                                 if ((width = va_arg(args, int)) < 0) {
365                                         flags |= PRINT_F_MINUS;
366                                         width = -width;
367                                 }
368                                 ch = *format++;
369                                 state = PRINT_S_DOT;
370                         } else
371                                 state = PRINT_S_DOT;
372                         break;
373                 case PRINT_S_DOT:
374                         if (ch == '.') {
375                                 state = PRINT_S_PRECISION;
376                                 ch = *format++;
377                         } else
378                                 state = PRINT_S_MOD;
379                         break;
380                 case PRINT_S_PRECISION:
381                         if (precision == -1)
382                                 precision = 0;
383                         if (ISDIGIT(ch)) {
384                                 ch = CHARTOINT(ch);
385                                 if (precision > (INT_MAX - ch) / 10) {
386                                         overflow = 1;
387                                         goto out;
388                                 }
389                                 precision = 10 * precision + ch;
390                                 ch = *format++;
391                         } else if (ch == '*') {
392                                 /*
393                                  * C99 says: "A negative precision argument is
394                                  * taken as if the precision were omitted."
395                                  * (7.19.6.1, 5)
396                                  */
397                                 if ((precision = va_arg(args, int)) < 0)
398                                         precision = -1;
399                                 ch = *format++;
400                                 state = PRINT_S_MOD;
401                         } else
402                                 state = PRINT_S_MOD;
403                         break;
404                 case PRINT_S_MOD:
405                         switch (ch) {
406                         case 'h':
407                                 ch = *format++;
408                                 if (ch == 'h') {        /* It's a char. */
409                                         ch = *format++;
410                                         cflags = PRINT_C_CHAR;
411                                 } else
412                                         cflags = PRINT_C_SHORT;
413                                 break;
414                         case 'l':
415                                 ch = *format++;
416                                 if (ch == 'l') {        /* It's a long long. */
417                                         ch = *format++;
418                                         cflags = PRINT_C_LLONG;
419                                 } else
420                                         cflags = PRINT_C_LONG;
421                                 break;
422                         case 'j':
423                                 cflags = PRINT_C_INTMAX;
424                                 ch = *format++;
425                                 break;
426                         case 't':
427                                 cflags = PRINT_C_PTRDIFF;
428                                 ch = *format++;
429                                 break;
430                         case 'z':
431                                 cflags = PRINT_C_SIZE;
432                                 ch = *format++;
433                                 break;
434                         }
435                         state = PRINT_S_CONV;
436                         break;
437                 case PRINT_S_CONV:
438                         switch (ch) {
439                         case 'd':
440                                 /* FALLTHROUGH */
441                         case 'i':
442                                 switch (cflags) {
443                                 case PRINT_C_CHAR:
444                                         value = (signed char)va_arg(args, int);
445                                         break;
446                                 case PRINT_C_SHORT:
447                                         value = (short int)va_arg(args, int);
448                                         break;
449                                 case PRINT_C_LONG:
450                                         value = va_arg(args, long int);
451                                         break;
452                                 case PRINT_C_LLONG:
453                                         value = va_arg(args, LLONG);
454                                         break;
455                                 case PRINT_C_SIZE:
456                                         value = va_arg(args, SSIZE_T);
457                                         break;
458                                 case PRINT_C_INTMAX:
459                                         value = va_arg(args, INTMAX_T);
460                                         break;
461                                 case PRINT_C_PTRDIFF:
462                                         value = va_arg(args, PTRDIFF_T);
463                                         break;
464                                 default:
465                                         value = va_arg(args, int);
466                                         break;
467                                 }
468                                 fmtint(str, &len, size, value, 10, width,
469                                     precision, flags);
470                                 break;
471                         case 'X':
472                                 flags |= PRINT_F_UP;
473                                 /* FALLTHROUGH */
474                         case 'x':
475                                 base = 16;
476                                 /* FALLTHROUGH */
477                         case 'o':
478                                 if (base == 0)
479                                         base = 8;
480                                 /* FALLTHROUGH */
481                         case 'u':
482                                 if (base == 0)
483                                         base = 10;
484                                 flags |= PRINT_F_UNSIGNED;
485                                 switch (cflags) {
486                                 case PRINT_C_CHAR:
487                                         value = (unsigned char)va_arg(args,
488                                             unsigned int);
489                                         break;
490                                 case PRINT_C_SHORT:
491                                         value = (unsigned short int)va_arg(args,
492                                             unsigned int);
493                                         break;
494                                 case PRINT_C_LONG:
495                                         value = va_arg(args, unsigned long int);
496                                         break;
497                                 case PRINT_C_LLONG:
498                                         value = va_arg(args, ULLONG);
499                                         break;
500                                 case PRINT_C_SIZE:
501                                         value = va_arg(args, size_t);
502                                         break;
503                                 case PRINT_C_INTMAX:
504                                         value = va_arg(args, UINTMAX_T);
505                                         break;
506                                 case PRINT_C_PTRDIFF:
507                                         value = va_arg(args, UPTRDIFF_T);
508                                         break;
509                                 default:
510                                         value = va_arg(args, unsigned int);
511                                         break;
512                                 }
513                                 fmtint(str, &len, size, value, base, width,
514                                     precision, flags);
515                                 break;
516                         case 'c':
517                                 cvalue = va_arg(args, int);
518                                 OUTCHAR(str, len, size, cvalue);
519                                 break;
520                         case 's':
521                                 strvalue = va_arg(args, char *);
522                                 fmtstr(str, &len, size, strvalue, width,
523                                     precision, flags);
524                                 break;
525                         case 'p':
526                                 /*
527                                  * C99 says: "The value of the pointer is
528                                  * converted to a sequence of printing
529                                  * characters, in an implementation-defined
530                                  * manner." (C99: 7.19.6.1, 8)
531                                  */
532                                 if ((strvalue = va_arg(args, void *)) == NULL)
533                                         /*
534                                          * We use the glibc format.  BSD prints
535                                          * "0x0", SysV "0".
536                                          */
537                                         fmtstr(str, &len, size, "(nil)", width,
538                                             -1, flags);
539                                 else {
540                                         /*
541                                          * We use the BSD/glibc format.  SysV
542                                          * omits the "0x" prefix (which we emit
543                                          * using the PRINT_F_NUM flag).
544                                          */
545                                         flags |= PRINT_F_NUM;
546                                         flags |= PRINT_F_UNSIGNED;
547                                         fmtint(str, &len, size,
548                                             (UINTPTR_T)strvalue, 16, width,
549                                             precision, flags);
550                                 }
551                                 break;
552                         case 'n':
553                                 switch (cflags) {
554                                 case PRINT_C_CHAR:
555                                         charptr = va_arg(args, signed char *);
556                                         *charptr = len;
557                                         break;
558                                 case PRINT_C_SHORT:
559                                         shortptr = va_arg(args, short int *);
560                                         *shortptr = len;
561                                         break;
562                                 case PRINT_C_LONG:
563                                         longptr = va_arg(args, long int *);
564                                         *longptr = len;
565                                         break;
566                                 case PRINT_C_LLONG:
567                                         llongptr = va_arg(args, LLONG *);
568                                         *llongptr = len;
569                                         break;
570                                 case PRINT_C_SIZE:
571                                         /*
572                                          * C99 says that with the "z" length
573                                          * modifier, "a following `n' conversion
574                                          * specifier applies to a pointer to a
575                                          * signed integer type corresponding to
576                                          * size_t argument." (7.19.6.1, 7)
577                                          */
578                                         sizeptr = va_arg(args, SSIZE_T *);
579                                         *sizeptr = len;
580                                         break;
581                                 case PRINT_C_INTMAX:
582                                         intmaxptr = va_arg(args, INTMAX_T *);
583                                         *intmaxptr = len;
584                                         break;
585                                 case PRINT_C_PTRDIFF:
586                                         ptrdiffptr = va_arg(args, PTRDIFF_T *);
587                                         *ptrdiffptr = len;
588                                         break;
589                                 default:
590                                         intptr = va_arg(args, int *);
591                                         *intptr = len;
592                                         break;
593                                 }
594                                 break;
595                         case '%':       /* Print a "%" character verbatim. */
596                                 OUTCHAR(str, len, size, ch);
597                                 break;
598                         default:        /* Skip other characters. */
599                                 break;
600                         }
601                         ch = *format++;
602                         state = PRINT_S_DEFAULT;
603                         base = cflags = flags = width = 0;
604                         precision = -1;
605                         break;
606                 }
607 out:
608         if (len < size)
609                 str[len] = '\0';
610         else if (size > 0)
611                 str[size - 1] = '\0';
612
613         if (overflow || len >= INT_MAX) {
614                 return -1;
615         }
616         return (int)len;
617 }
618
619 static void
620 fmtstr(char *str, size_t *len, size_t size, const char *value, int width,
621        int precision, int flags)
622 {
623         int padlen, strln;      /* Amount to pad. */
624         int noprecision = (precision == -1);
625
626         if (value == NULL)      /* We're forgiving. */
627                 value = "(null)";
628
629         /* If a precision was specified, don't read the string past it. */
630         for (strln = 0; value[strln] != '\0' &&
631             (noprecision || strln < precision); strln++)
632                 continue;
633
634         if ((padlen = width - strln) < 0)
635                 padlen = 0;
636         if (flags & PRINT_F_MINUS)      /* Left justify. */
637                 padlen = -padlen;
638
639         while (padlen > 0) {    /* Leading spaces. */
640                 OUTCHAR(str, *len, size, ' ');
641                 padlen--;
642         }
643         while (*value != '\0' && (noprecision || precision-- > 0)) {
644                 OUTCHAR(str, *len, size, *value);
645                 value++;
646         }
647         while (padlen < 0) {    /* Trailing spaces. */
648                 OUTCHAR(str, *len, size, ' ');
649                 padlen++;
650         }
651 }
652
653 static void
654 fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width,
655        int precision, int flags)
656 {
657         UINTMAX_T uvalue;
658         char iconvert[MAX_CONVERT_LENGTH];
659         char sign = 0;
660         char hexprefix = 0;
661         int spadlen = 0;        /* Amount to space pad. */
662         int zpadlen = 0;        /* Amount to zero pad. */
663         int pos;
664         int separators = (flags & PRINT_F_QUOTE);
665         int noprecision = (precision == -1);
666
667         if (flags & PRINT_F_UNSIGNED)
668                 uvalue = value;
669         else {
670                 uvalue = (value >= 0) ? value : -value;
671                 if (value < 0)
672                         sign = '-';
673                 else if (flags & PRINT_F_PLUS)  /* Do a sign. */
674                         sign = '+';
675                 else if (flags & PRINT_F_SPACE)
676                         sign = ' ';
677         }
678
679         pos = convert(uvalue, iconvert, sizeof(iconvert), base,
680             flags & PRINT_F_UP);
681
682         if (flags & PRINT_F_NUM && uvalue != 0) {
683                 /*
684                  * C99 says: "The result is converted to an `alternative form'.
685                  * For `o' conversion, it increases the precision, if and only
686                  * if necessary, to force the first digit of the result to be a
687                  * zero (if the value and precision are both 0, a single 0 is
688                  * printed).  For `x' (or `X') conversion, a nonzero result has
689                  * `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
690                  */
691                 switch (base) {
692                 case 8:
693                         if (precision <= pos)
694                                 precision = pos + 1;
695                         break;
696                 case 16:
697                         hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
698                         break;
699                 }
700         }
701
702         if (separators) /* Get the number of group separators we'll print. */
703                 separators = getnumsep(pos);
704
705         zpadlen = precision - pos - separators;
706         spadlen = width                         /* Minimum field width. */
707             - separators                        /* Number of separators. */
708             - MAX(precision, pos)               /* Number of integer digits. */
709             - ((sign != 0) ? 1 : 0)             /* Will we print a sign? */
710             - ((hexprefix != 0) ? 2 : 0);       /* Will we print a prefix? */
711
712         if (zpadlen < 0)
713                 zpadlen = 0;
714         if (spadlen < 0)
715                 spadlen = 0;
716
717         /*
718          * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
719          * ignored.  For `d', `i', `o', `u', `x', and `X' conversions, if a
720          * precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
721          */
722         if (flags & PRINT_F_MINUS)      /* Left justify. */
723                 spadlen = -spadlen;
724         else if (flags & PRINT_F_ZERO && noprecision) {
725                 zpadlen += spadlen;
726                 spadlen = 0;
727         }
728         while (spadlen > 0) {   /* Leading spaces. */
729                 OUTCHAR(str, *len, size, ' ');
730                 spadlen--;
731         }
732         if (sign != 0)  /* Sign. */
733                 OUTCHAR(str, *len, size, sign);
734         if (hexprefix != 0) {   /* A "0x" or "0X" prefix. */
735                 OUTCHAR(str, *len, size, '0');
736                 OUTCHAR(str, *len, size, hexprefix);
737         }
738         while (zpadlen > 0) {   /* Leading zeros. */
739                 OUTCHAR(str, *len, size, '0');
740                 zpadlen--;
741         }
742         while (pos > 0) {       /* The actual digits. */
743                 pos--;
744                 OUTCHAR(str, *len, size, iconvert[pos]);
745                 if (separators > 0 && pos > 0 && pos % 3 == 0)
746                         printsep(str, len, size);
747         }
748         while (spadlen < 0) {   /* Trailing spaces. */
749                 OUTCHAR(str, *len, size, ' ');
750                 spadlen++;
751         }
752 }
753
754
755 static void
756 printsep(char *str, size_t *len, size_t size)
757 {
758         OUTCHAR(str, *len, size, ',');
759 }
760
761 static int
762 getnumsep(int digits)
763 {
764         int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
765         return separators;
766 }
767
768 static int
769 convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
770 {
771         const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
772         size_t pos = 0;
773
774         /* We return an unterminated buffer with the digits in reverse order. */
775         do {
776                 buf[pos++] = digits[value % base];
777                 value /= base;
778         } while (value != 0 && pos < size);
779
780         return (int)pos;
781 }
782
783 int vsprintf(char *buf, const char *fmt, va_list args)
784 {
785         return vsnprintf(buf, INT_MAX, fmt, args);
786 }
787
788 int sprintf(char *buffer, const char *fmt, ...)
789 {
790         va_list args;
791         int i;
792
793         va_start(args, fmt);
794         i = vsprintf(buffer, fmt,args);
795         va_end(args);
796         return i;
797 }
798