1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* -*- linux-c -*- ------------------------------------------------------- *
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 1991, 1992 Linus Torvalds
5*4882a593Smuzhiyun * Copyright 2007 rPath, Inc. - All Rights Reserved
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * ----------------------------------------------------------------------- */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun /*
10*4882a593Smuzhiyun * Oh, it's a waste of space, but oh-so-yummy for debugging.
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <stdarg.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/compiler.h>
16*4882a593Smuzhiyun #include <linux/ctype.h>
17*4882a593Smuzhiyun #include <linux/kernel.h>
18*4882a593Smuzhiyun #include <linux/limits.h>
19*4882a593Smuzhiyun #include <linux/string.h>
20*4882a593Smuzhiyun #include <linux/types.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static
skip_atoi(const char ** s)23*4882a593Smuzhiyun int skip_atoi(const char **s)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun int i = 0;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun while (isdigit(**s))
28*4882a593Smuzhiyun i = i * 10 + *((*s)++) - '0';
29*4882a593Smuzhiyun return i;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun * put_dec_full4 handles numbers in the range 0 <= r < 10000.
34*4882a593Smuzhiyun * The multiplier 0xccd is round(2^15/10), and the approximation
35*4882a593Smuzhiyun * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun static
put_dec_full4(char * end,unsigned int r)38*4882a593Smuzhiyun void put_dec_full4(char *end, unsigned int r)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun int i;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
43*4882a593Smuzhiyun unsigned int q = (r * 0xccd) >> 15;
44*4882a593Smuzhiyun *--end = '0' + (r - q * 10);
45*4882a593Smuzhiyun r = q;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun *--end = '0' + r;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* put_dec is copied from lib/vsprintf.c with small modifications */
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * Call put_dec_full4 on x % 10000, return x / 10000.
54*4882a593Smuzhiyun * The approximation x/10000 == (x * 0x346DC5D7) >> 43
55*4882a593Smuzhiyun * holds for all x < 1,128,869,999. The largest value this
56*4882a593Smuzhiyun * helper will ever be asked to convert is 1,125,520,955.
57*4882a593Smuzhiyun * (second call in the put_dec code, assuming n is all-ones).
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun static
put_dec_helper4(char * end,unsigned int x)60*4882a593Smuzhiyun unsigned int put_dec_helper4(char *end, unsigned int x)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun unsigned int q = (x * 0x346DC5D7ULL) >> 43;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun put_dec_full4(end, x - q * 10000);
65*4882a593Smuzhiyun return q;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /* Based on code by Douglas W. Jones found at
69*4882a593Smuzhiyun * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
70*4882a593Smuzhiyun * (with permission from the author).
71*4882a593Smuzhiyun * Performs no 64-bit division and hence should be fast on 32-bit machines.
72*4882a593Smuzhiyun */
73*4882a593Smuzhiyun static
put_dec(char * end,unsigned long long n)74*4882a593Smuzhiyun char *put_dec(char *end, unsigned long long n)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun unsigned int d3, d2, d1, q, h;
77*4882a593Smuzhiyun char *p = end;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun d1 = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
80*4882a593Smuzhiyun h = (n >> 32);
81*4882a593Smuzhiyun d2 = (h ) & 0xffff;
82*4882a593Smuzhiyun d3 = (h >> 16); /* implicit "& 0xffff" */
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
85*4882a593Smuzhiyun = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
86*4882a593Smuzhiyun q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
87*4882a593Smuzhiyun q = put_dec_helper4(p, q);
88*4882a593Smuzhiyun p -= 4;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun q += 7671 * d3 + 9496 * d2 + 6 * d1;
91*4882a593Smuzhiyun q = put_dec_helper4(p, q);
92*4882a593Smuzhiyun p -= 4;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun q += 4749 * d3 + 42 * d2;
95*4882a593Smuzhiyun q = put_dec_helper4(p, q);
96*4882a593Smuzhiyun p -= 4;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun q += 281 * d3;
99*4882a593Smuzhiyun q = put_dec_helper4(p, q);
100*4882a593Smuzhiyun p -= 4;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun put_dec_full4(p, q);
103*4882a593Smuzhiyun p -= 4;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* strip off the extra 0's we printed */
106*4882a593Smuzhiyun while (p < end && *p == '0')
107*4882a593Smuzhiyun ++p;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun return p;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun static
number(char * end,unsigned long long num,int base,char locase)113*4882a593Smuzhiyun char *number(char *end, unsigned long long num, int base, char locase)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun /*
116*4882a593Smuzhiyun * locase = 0 or 0x20. ORing digits or letters with 'locase'
117*4882a593Smuzhiyun * produces same digits or (maybe lowercased) letters
118*4882a593Smuzhiyun */
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
121*4882a593Smuzhiyun static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun switch (base) {
124*4882a593Smuzhiyun case 10:
125*4882a593Smuzhiyun if (num != 0)
126*4882a593Smuzhiyun end = put_dec(end, num);
127*4882a593Smuzhiyun break;
128*4882a593Smuzhiyun case 8:
129*4882a593Smuzhiyun for (; num != 0; num >>= 3)
130*4882a593Smuzhiyun *--end = '0' + (num & 07);
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun case 16:
133*4882a593Smuzhiyun for (; num != 0; num >>= 4)
134*4882a593Smuzhiyun *--end = digits[num & 0xf] | locase;
135*4882a593Smuzhiyun break;
136*4882a593Smuzhiyun default:
137*4882a593Smuzhiyun unreachable();
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun return end;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun #define ZEROPAD 1 /* pad with zero */
144*4882a593Smuzhiyun #define SIGN 2 /* unsigned/signed long */
145*4882a593Smuzhiyun #define PLUS 4 /* show plus */
146*4882a593Smuzhiyun #define SPACE 8 /* space if plus */
147*4882a593Smuzhiyun #define LEFT 16 /* left justified */
148*4882a593Smuzhiyun #define SMALL 32 /* Must be 32 == 0x20 */
149*4882a593Smuzhiyun #define SPECIAL 64 /* 0x */
150*4882a593Smuzhiyun #define WIDE 128 /* UTF-16 string */
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static
get_flags(const char ** fmt)153*4882a593Smuzhiyun int get_flags(const char **fmt)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun int flags = 0;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun do {
158*4882a593Smuzhiyun switch (**fmt) {
159*4882a593Smuzhiyun case '-':
160*4882a593Smuzhiyun flags |= LEFT;
161*4882a593Smuzhiyun break;
162*4882a593Smuzhiyun case '+':
163*4882a593Smuzhiyun flags |= PLUS;
164*4882a593Smuzhiyun break;
165*4882a593Smuzhiyun case ' ':
166*4882a593Smuzhiyun flags |= SPACE;
167*4882a593Smuzhiyun break;
168*4882a593Smuzhiyun case '#':
169*4882a593Smuzhiyun flags |= SPECIAL;
170*4882a593Smuzhiyun break;
171*4882a593Smuzhiyun case '0':
172*4882a593Smuzhiyun flags |= ZEROPAD;
173*4882a593Smuzhiyun break;
174*4882a593Smuzhiyun default:
175*4882a593Smuzhiyun return flags;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun ++(*fmt);
178*4882a593Smuzhiyun } while (1);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun static
get_int(const char ** fmt,va_list * ap)182*4882a593Smuzhiyun int get_int(const char **fmt, va_list *ap)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun if (isdigit(**fmt))
185*4882a593Smuzhiyun return skip_atoi(fmt);
186*4882a593Smuzhiyun if (**fmt == '*') {
187*4882a593Smuzhiyun ++(*fmt);
188*4882a593Smuzhiyun /* it's the next argument */
189*4882a593Smuzhiyun return va_arg(*ap, int);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun static
get_number(int sign,int qualifier,va_list * ap)195*4882a593Smuzhiyun unsigned long long get_number(int sign, int qualifier, va_list *ap)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun if (sign) {
198*4882a593Smuzhiyun switch (qualifier) {
199*4882a593Smuzhiyun case 'L':
200*4882a593Smuzhiyun return va_arg(*ap, long long);
201*4882a593Smuzhiyun case 'l':
202*4882a593Smuzhiyun return va_arg(*ap, long);
203*4882a593Smuzhiyun case 'h':
204*4882a593Smuzhiyun return (short)va_arg(*ap, int);
205*4882a593Smuzhiyun case 'H':
206*4882a593Smuzhiyun return (signed char)va_arg(*ap, int);
207*4882a593Smuzhiyun default:
208*4882a593Smuzhiyun return va_arg(*ap, int);
209*4882a593Smuzhiyun };
210*4882a593Smuzhiyun } else {
211*4882a593Smuzhiyun switch (qualifier) {
212*4882a593Smuzhiyun case 'L':
213*4882a593Smuzhiyun return va_arg(*ap, unsigned long long);
214*4882a593Smuzhiyun case 'l':
215*4882a593Smuzhiyun return va_arg(*ap, unsigned long);
216*4882a593Smuzhiyun case 'h':
217*4882a593Smuzhiyun return (unsigned short)va_arg(*ap, int);
218*4882a593Smuzhiyun case 'H':
219*4882a593Smuzhiyun return (unsigned char)va_arg(*ap, int);
220*4882a593Smuzhiyun default:
221*4882a593Smuzhiyun return va_arg(*ap, unsigned int);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun static
get_sign(long long * num,int flags)227*4882a593Smuzhiyun char get_sign(long long *num, int flags)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun if (!(flags & SIGN))
230*4882a593Smuzhiyun return 0;
231*4882a593Smuzhiyun if (*num < 0) {
232*4882a593Smuzhiyun *num = -(*num);
233*4882a593Smuzhiyun return '-';
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun if (flags & PLUS)
236*4882a593Smuzhiyun return '+';
237*4882a593Smuzhiyun if (flags & SPACE)
238*4882a593Smuzhiyun return ' ';
239*4882a593Smuzhiyun return 0;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun static
utf16s_utf8nlen(const u16 * s16,size_t maxlen)243*4882a593Smuzhiyun size_t utf16s_utf8nlen(const u16 *s16, size_t maxlen)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun size_t len, clen;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun for (len = 0; len < maxlen && *s16; len += clen) {
248*4882a593Smuzhiyun u16 c0 = *s16++;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /* First, get the length for a BMP character */
251*4882a593Smuzhiyun clen = 1 + (c0 >= 0x80) + (c0 >= 0x800);
252*4882a593Smuzhiyun if (len + clen > maxlen)
253*4882a593Smuzhiyun break;
254*4882a593Smuzhiyun /*
255*4882a593Smuzhiyun * If this is a high surrogate, and we're already at maxlen, we
256*4882a593Smuzhiyun * can't include the character if it's a valid surrogate pair.
257*4882a593Smuzhiyun * Avoid accessing one extra word just to check if it's valid
258*4882a593Smuzhiyun * or not.
259*4882a593Smuzhiyun */
260*4882a593Smuzhiyun if ((c0 & 0xfc00) == 0xd800) {
261*4882a593Smuzhiyun if (len + clen == maxlen)
262*4882a593Smuzhiyun break;
263*4882a593Smuzhiyun if ((*s16 & 0xfc00) == 0xdc00) {
264*4882a593Smuzhiyun ++s16;
265*4882a593Smuzhiyun ++clen;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun return len;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun static
utf16_to_utf32(const u16 ** s16)274*4882a593Smuzhiyun u32 utf16_to_utf32(const u16 **s16)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun u16 c0, c1;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun c0 = *(*s16)++;
279*4882a593Smuzhiyun /* not a surrogate */
280*4882a593Smuzhiyun if ((c0 & 0xf800) != 0xd800)
281*4882a593Smuzhiyun return c0;
282*4882a593Smuzhiyun /* invalid: low surrogate instead of high */
283*4882a593Smuzhiyun if (c0 & 0x0400)
284*4882a593Smuzhiyun return 0xfffd;
285*4882a593Smuzhiyun c1 = **s16;
286*4882a593Smuzhiyun /* invalid: missing low surrogate */
287*4882a593Smuzhiyun if ((c1 & 0xfc00) != 0xdc00)
288*4882a593Smuzhiyun return 0xfffd;
289*4882a593Smuzhiyun /* valid surrogate pair */
290*4882a593Smuzhiyun ++(*s16);
291*4882a593Smuzhiyun return (0x10000 - (0xd800 << 10) - 0xdc00) + (c0 << 10) + c1;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun #define PUTC(c) \
295*4882a593Smuzhiyun do { \
296*4882a593Smuzhiyun if (pos < size) \
297*4882a593Smuzhiyun buf[pos] = (c); \
298*4882a593Smuzhiyun ++pos; \
299*4882a593Smuzhiyun } while (0);
300*4882a593Smuzhiyun
vsnprintf(char * buf,size_t size,const char * fmt,va_list ap)301*4882a593Smuzhiyun int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun /* The maximum space required is to print a 64-bit number in octal */
304*4882a593Smuzhiyun char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
305*4882a593Smuzhiyun char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
306*4882a593Smuzhiyun long long num;
307*4882a593Smuzhiyun int base;
308*4882a593Smuzhiyun const char *s;
309*4882a593Smuzhiyun size_t len, pos;
310*4882a593Smuzhiyun char sign;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun int flags; /* flags to number() */
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun int field_width; /* width of output field */
315*4882a593Smuzhiyun int precision; /* min. # of digits for integers; max
316*4882a593Smuzhiyun number of chars for from string */
317*4882a593Smuzhiyun int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun va_list args;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun /*
322*4882a593Smuzhiyun * We want to pass our input va_list to helper functions by reference,
323*4882a593Smuzhiyun * but there's an annoying edge case. If va_list was originally passed
324*4882a593Smuzhiyun * to us by value, we could just pass &ap down to the helpers. This is
325*4882a593Smuzhiyun * the case on, for example, X86_32.
326*4882a593Smuzhiyun * However, on X86_64 (and possibly others), va_list is actually a
327*4882a593Smuzhiyun * size-1 array containing a structure. Our function parameter ap has
328*4882a593Smuzhiyun * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
329*4882a593Smuzhiyun * which is what will be expected by a function taking a va_list *
330*4882a593Smuzhiyun * parameter.
331*4882a593Smuzhiyun * One standard way to solve this mess is by creating a copy in a local
332*4882a593Smuzhiyun * variable of type va_list and then passing a pointer to that local
333*4882a593Smuzhiyun * copy instead, which is what we do here.
334*4882a593Smuzhiyun */
335*4882a593Smuzhiyun va_copy(args, ap);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun for (pos = 0; *fmt; ++fmt) {
338*4882a593Smuzhiyun if (*fmt != '%' || *++fmt == '%') {
339*4882a593Smuzhiyun PUTC(*fmt);
340*4882a593Smuzhiyun continue;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /* process flags */
344*4882a593Smuzhiyun flags = get_flags(&fmt);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /* get field width */
347*4882a593Smuzhiyun field_width = get_int(&fmt, &args);
348*4882a593Smuzhiyun if (field_width < 0) {
349*4882a593Smuzhiyun field_width = -field_width;
350*4882a593Smuzhiyun flags |= LEFT;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun if (flags & LEFT)
354*4882a593Smuzhiyun flags &= ~ZEROPAD;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* get the precision */
357*4882a593Smuzhiyun precision = -1;
358*4882a593Smuzhiyun if (*fmt == '.') {
359*4882a593Smuzhiyun ++fmt;
360*4882a593Smuzhiyun precision = get_int(&fmt, &args);
361*4882a593Smuzhiyun if (precision >= 0)
362*4882a593Smuzhiyun flags &= ~ZEROPAD;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /* get the conversion qualifier */
366*4882a593Smuzhiyun qualifier = -1;
367*4882a593Smuzhiyun if (*fmt == 'h' || *fmt == 'l') {
368*4882a593Smuzhiyun qualifier = *fmt;
369*4882a593Smuzhiyun ++fmt;
370*4882a593Smuzhiyun if (qualifier == *fmt) {
371*4882a593Smuzhiyun qualifier -= 'a'-'A';
372*4882a593Smuzhiyun ++fmt;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun sign = 0;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun switch (*fmt) {
379*4882a593Smuzhiyun case 'c':
380*4882a593Smuzhiyun flags &= LEFT;
381*4882a593Smuzhiyun s = tmp;
382*4882a593Smuzhiyun if (qualifier == 'l') {
383*4882a593Smuzhiyun ((u16 *)tmp)[0] = (u16)va_arg(args, unsigned int);
384*4882a593Smuzhiyun ((u16 *)tmp)[1] = L'\0';
385*4882a593Smuzhiyun precision = INT_MAX;
386*4882a593Smuzhiyun goto wstring;
387*4882a593Smuzhiyun } else {
388*4882a593Smuzhiyun tmp[0] = (unsigned char)va_arg(args, int);
389*4882a593Smuzhiyun precision = len = 1;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun goto output;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun case 's':
394*4882a593Smuzhiyun flags &= LEFT;
395*4882a593Smuzhiyun if (precision < 0)
396*4882a593Smuzhiyun precision = INT_MAX;
397*4882a593Smuzhiyun s = va_arg(args, void *);
398*4882a593Smuzhiyun if (!s)
399*4882a593Smuzhiyun s = precision < 6 ? "" : "(null)";
400*4882a593Smuzhiyun else if (qualifier == 'l') {
401*4882a593Smuzhiyun wstring:
402*4882a593Smuzhiyun flags |= WIDE;
403*4882a593Smuzhiyun precision = len = utf16s_utf8nlen((const u16 *)s, precision);
404*4882a593Smuzhiyun goto output;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun precision = len = strnlen(s, precision);
407*4882a593Smuzhiyun goto output;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun /* integer number formats - set up the flags and "break" */
410*4882a593Smuzhiyun case 'o':
411*4882a593Smuzhiyun base = 8;
412*4882a593Smuzhiyun break;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun case 'p':
415*4882a593Smuzhiyun if (precision < 0)
416*4882a593Smuzhiyun precision = 2 * sizeof(void *);
417*4882a593Smuzhiyun fallthrough;
418*4882a593Smuzhiyun case 'x':
419*4882a593Smuzhiyun flags |= SMALL;
420*4882a593Smuzhiyun fallthrough;
421*4882a593Smuzhiyun case 'X':
422*4882a593Smuzhiyun base = 16;
423*4882a593Smuzhiyun break;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun case 'd':
426*4882a593Smuzhiyun case 'i':
427*4882a593Smuzhiyun flags |= SIGN;
428*4882a593Smuzhiyun fallthrough;
429*4882a593Smuzhiyun case 'u':
430*4882a593Smuzhiyun flags &= ~SPECIAL;
431*4882a593Smuzhiyun base = 10;
432*4882a593Smuzhiyun break;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun default:
435*4882a593Smuzhiyun /*
436*4882a593Smuzhiyun * Bail out if the conversion specifier is invalid.
437*4882a593Smuzhiyun * There's probably a typo in the format string and the
438*4882a593Smuzhiyun * remaining specifiers are unlikely to match up with
439*4882a593Smuzhiyun * the arguments.
440*4882a593Smuzhiyun */
441*4882a593Smuzhiyun goto fail;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun if (*fmt == 'p') {
444*4882a593Smuzhiyun num = (unsigned long)va_arg(args, void *);
445*4882a593Smuzhiyun } else {
446*4882a593Smuzhiyun num = get_number(flags & SIGN, qualifier, &args);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun sign = get_sign(&num, flags);
450*4882a593Smuzhiyun if (sign)
451*4882a593Smuzhiyun --field_width;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun s = number(tmp_end, num, base, flags & SMALL);
454*4882a593Smuzhiyun len = tmp_end - s;
455*4882a593Smuzhiyun /* default precision is 1 */
456*4882a593Smuzhiyun if (precision < 0)
457*4882a593Smuzhiyun precision = 1;
458*4882a593Smuzhiyun /* precision is minimum number of digits to print */
459*4882a593Smuzhiyun if (precision < len)
460*4882a593Smuzhiyun precision = len;
461*4882a593Smuzhiyun if (flags & SPECIAL) {
462*4882a593Smuzhiyun /*
463*4882a593Smuzhiyun * For octal, a leading 0 is printed only if necessary,
464*4882a593Smuzhiyun * i.e. if it's not already there because of the
465*4882a593Smuzhiyun * precision.
466*4882a593Smuzhiyun */
467*4882a593Smuzhiyun if (base == 8 && precision == len)
468*4882a593Smuzhiyun ++precision;
469*4882a593Smuzhiyun /*
470*4882a593Smuzhiyun * For hexadecimal, the leading 0x is skipped if the
471*4882a593Smuzhiyun * output is empty, i.e. both the number and the
472*4882a593Smuzhiyun * precision are 0.
473*4882a593Smuzhiyun */
474*4882a593Smuzhiyun if (base == 16 && precision > 0)
475*4882a593Smuzhiyun field_width -= 2;
476*4882a593Smuzhiyun else
477*4882a593Smuzhiyun flags &= ~SPECIAL;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun /*
480*4882a593Smuzhiyun * For zero padding, increase the precision to fill the field
481*4882a593Smuzhiyun * width.
482*4882a593Smuzhiyun */
483*4882a593Smuzhiyun if ((flags & ZEROPAD) && field_width > precision)
484*4882a593Smuzhiyun precision = field_width;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun output:
487*4882a593Smuzhiyun /* Calculate the padding necessary */
488*4882a593Smuzhiyun field_width -= precision;
489*4882a593Smuzhiyun /* Leading padding with ' ' */
490*4882a593Smuzhiyun if (!(flags & LEFT))
491*4882a593Smuzhiyun while (field_width-- > 0)
492*4882a593Smuzhiyun PUTC(' ');
493*4882a593Smuzhiyun /* sign */
494*4882a593Smuzhiyun if (sign)
495*4882a593Smuzhiyun PUTC(sign);
496*4882a593Smuzhiyun /* 0x/0X for hexadecimal */
497*4882a593Smuzhiyun if (flags & SPECIAL) {
498*4882a593Smuzhiyun PUTC('0');
499*4882a593Smuzhiyun PUTC( 'X' | (flags & SMALL));
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun /* Zero padding and excess precision */
502*4882a593Smuzhiyun while (precision-- > len)
503*4882a593Smuzhiyun PUTC('0');
504*4882a593Smuzhiyun /* Actual output */
505*4882a593Smuzhiyun if (flags & WIDE) {
506*4882a593Smuzhiyun const u16 *ws = (const u16 *)s;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun while (len-- > 0) {
509*4882a593Smuzhiyun u32 c32 = utf16_to_utf32(&ws);
510*4882a593Smuzhiyun u8 *s8;
511*4882a593Smuzhiyun size_t clen;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun if (c32 < 0x80) {
514*4882a593Smuzhiyun PUTC(c32);
515*4882a593Smuzhiyun continue;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /* Number of trailing octets */
519*4882a593Smuzhiyun clen = 1 + (c32 >= 0x800) + (c32 >= 0x10000);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun len -= clen;
522*4882a593Smuzhiyun s8 = (u8 *)&buf[pos];
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /* Avoid writing partial character */
525*4882a593Smuzhiyun PUTC('\0');
526*4882a593Smuzhiyun pos += clen;
527*4882a593Smuzhiyun if (pos >= size)
528*4882a593Smuzhiyun continue;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* Set high bits of leading octet */
531*4882a593Smuzhiyun *s8 = (0xf00 >> 1) >> clen;
532*4882a593Smuzhiyun /* Write trailing octets in reverse order */
533*4882a593Smuzhiyun for (s8 += clen; clen; --clen, c32 >>= 6)
534*4882a593Smuzhiyun *s8-- = 0x80 | (c32 & 0x3f);
535*4882a593Smuzhiyun /* Set low bits of leading octet */
536*4882a593Smuzhiyun *s8 |= c32;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun } else {
539*4882a593Smuzhiyun while (len-- > 0)
540*4882a593Smuzhiyun PUTC(*s++);
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun /* Trailing padding with ' ' */
543*4882a593Smuzhiyun while (field_width-- > 0)
544*4882a593Smuzhiyun PUTC(' ');
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun fail:
547*4882a593Smuzhiyun va_end(args);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (size)
550*4882a593Smuzhiyun buf[min(pos, size-1)] = '\0';
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun return pos;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
snprintf(char * buf,size_t size,const char * fmt,...)555*4882a593Smuzhiyun int snprintf(char *buf, size_t size, const char *fmt, ...)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun va_list args;
558*4882a593Smuzhiyun int i;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun va_start(args, fmt);
561*4882a593Smuzhiyun i = vsnprintf(buf, size, fmt, args);
562*4882a593Smuzhiyun va_end(args);
563*4882a593Smuzhiyun return i;
564*4882a593Smuzhiyun }
565