vsprintf.c (fb031937a86874e6d663542bdbd83e310c13610e) vsprintf.c (6c4bcd8a46a98856c06ca3ba8a80f03a61e23960)
1// SPDX-License-Identifier: GPL-2.0-only
2/* -*- linux-c -*- ------------------------------------------------------- *
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright 2007 rPath, Inc. - All Rights Reserved
6 *
7 * ----------------------------------------------------------------------- */
8
9/*
10 * Oh, it's a waste of space, but oh-so-yummy for debugging.
11 */
12
13#include <stdarg.h>
14
15#include <linux/compiler.h>
16#include <linux/ctype.h>
1// SPDX-License-Identifier: GPL-2.0-only
2/* -*- linux-c -*- ------------------------------------------------------- *
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright 2007 rPath, Inc. - All Rights Reserved
6 *
7 * ----------------------------------------------------------------------- */
8
9/*
10 * Oh, it's a waste of space, but oh-so-yummy for debugging.
11 */
12
13#include <stdarg.h>
14
15#include <linux/compiler.h>
16#include <linux/ctype.h>
17#include <linux/kernel.h>
17#include <linux/limits.h>
18#include <linux/string.h>
19
18#include <linux/limits.h>
19#include <linux/string.h>
20
20static int skip_atoi(const char **s)
21static
22int skip_atoi(const char **s)
21{
22 int i = 0;
23
24 while (isdigit(**s))
25 i = i * 10 + *((*s)++) - '0';
26 return i;
27}
28
29/*
30 * put_dec_full4 handles numbers in the range 0 <= r < 10000.
31 * The multiplier 0xccd is round(2^15/10), and the approximation
32 * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
33 */
34static
23{
24 int i = 0;
25
26 while (isdigit(**s))
27 i = i * 10 + *((*s)++) - '0';
28 return i;
29}
30
31/*
32 * put_dec_full4 handles numbers in the range 0 <= r < 10000.
33 * The multiplier 0xccd is round(2^15/10), and the approximation
34 * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
35 */
36static
35void put_dec_full4(char *buf, unsigned int r)
37void put_dec_full4(char *end, unsigned int r)
36{
37 int i;
38
39 for (i = 0; i < 3; i++) {
40 unsigned int q = (r * 0xccd) >> 15;
38{
39 int i;
40
41 for (i = 0; i < 3; i++) {
42 unsigned int q = (r * 0xccd) >> 15;
41 *buf++ = '0' + (r - q * 10);
43 *--end = '0' + (r - q * 10);
42 r = q;
43 }
44 r = q;
45 }
44 *buf++ = '0' + r;
46 *--end = '0' + r;
45}
46
47/* put_dec is copied from lib/vsprintf.c with small modifications */
48
49/*
50 * Call put_dec_full4 on x % 10000, return x / 10000.
51 * The approximation x/10000 == (x * 0x346DC5D7) >> 43
52 * holds for all x < 1,128,869,999. The largest value this
53 * helper will ever be asked to convert is 1,125,520,955.
54 * (second call in the put_dec code, assuming n is all-ones).
55 */
56static
47}
48
49/* put_dec is copied from lib/vsprintf.c with small modifications */
50
51/*
52 * Call put_dec_full4 on x % 10000, return x / 10000.
53 * The approximation x/10000 == (x * 0x346DC5D7) >> 43
54 * holds for all x < 1,128,869,999. The largest value this
55 * helper will ever be asked to convert is 1,125,520,955.
56 * (second call in the put_dec code, assuming n is all-ones).
57 */
58static
57unsigned int put_dec_helper4(char *buf, unsigned int x)
59unsigned int put_dec_helper4(char *end, unsigned int x)
58{
59 unsigned int q = (x * 0x346DC5D7ULL) >> 43;
60
60{
61 unsigned int q = (x * 0x346DC5D7ULL) >> 43;
62
61 put_dec_full4(buf, x - q * 10000);
63 put_dec_full4(end, x - q * 10000);
62 return q;
63}
64
65/* Based on code by Douglas W. Jones found at
66 * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
67 * (with permission from the author).
68 * Performs no 64-bit division and hence should be fast on 32-bit machines.
69 */
70static
64 return q;
65}
66
67/* Based on code by Douglas W. Jones found at
68 * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
69 * (with permission from the author).
70 * Performs no 64-bit division and hence should be fast on 32-bit machines.
71 */
72static
71int put_dec(char *buf, unsigned long long n)
73char *put_dec(char *end, unsigned long long n)
72{
73 unsigned int d3, d2, d1, q, h;
74{
75 unsigned int d3, d2, d1, q, h;
74 char *p = buf;
76 char *p = end;
75
76 d1 = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
77 h = (n >> 32);
78 d2 = (h ) & 0xffff;
79 d3 = (h >> 16); /* implicit "& 0xffff" */
80
81 /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
82 = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
83 q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
84 q = put_dec_helper4(p, q);
77
78 d1 = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
79 h = (n >> 32);
80 d2 = (h ) & 0xffff;
81 d3 = (h >> 16); /* implicit "& 0xffff" */
82
83 /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
84 = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
85 q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
86 q = put_dec_helper4(p, q);
85 p += 4;
87 p -= 4;
86
87 q += 7671 * d3 + 9496 * d2 + 6 * d1;
88 q = put_dec_helper4(p, q);
88
89 q += 7671 * d3 + 9496 * d2 + 6 * d1;
90 q = put_dec_helper4(p, q);
89 p += 4;
91 p -= 4;
90
91 q += 4749 * d3 + 42 * d2;
92 q = put_dec_helper4(p, q);
92
93 q += 4749 * d3 + 42 * d2;
94 q = put_dec_helper4(p, q);
93 p += 4;
95 p -= 4;
94
95 q += 281 * d3;
96 q = put_dec_helper4(p, q);
96
97 q += 281 * d3;
98 q = put_dec_helper4(p, q);
97 p += 4;
99 p -= 4;
98
99 put_dec_full4(p, q);
100
101 put_dec_full4(p, q);
100 p += 4;
102 p -= 4;
101
102 /* strip off the extra 0's we printed */
103
104 /* strip off the extra 0's we printed */
103 while (p > buf && p[-1] == '0')
104 --p;
105 while (p < end && *p == '0')
106 ++p;
105
107
106 return p - buf;
108 return p;
107}
108
109}
110
111static
112char *number(char *end, unsigned long long num, int base, char locase)
113{
114 /*
115 * locase = 0 or 0x20. ORing digits or letters with 'locase'
116 * produces same digits or (maybe lowercased) letters
117 */
118
119 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
120 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
121
122 switch (base) {
123 case 10:
124 if (num != 0)
125 end = put_dec(end, num);
126 break;
127 case 8:
128 for (; num != 0; num >>= 3)
129 *--end = '0' + (num & 07);
130 break;
131 case 16:
132 for (; num != 0; num >>= 4)
133 *--end = digits[num & 0xf] | locase;
134 break;
135 default:
136 unreachable();
137 };
138
139 return end;
140}
141
109#define ZEROPAD 1 /* pad with zero */
110#define SIGN 2 /* unsigned/signed long */
111#define PLUS 4 /* show plus */
112#define SPACE 8 /* space if plus */
113#define LEFT 16 /* left justified */
114#define SMALL 32 /* Must be 32 == 0x20 */
115#define SPECIAL 64 /* 0x */
116
142#define ZEROPAD 1 /* pad with zero */
143#define SIGN 2 /* unsigned/signed long */
144#define PLUS 4 /* show plus */
145#define SPACE 8 /* space if plus */
146#define LEFT 16 /* left justified */
147#define SMALL 32 /* Must be 32 == 0x20 */
148#define SPECIAL 64 /* 0x */
149
117static char *number(char *str, long long num, int base, int size, int precision,
118 int type)
119{
120 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
121 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
122
123 char tmp[66];
124 char c, sign, locase;
125 int i;
126
127 /* locase = 0 or 0x20. ORing digits or letters with 'locase'
128 * produces same digits or (maybe lowercased) letters */
129 locase = (type & SMALL);
130 if (type & LEFT)
131 type &= ~ZEROPAD;
132 c = (type & ZEROPAD) ? '0' : ' ';
133 sign = 0;
134 if (type & SIGN) {
135 if (num < 0) {
136 sign = '-';
137 num = -num;
138 size--;
139 } else if (type & PLUS) {
140 sign = '+';
141 size--;
142 } else if (type & SPACE) {
143 sign = ' ';
144 size--;
145 }
146 }
147 if (type & SPECIAL) {
148 if (base == 16)
149 size -= 2;
150 else if (base == 8)
151 size--;
152 }
153 i = 0;
154 if (num == 0)
155 tmp[i++] = '0';
156 else {
157 switch (base) {
158 case 10:
159 i += put_dec(&tmp[i], num);
160 break;
161 case 8:
162 while (num != 0) {
163 tmp[i++] = '0' + (num & 07);
164 num = (unsigned long long)num >> 3;
165 }
166 break;
167 case 16:
168 while (num != 0) {
169 tmp[i++] = digits[num & 0xf] | locase;
170 num = (unsigned long long)num >> 4;
171 }
172 break;
173 default:
174 unreachable();
175 }
176 }
177
178 if (i > precision)
179 precision = i;
180 size -= precision;
181 if (!(type & (ZEROPAD + LEFT)))
182 while (size-- > 0)
183 *str++ = ' ';
184 if (sign)
185 *str++ = sign;
186 if (type & SPECIAL) {
187 if (base == 8) {
188 *str++ = '0';
189 } else if (base == 16) {
190 *str++ = '0';
191 *str++ = ('X' | locase);
192 }
193 }
194 if (!(type & LEFT))
195 while (size-- > 0)
196 *str++ = c;
197 while (i < precision--)
198 *str++ = '0';
199 while (i-- > 0)
200 *str++ = tmp[i];
201 while (size-- > 0)
202 *str++ = ' ';
203 return str;
204}
205
206static
207int get_flags(const char **fmt)
208{
209 int flags = 0;
210
211 do {
212 switch (**fmt) {
213 case '-':

--- 58 unchanged lines hidden (view full) ---

272 case 'H':
273 return (unsigned char)va_arg(*ap, int);
274 default:
275 return va_arg(*ap, unsigned int);
276 }
277 }
278}
279
150static
151int get_flags(const char **fmt)
152{
153 int flags = 0;
154
155 do {
156 switch (**fmt) {
157 case '-':

--- 58 unchanged lines hidden (view full) ---

216 case 'H':
217 return (unsigned char)va_arg(*ap, int);
218 default:
219 return va_arg(*ap, unsigned int);
220 }
221 }
222}
223
224static
225char get_sign(long long *num, int flags)
226{
227 if (!(flags & SIGN))
228 return 0;
229 if (*num < 0) {
230 *num = -(*num);
231 return '-';
232 }
233 if (flags & PLUS)
234 return '+';
235 if (flags & SPACE)
236 return ' ';
237 return 0;
238}
239
280int vsprintf(char *buf, const char *fmt, va_list ap)
281{
240int vsprintf(char *buf, const char *fmt, va_list ap)
241{
282 int len;
283 unsigned long long num;
284 int i, base;
242 /* The maximum space required is to print a 64-bit number in octal */
243 char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
244 char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
245 long long num;
246 int base;
285 char *str;
286 const char *s;
247 char *str;
248 const char *s;
249 int len;
250 char sign;
287
288 int flags; /* flags to number() */
289
290 int field_width; /* width of output field */
291 int precision; /* min. # of digits for integers; max
292 number of chars for from string */
293 int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */
294

--- 26 unchanged lines hidden (view full) ---

321
322 /* get field width */
323 field_width = get_int(&fmt, &args);
324 if (field_width < 0) {
325 field_width = -field_width;
326 flags |= LEFT;
327 }
328
251
252 int flags; /* flags to number() */
253
254 int field_width; /* width of output field */
255 int precision; /* min. # of digits for integers; max
256 number of chars for from string */
257 int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */
258

--- 26 unchanged lines hidden (view full) ---

285
286 /* get field width */
287 field_width = get_int(&fmt, &args);
288 if (field_width < 0) {
289 field_width = -field_width;
290 flags |= LEFT;
291 }
292
293 if (flags & LEFT)
294 flags &= ~ZEROPAD;
295
329 /* get the precision */
330 precision = -1;
331 if (*fmt == '.') {
332 ++fmt;
333 precision = get_int(&fmt, &args);
334 if (precision >= 0)
335 flags &= ~ZEROPAD;
336 }

--- 4 unchanged lines hidden (view full) ---

341 qualifier = *fmt;
342 ++fmt;
343 if (qualifier == *fmt) {
344 qualifier -= 'a'-'A';
345 ++fmt;
346 }
347 }
348
296 /* get the precision */
297 precision = -1;
298 if (*fmt == '.') {
299 ++fmt;
300 precision = get_int(&fmt, &args);
301 if (precision >= 0)
302 flags &= ~ZEROPAD;
303 }

--- 4 unchanged lines hidden (view full) ---

308 qualifier = *fmt;
309 ++fmt;
310 if (qualifier == *fmt) {
311 qualifier -= 'a'-'A';
312 ++fmt;
313 }
314 }
315
316 sign = 0;
317
349 switch (*fmt) {
350 case 'c':
318 switch (*fmt) {
319 case 'c':
351 if (!(flags & LEFT))
352 while (--field_width > 0)
353 *str++ = ' ';
354 *str++ = (unsigned char)va_arg(args, int);
355 while (--field_width > 0)
356 *str++ = ' ';
357 continue;
320 flags &= LEFT;
321 tmp[0] = (unsigned char)va_arg(args, int);
322 s = tmp;
323 precision = len = 1;
324 goto output;
358
359 case 's':
325
326 case 's':
327 flags &= LEFT;
360 if (precision < 0)
361 precision = INT_MAX;
362 s = va_arg(args, char *);
363 if (!s)
364 s = precision < 6 ? "" : "(null)";
328 if (precision < 0)
329 precision = INT_MAX;
330 s = va_arg(args, char *);
331 if (!s)
332 s = precision < 6 ? "" : "(null)";
365 len = strnlen(s, precision);
333 precision = len = strnlen(s, precision);
334 goto output;
366
335
367 if (!(flags & LEFT))
368 while (len < field_width--)
369 *str++ = ' ';
370 for (i = 0; i < len; ++i)
371 *str++ = *s++;
372 while (len < field_width--)
373 *str++ = ' ';
374 continue;
375
376 /* integer number formats - set up the flags and "break" */
377 case 'o':
378 base = 8;
379 break;
380
381 case 'p':
382 if (precision < 0)
383 precision = 2 * sizeof(void *);

--- 5 unchanged lines hidden (view full) ---

389 base = 16;
390 break;
391
392 case 'd':
393 case 'i':
394 flags |= SIGN;
395 fallthrough;
396 case 'u':
336 /* integer number formats - set up the flags and "break" */
337 case 'o':
338 base = 8;
339 break;
340
341 case 'p':
342 if (precision < 0)
343 precision = 2 * sizeof(void *);

--- 5 unchanged lines hidden (view full) ---

349 base = 16;
350 break;
351
352 case 'd':
353 case 'i':
354 flags |= SIGN;
355 fallthrough;
356 case 'u':
357 flags &= ~SPECIAL;
397 base = 10;
398 break;
399
400 default:
401 *str++ = '%';
402 if (*fmt)
403 *str++ = *fmt;
404 else
405 --fmt;
406 continue;
407 }
408 if (*fmt == 'p') {
409 num = (unsigned long)va_arg(args, void *);
410 } else {
411 num = get_number(flags & SIGN, qualifier, &args);
412 }
358 base = 10;
359 break;
360
361 default:
362 *str++ = '%';
363 if (*fmt)
364 *str++ = *fmt;
365 else
366 --fmt;
367 continue;
368 }
369 if (*fmt == 'p') {
370 num = (unsigned long)va_arg(args, void *);
371 } else {
372 num = get_number(flags & SIGN, qualifier, &args);
373 }
413 str = number(str, num, base, field_width, precision, flags);
374
375 sign = get_sign(&num, flags);
376 if (sign)
377 --field_width;
378
379 s = number(tmp_end, num, base, flags & SMALL);
380 len = tmp_end - s;
381 /* default precision is 1 */
382 if (precision < 0)
383 precision = 1;
384 /* precision is minimum number of digits to print */
385 if (precision < len)
386 precision = len;
387 if (flags & SPECIAL) {
388 /*
389 * For octal, a leading 0 is printed only if necessary,
390 * i.e. if it's not already there because of the
391 * precision.
392 */
393 if (base == 8 && precision == len)
394 ++precision;
395 /*
396 * For hexadecimal, the leading 0x is skipped if the
397 * output is empty, i.e. both the number and the
398 * precision are 0.
399 */
400 if (base == 16 && precision > 0)
401 field_width -= 2;
402 else
403 flags &= ~SPECIAL;
404 }
405 /*
406 * For zero padding, increase the precision to fill the field
407 * width.
408 */
409 if ((flags & ZEROPAD) && field_width > precision)
410 precision = field_width;
411
412output:
413 /* Calculate the padding necessary */
414 field_width -= precision;
415 /* Leading padding with ' ' */
416 if (!(flags & LEFT))
417 while (field_width-- > 0)
418 *str++ = ' ';
419 /* sign */
420 if (sign)
421 *str++ = sign;
422 /* 0x/0X for hexadecimal */
423 if (flags & SPECIAL) {
424 *str++ = '0';
425 *str++ = 'X' | (flags & SMALL);
426 }
427 /* Zero padding and excess precision */
428 while (precision-- > len)
429 *str++ = '0';
430 /* Actual output */
431 while (len-- > 0)
432 *str++ = *s++;
433 /* Trailing padding with ' ' */
434 while (field_width-- > 0)
435 *str++ = ' ';
414 }
415 *str = '\0';
416
417 va_end(args);
418
419 return str - buf;
420}
421
422int sprintf(char *buf, const char *fmt, ...)
423{
424 va_list args;
425 int i;
426
427 va_start(args, fmt);
428 i = vsprintf(buf, fmt, args);
429 va_end(args);
430 return i;
431}
436 }
437 *str = '\0';
438
439 va_end(args);
440
441 return str - buf;
442}
443
444int sprintf(char *buf, const char *fmt, ...)
445{
446 va_list args;
447 int i;
448
449 va_start(args, fmt);
450 i = vsprintf(buf, fmt, args);
451 va_end(args);
452 return i;
453}