14
14
15
15
#include <linux/compiler.h>
16
16
#include <linux/ctype.h>
17
+ #include <linux/kernel.h>
17
18
#include <linux/limits.h>
18
19
#include <linux/string.h>
19
20
20
- static int skip_atoi (const char * * s )
21
+ static
22
+ int skip_atoi (const char * * s )
21
23
{
22
24
int i = 0 ;
23
25
@@ -32,16 +34,16 @@ static int skip_atoi(const char **s)
32
34
* r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
33
35
*/
34
36
static
35
- void put_dec_full4 (char * buf , unsigned int r )
37
+ void put_dec_full4 (char * end , unsigned int r )
36
38
{
37
39
int i ;
38
40
39
41
for (i = 0 ; i < 3 ; i ++ ) {
40
42
unsigned int q = (r * 0xccd ) >> 15 ;
41
- * buf ++ = '0' + (r - q * 10 );
43
+ * -- end = '0' + (r - q * 10 );
42
44
r = q ;
43
45
}
44
- * buf ++ = '0' + r ;
46
+ * -- end = '0' + r ;
45
47
}
46
48
47
49
/* put_dec is copied from lib/vsprintf.c with small modifications */
@@ -54,11 +56,11 @@ void put_dec_full4(char *buf, unsigned int r)
54
56
* (second call in the put_dec code, assuming n is all-ones).
55
57
*/
56
58
static
57
- unsigned int put_dec_helper4 (char * buf , unsigned int x )
59
+ unsigned int put_dec_helper4 (char * end , unsigned int x )
58
60
{
59
61
unsigned int q = (x * 0x346DC5D7ULL ) >> 43 ;
60
62
61
- put_dec_full4 (buf , x - q * 10000 );
63
+ put_dec_full4 (end , x - q * 10000 );
62
64
return q ;
63
65
}
64
66
@@ -68,10 +70,10 @@ unsigned int put_dec_helper4(char *buf, unsigned int x)
68
70
* Performs no 64-bit division and hence should be fast on 32-bit machines.
69
71
*/
70
72
static
71
- int put_dec (char * buf , unsigned long long n )
73
+ char * put_dec (char * end , unsigned long long n )
72
74
{
73
75
unsigned int d3 , d2 , d1 , q , h ;
74
- char * p = buf ;
76
+ char * p = end ;
75
77
76
78
d1 = ((unsigned int )n >> 16 ); /* implicit "& 0xffff" */
77
79
h = (n >> 32 );
@@ -82,28 +84,59 @@ int put_dec(char *buf, unsigned long long n)
82
84
= 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
83
85
q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int )n & 0xffff );
84
86
q = put_dec_helper4 (p , q );
85
- p + = 4 ;
87
+ p - = 4 ;
86
88
87
89
q += 7671 * d3 + 9496 * d2 + 6 * d1 ;
88
90
q = put_dec_helper4 (p , q );
89
- p + = 4 ;
91
+ p - = 4 ;
90
92
91
93
q += 4749 * d3 + 42 * d2 ;
92
94
q = put_dec_helper4 (p , q );
93
- p + = 4 ;
95
+ p - = 4 ;
94
96
95
97
q += 281 * d3 ;
96
98
q = put_dec_helper4 (p , q );
97
- p + = 4 ;
99
+ p - = 4 ;
98
100
99
101
put_dec_full4 (p , q );
100
- p + = 4 ;
102
+ p - = 4 ;
101
103
102
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 ;
109
+ }
110
+
111
+ static
112
+ char * 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 ;
107
140
}
108
141
109
142
#define ZEROPAD 1 /* pad with zero */
@@ -114,95 +147,6 @@ int put_dec(char *buf, unsigned long long n)
114
147
#define SMALL 32 /* Must be 32 == 0x20 */
115
148
#define SPECIAL 64 /* 0x */
116
149
117
- static 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
-
206
150
static
207
151
int get_flags (const char * * fmt )
208
152
{
@@ -277,13 +221,33 @@ unsigned long long get_number(int sign, int qualifier, va_list *ap)
277
221
}
278
222
}
279
223
224
+ static
225
+ char 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
+
280
240
int vsprintf (char * buf , const char * fmt , va_list ap )
281
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
247
char * str ;
286
248
const char * s ;
249
+ int len ;
250
+ char sign ;
287
251
288
252
int flags ; /* flags to number() */
289
253
@@ -326,6 +290,9 @@ int vsprintf(char *buf, const char *fmt, va_list ap)
326
290
flags |= LEFT ;
327
291
}
328
292
293
+ if (flags & LEFT )
294
+ flags &= ~ZEROPAD ;
295
+
329
296
/* get the precision */
330
297
precision = -1 ;
331
298
if (* fmt == '.' ) {
@@ -346,32 +313,25 @@ int vsprintf(char *buf, const char *fmt, va_list ap)
346
313
}
347
314
}
348
315
316
+ sign = 0 ;
317
+
349
318
switch (* fmt ) {
350
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
325
359
326
case 's' :
327
+ flags &= LEFT ;
360
328
if (precision < 0 )
361
329
precision = INT_MAX ;
362
330
s = va_arg (args , char * );
363
331
if (!s )
364
332
s = precision < 6 ? "" : "(null)" ;
365
- len = strnlen (s , precision );
366
-
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 ;
333
+ precision = len = strnlen (s , precision );
334
+ goto output ;
375
335
376
336
/* integer number formats - set up the flags and "break" */
377
337
case 'o' :
@@ -394,6 +354,7 @@ int vsprintf(char *buf, const char *fmt, va_list ap)
394
354
flags |= SIGN ;
395
355
fallthrough ;
396
356
case 'u' :
357
+ flags &= ~SPECIAL ;
397
358
base = 10 ;
398
359
break ;
399
360
@@ -410,7 +371,68 @@ int vsprintf(char *buf, const char *fmt, va_list ap)
410
371
} else {
411
372
num = get_number (flags & SIGN , qualifier , & args );
412
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
+
412
+ output :
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
436
}
415
437
* str = '\0' ;
416
438
0 commit comments