4 * vsnprintf(), from which the rest of the printf()
16 FL_ZERO
= 0x01, /* Zero modifier */
17 FL_MINUS
= 0x02, /* Minus modifier */
18 FL_PLUS
= 0x04, /* Plus modifier */
19 FL_TICK
= 0x08, /* ' modifier */
20 FL_SPACE
= 0x10, /* Space modifier */
21 FL_HASH
= 0x20, /* # modifier */
22 FL_SIGNED
= 0x40, /* Number is signed */
23 FL_UPPER
= 0x80 /* Upper case digits */
26 /* These may have to be adjusted on certain implementations */
35 #define MIN_RANK rank_char
36 #define MAX_RANK rank_longlong
38 #define INTMAX_RANK rank_longlong
39 #define SIZE_T_RANK rank_long
40 #define PTRDIFF_T_RANK rank_long
42 #define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
45 format_int(char *q
, size_t n
, uintmax_t val
, enum flags flags
,
46 int base
, int width
, int prec
)
50 static const char lcdigits
[] = "0123456789abcdef";
51 static const char ucdigits
[] = "0123456789ABCDEF";
55 int ndigits
= 0, nchars
;
58 /* Select type of digits */
59 digits
= (flags
& FL_UPPER
) ? ucdigits
: lcdigits
;
61 /* If signed, separate out the minus */
62 if (flags
& FL_SIGNED
&& (intmax_t) val
< 0) {
64 val
= (uintmax_t) (-(intmax_t) val
);
67 /* Count the number of digits needed. This returns zero for 0. */
74 /* Adjust ndigits for size of output */
76 if (flags
& FL_HASH
&& base
== 8) {
77 if (prec
< ndigits
+ 1)
82 ndigits
= prec
; /* Mandatory number padding */
83 } else if (val
== 0) {
84 ndigits
= 1; /* Zero still requires space */
87 /* For ', figure out what the skip should be */
88 if (flags
& FL_TICK
) {
89 tickskip
= (base
== 16) ? 4 : 3;
91 tickskip
= ndigits
; /* No tick marks */
94 /* Tick marks aren't digits, but generated by the number converter */
95 ndigits
+= (ndigits
- 1) / tickskip
;
97 /* Now compute the number of nondigits */
100 if (minus
|| (flags
& (FL_PLUS
| FL_SPACE
)))
101 nchars
++; /* Need space for sign */
102 if ((flags
& FL_HASH
) && base
== 16) {
103 nchars
+= 2; /* Add 0x for hex */
106 /* Emit early space padding */
107 if (!(flags
& (FL_MINUS
| FL_ZERO
)) && width
> nchars
) {
108 while (width
> nchars
) {
117 else if (flags
& FL_PLUS
)
119 else if (flags
& FL_SPACE
)
122 if ((flags
& FL_HASH
) && base
== 16) {
124 EMIT((flags
& FL_UPPER
) ? 'X' : 'x');
127 /* Emit zero padding */
128 if ((flags
& (FL_MINUS
| FL_ZERO
)) == FL_ZERO
&& width
> ndigits
) {
129 while (width
> nchars
) {
135 /* Generate the number. This is done from right to left. */
136 q
+= ndigits
; /* Advance the pointer to end of number */
139 oo
= o
; /* Temporary values */
142 while (ndigits
> 0) {
149 b4tick
= tickskip
- 1;
155 *qq
= digits
[val
% base
];
159 /* Emit late space padding */
160 while ((flags
& FL_MINUS
) && width
> nchars
) {
168 int vsnprintf(char *buffer
, size_t n
, const char *format
, va_list ap
)
170 const char *p
= format
;
173 size_t o
= 0; /* Number of characters output */
175 int rank
= rank_int
; /* Default rank */
180 enum flags flags
= 0;
182 st_normal
, /* Ground state */
183 st_flags
, /* Special flags */
184 st_width
, /* Field width */
185 st_prec
, /* Field precision */
186 st_modifiers
/* Length or conversion modifiers */
188 const char *sarg
; /* %s string argument */
189 char carg
; /* %c char argument */
190 int slen
; /* String length */
192 while ((ch
= *p
++)) {
228 p
--; /* Process this character again */
234 if (ch
>= '0' && ch
<= '9') {
235 width
= width
* 10 + (ch
- '0');
236 } else if (ch
== '*') {
237 width
= va_arg(ap
, int);
242 } else if (ch
== '.') {
243 prec
= 0; /* Precision given */
246 state
= st_modifiers
;
247 p
--; /* Process this character again */
252 if (ch
>= '0' && ch
<= '9') {
253 prec
= prec
* 10 + (ch
- '0');
254 } else if (ch
== '*') {
255 prec
= va_arg(ap
, int);
259 state
= st_modifiers
;
260 p
--; /* Process this character again */
266 /* Length modifiers - nonterminal sequences */
268 rank
--; /* Shorter rank */
271 rank
++; /* Longer rank */
280 rank
= PTRDIFF_T_RANK
;
287 /* Output modifiers - terminal sequences */
288 state
= st_normal
; /* Next state will be normal */
289 if (rank
< MIN_RANK
) /* Canonicalize rank */
291 else if (rank
> MAX_RANK
)
295 case 'P': /* Upper case pointer */
298 case 'p': /* Pointer */
300 prec
= (CHAR_BIT
* sizeof(void *) + 3) / 4;
302 val
= (uintmax_t) (uintptr_t) va_arg(ap
, void *);
305 case 'd': /* Signed decimal output */
311 /* Yes, all these casts are needed... */
313 (uintmax_t) (intmax_t) (signed char)va_arg(ap
,
319 (uintmax_t) (intmax_t) (signed short)va_arg(ap
,
324 val
= (uintmax_t) (intmax_t) va_arg(ap
, signed int);
327 val
= (uintmax_t) (intmax_t) va_arg(ap
, signed long);
331 (uintmax_t) (intmax_t) va_arg(ap
, signed long long);
335 case 'o': /* Octal */
338 case 'u': /* Unsigned decimal */
341 case 'X': /* Upper case hexadecimal */
344 case 'x': /* Hexadecimal */
352 (uintmax_t) (unsigned char)va_arg(ap
, unsigned int);
356 (uintmax_t) (unsigned short)va_arg(ap
,
360 val
= (uintmax_t) va_arg(ap
, unsigned int);
363 val
= (uintmax_t) va_arg(ap
, unsigned long);
366 val
= (uintmax_t) va_arg(ap
, unsigned long long);
372 sz
= format_int(q
, (o
< n
) ? n
- o
: 0, val
, flags
, base
,
378 case 'c': /* Character */
379 carg
= (char)va_arg(ap
, int);
383 case 's': /* String */
384 sarg
= va_arg(ap
, const char *);
385 sarg
= sarg
? sarg
: "(null)";
394 if (prec
!= -1 && slen
> prec
)
397 if (width
> slen
&& !(flags
& FL_MINUS
)) {
398 char pad
= (flags
& FL_ZERO
) ? '0' : ' ';
399 while (width
> slen
) {
404 for (i
= slen
; i
; i
--) {
408 if (width
> slen
&& (flags
& FL_MINUS
)) {
409 while (width
> slen
) {
417 case 'n': /* Output the number of characters written */
421 *va_arg(ap
, signed char *) = o
;
424 *va_arg(ap
, signed short *) = o
;
427 *va_arg(ap
, signed int *) = o
;
430 *va_arg(ap
, signed long *) = o
;
433 *va_arg(ap
, signed long long *) = o
;
439 default: /* Anything else, including % */
447 /* Null-terminate the string */
449 *q
= '\0'; /* No overflow */
451 buffer
[n
- 1] = '\0'; /* Overflow - terminate at end of buffer */