1
|
/*
|
2
|
* linux/lib/vsprintf.c
|
3
|
*
|
4
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
5
|
*/
|
6
|
|
7
|
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
|
8
|
/*
|
9
|
* Wirzenius wrote this portably, Torvalds fucked it up :-)
|
10
|
*/
|
11
|
|
12
|
/*
|
13
|
* Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
|
14
|
* - changed to provide snprintf and vsnprintf functions
|
15
|
* So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
|
16
|
* - scnprintf and vscnprintf
|
17
|
*/
|
18
|
|
19
|
#include <stdarg.h>
|
20
|
#include <limits.h>
|
21
|
#include <sys/types.h>
|
22
|
#include <string.h>
|
23
|
#include <asm/ctype.h>
|
24
|
|
25
|
#include <asm/div64.h>
|
26
|
|
27
|
/**
|
28
|
* simple_strtoul - convert a string to an unsigned long
|
29
|
* @cp: The start of the string
|
30
|
* @endp: A pointer to the end of the parsed string will be placed here
|
31
|
* @base: The number base to use
|
32
|
*/
|
33
|
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
|
34
|
{
|
35
|
unsigned long result = 0,value;
|
36
|
|
37
|
if (!base) {
|
38
|
base = 10;
|
39
|
if (*cp == '0') {
|
40
|
base = 8;
|
41
|
cp++;
|
42
|
if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
|
43
|
cp++;
|
44
|
base = 16;
|
45
|
}
|
46
|
}
|
47
|
} else if (base == 16) {
|
48
|
if (cp[0] == '0' && toupper(cp[1]) == 'X')
|
49
|
cp += 2;
|
50
|
}
|
51
|
while (isxdigit(*cp) &&
|
52
|
(value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
|
53
|
result = result*base + value;
|
54
|
cp++;
|
55
|
}
|
56
|
if (endp)
|
57
|
*endp = (char *)cp;
|
58
|
return result;
|
59
|
}
|
60
|
|
61
|
|
62
|
/**
|
63
|
* simple_strtol - convert a string to a signed long
|
64
|
* @cp: The start of the string
|
65
|
* @endp: A pointer to the end of the parsed string will be placed here
|
66
|
* @base: The number base to use
|
67
|
*/
|
68
|
long simple_strtol(const char *cp,char **endp,unsigned int base)
|
69
|
{
|
70
|
if(*cp=='-')
|
71
|
return -simple_strtoul(cp+1,endp,base);
|
72
|
return simple_strtoul(cp,endp,base);
|
73
|
}
|
74
|
|
75
|
|
76
|
/**
|
77
|
* simple_strtoull - convert a string to an unsigned long long
|
78
|
* @cp: The start of the string
|
79
|
* @endp: A pointer to the end of the parsed string will be placed here
|
80
|
* @base: The number base to use
|
81
|
*/
|
82
|
unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
|
83
|
{
|
84
|
unsigned long long result = 0,value;
|
85
|
|
86
|
if (!base) {
|
87
|
base = 10;
|
88
|
if (*cp == '0') {
|
89
|
base = 8;
|
90
|
cp++;
|
91
|
if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
|
92
|
cp++;
|
93
|
base = 16;
|
94
|
}
|
95
|
}
|
96
|
} else if (base == 16) {
|
97
|
if (cp[0] == '0' && toupper(cp[1]) == 'X')
|
98
|
cp += 2;
|
99
|
}
|
100
|
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
|
101
|
? toupper(*cp) : *cp)-'A'+10) < base) {
|
102
|
result = result*base + value;
|
103
|
cp++;
|
104
|
}
|
105
|
if (endp)
|
106
|
*endp = (char *)cp;
|
107
|
return result;
|
108
|
}
|
109
|
|
110
|
|
111
|
/**
|
112
|
* simple_strtoll - convert a string to a signed long long
|
113
|
* @cp: The start of the string
|
114
|
* @endp: A pointer to the end of the parsed string will be placed here
|
115
|
* @base: The number base to use
|
116
|
*/
|
117
|
long long simple_strtoll(const char *cp,char **endp,unsigned int base)
|
118
|
{
|
119
|
if(*cp=='-')
|
120
|
return -simple_strtoull(cp+1,endp,base);
|
121
|
return simple_strtoull(cp,endp,base);
|
122
|
}
|
123
|
|
124
|
static int skip_atoi(const char **s)
|
125
|
{
|
126
|
int i=0;
|
127
|
|
128
|
while (isdigit(**s))
|
129
|
i = i*10 + *((*s)++) - '0';
|
130
|
return i;
|
131
|
}
|
132
|
|
133
|
#define ZEROPAD 1 /* pad with zero */
|
134
|
#define SIGN 2 /* unsigned/signed long */
|
135
|
#define PLUS 4 /* show plus */
|
136
|
#define SPACE 8 /* space if plus */
|
137
|
#define LEFT 16 /* left justified */
|
138
|
#define SPECIAL 32 /* 0x */
|
139
|
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
140
|
|
141
|
static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
|
142
|
{
|
143
|
char c,sign,tmp[66];
|
144
|
const char *digits;
|
145
|
static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
146
|
static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
147
|
int i;
|
148
|
|
149
|
digits = (type & LARGE) ? large_digits : small_digits;
|
150
|
if (type & LEFT)
|
151
|
type &= ~ZEROPAD;
|
152
|
if (base < 2 || base > 36)
|
153
|
return NULL;
|
154
|
c = (type & ZEROPAD) ? '0' : ' ';
|
155
|
sign = 0;
|
156
|
if (type & SIGN) {
|
157
|
if ((signed long long) num < 0) {
|
158
|
sign = '-';
|
159
|
num = - (signed long long) num;
|
160
|
size--;
|
161
|
} else if (type & PLUS) {
|
162
|
sign = '+';
|
163
|
size--;
|
164
|
} else if (type & SPACE) {
|
165
|
sign = ' ';
|
166
|
size--;
|
167
|
}
|
168
|
}
|
169
|
if (type & SPECIAL) {
|
170
|
if (base == 16)
|
171
|
size -= 2;
|
172
|
else if (base == 8)
|
173
|
size--;
|
174
|
}
|
175
|
i = 0;
|
176
|
if (num == 0)
|
177
|
tmp[i++]='0';
|
178
|
else while (num != 0)
|
179
|
tmp[i++] = digits[do_div(num,base)];
|
180
|
if (i > precision)
|
181
|
precision = i;
|
182
|
size -= precision;
|
183
|
if (!(type&(ZEROPAD+LEFT))) {
|
184
|
while(size-->0) {
|
185
|
if (buf <= end)
|
186
|
*buf = ' ';
|
187
|
++buf;
|
188
|
}
|
189
|
}
|
190
|
if (sign) {
|
191
|
if (buf <= end)
|
192
|
*buf = sign;
|
193
|
++buf;
|
194
|
}
|
195
|
if (type & SPECIAL) {
|
196
|
if (base==8) {
|
197
|
if (buf <= end)
|
198
|
*buf = '0';
|
199
|
++buf;
|
200
|
} else if (base==16) {
|
201
|
if (buf <= end)
|
202
|
*buf = '0';
|
203
|
++buf;
|
204
|
if (buf <= end)
|
205
|
*buf = digits[33];
|
206
|
++buf;
|
207
|
}
|
208
|
}
|
209
|
if (!(type & LEFT)) {
|
210
|
while (size-- > 0) {
|
211
|
if (buf <= end)
|
212
|
*buf = c;
|
213
|
++buf;
|
214
|
}
|
215
|
}
|
216
|
while (i < precision--) {
|
217
|
if (buf <= end)
|
218
|
*buf = '0';
|
219
|
++buf;
|
220
|
}
|
221
|
while (i-- > 0) {
|
222
|
if (buf <= end)
|
223
|
*buf = tmp[i];
|
224
|
++buf;
|
225
|
}
|
226
|
while (size-- > 0) {
|
227
|
if (buf <= end)
|
228
|
*buf = ' ';
|
229
|
++buf;
|
230
|
}
|
231
|
return buf;
|
232
|
}
|
233
|
|
234
|
/**
|
235
|
* vsnprintf - Format a string and place it in a buffer
|
236
|
* @buf: The buffer to place the result into
|
237
|
* @size: The size of the buffer, including the trailing null space
|
238
|
* @fmt: The format string to use
|
239
|
* @args: Arguments for the format string
|
240
|
*
|
241
|
* The return value is the number of characters which would
|
242
|
* be generated for the given input, excluding the trailing
|
243
|
* '\0', as per ISO C99. If you want to have the exact
|
244
|
* number of characters written into @buf as return value
|
245
|
* (not including the trailing '\0'), use vscnprintf. If the
|
246
|
* return is greater than or equal to @size, the resulting
|
247
|
* string is truncated.
|
248
|
*
|
249
|
* Call this function if you are already dealing with a va_list.
|
250
|
* You probably want snprintf instead.
|
251
|
*/
|
252
|
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
253
|
{
|
254
|
int len;
|
255
|
unsigned long long num;
|
256
|
int i, base;
|
257
|
char *str, *end, c;
|
258
|
const char *s;
|
259
|
|
260
|
int flags; /* flags to number() */
|
261
|
|
262
|
int field_width; /* width of output field */
|
263
|
int precision; /* min. # of digits for integers; max
|
264
|
number of chars for from string */
|
265
|
int qualifier; /* 'h', 'l', or 'L' for integer fields */
|
266
|
/* 'z' support added 23/7/1999 S.H. */
|
267
|
/* 'z' changed to 'Z' --davidm 1/25/99 */
|
268
|
/* 't' added for ptrdiff_t */
|
269
|
|
270
|
/* Reject out-of-range values early */
|
271
|
if ((int) size < 0) {
|
272
|
return 0;
|
273
|
}
|
274
|
|
275
|
str = buf;
|
276
|
end = buf + size - 1;
|
277
|
|
278
|
if (end < buf - 1) {
|
279
|
end = ((void *) -1);
|
280
|
size = end - buf + 1;
|
281
|
}
|
282
|
|
283
|
for (; *fmt ; ++fmt) {
|
284
|
if (*fmt != '%') {
|
285
|
if (str <= end)
|
286
|
*str = *fmt;
|
287
|
++str;
|
288
|
continue;
|
289
|
}
|
290
|
|
291
|
/* process flags */
|
292
|
flags = 0;
|
293
|
repeat:
|
294
|
++fmt; /* this also skips first '%' */
|
295
|
switch (*fmt) {
|
296
|
case '-': flags |= LEFT; goto repeat;
|
297
|
case '+': flags |= PLUS; goto repeat;
|
298
|
case ' ': flags |= SPACE; goto repeat;
|
299
|
case '#': flags |= SPECIAL; goto repeat;
|
300
|
case '0': flags |= ZEROPAD; goto repeat;
|
301
|
}
|
302
|
|
303
|
/* get field width */
|
304
|
field_width = -1;
|
305
|
if (isdigit(*fmt))
|
306
|
field_width = skip_atoi(&fmt);
|
307
|
else if (*fmt == '*') {
|
308
|
++fmt;
|
309
|
/* it's the next argument */
|
310
|
field_width = va_arg(args, int);
|
311
|
if (field_width < 0) {
|
312
|
field_width = -field_width;
|
313
|
flags |= LEFT;
|
314
|
}
|
315
|
}
|
316
|
|
317
|
/* get the precision */
|
318
|
precision = -1;
|
319
|
if (*fmt == '.') {
|
320
|
++fmt;
|
321
|
if (isdigit(*fmt))
|
322
|
precision = skip_atoi(&fmt);
|
323
|
else if (*fmt == '*') {
|
324
|
++fmt;
|
325
|
/* it's the next argument */
|
326
|
precision = va_arg(args, int);
|
327
|
}
|
328
|
if (precision < 0)
|
329
|
precision = 0;
|
330
|
}
|
331
|
|
332
|
/* get the conversion qualifier */
|
333
|
qualifier = -1;
|
334
|
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
|
335
|
*fmt =='Z' || *fmt == 'z' || *fmt == 't') {
|
336
|
qualifier = *fmt;
|
337
|
++fmt;
|
338
|
if (qualifier == 'l' && *fmt == 'l') {
|
339
|
qualifier = 'L';
|
340
|
++fmt;
|
341
|
}
|
342
|
}
|
343
|
|
344
|
/* default base */
|
345
|
base = 10;
|
346
|
|
347
|
switch (*fmt) {
|
348
|
case 'c':
|
349
|
if (!(flags & LEFT)) {
|
350
|
while (--field_width > 0) {
|
351
|
if (str <= end)
|
352
|
*str = ' ';
|
353
|
++str;
|
354
|
}
|
355
|
}
|
356
|
c = (unsigned char) va_arg(args, int);
|
357
|
if (str <= end)
|
358
|
*str = c;
|
359
|
++str;
|
360
|
while (--field_width > 0) {
|
361
|
if (str <= end)
|
362
|
*str = ' ';
|
363
|
++str;
|
364
|
}
|
365
|
continue;
|
366
|
|
367
|
case 's':
|
368
|
s = va_arg(args, char *);
|
369
|
|
370
|
len = strnlen(s, precision);
|
371
|
|
372
|
if (!(flags & LEFT)) {
|
373
|
while (len < field_width--) {
|
374
|
if (str <= end)
|
375
|
*str = ' ';
|
376
|
++str;
|
377
|
}
|
378
|
}
|
379
|
for (i = 0; i < len; ++i) {
|
380
|
if (str <= end)
|
381
|
*str = *s;
|
382
|
++str; ++s;
|
383
|
}
|
384
|
while (len < field_width--) {
|
385
|
if (str <= end)
|
386
|
*str = ' ';
|
387
|
++str;
|
388
|
}
|
389
|
continue;
|
390
|
|
391
|
case 'p':
|
392
|
if (field_width == -1) {
|
393
|
field_width = 2*sizeof(void *);
|
394
|
flags |= ZEROPAD;
|
395
|
}
|
396
|
str = number(str, end,
|
397
|
(unsigned long) va_arg(args, void *),
|
398
|
16, field_width, precision, flags);
|
399
|
continue;
|
400
|
|
401
|
|
402
|
case 'n':
|
403
|
/* FIXME:
|
404
|
* What does C99 say about the overflow case here? */
|
405
|
if (qualifier == 'l') {
|
406
|
long * ip = va_arg(args, long *);
|
407
|
*ip = (str - buf);
|
408
|
} else if (qualifier == 'Z' || qualifier == 'z') {
|
409
|
size_t * ip = va_arg(args, size_t *);
|
410
|
*ip = (str - buf);
|
411
|
} else {
|
412
|
int * ip = va_arg(args, int *);
|
413
|
*ip = (str - buf);
|
414
|
}
|
415
|
continue;
|
416
|
|
417
|
case '%':
|
418
|
if (str <= end)
|
419
|
*str = '%';
|
420
|
++str;
|
421
|
continue;
|
422
|
|
423
|
/* integer number formats - set up the flags and "break" */
|
424
|
case 'o':
|
425
|
base = 8;
|
426
|
break;
|
427
|
|
428
|
case 'X':
|
429
|
flags |= LARGE;
|
430
|
case 'x':
|
431
|
base = 16;
|
432
|
break;
|
433
|
|
434
|
case 'd':
|
435
|
case 'i':
|
436
|
flags |= SIGN;
|
437
|
case 'u':
|
438
|
break;
|
439
|
|
440
|
default:
|
441
|
if (str <= end)
|
442
|
*str = '%';
|
443
|
++str;
|
444
|
if (*fmt) {
|
445
|
if (str <= end)
|
446
|
*str = *fmt;
|
447
|
++str;
|
448
|
} else {
|
449
|
--fmt;
|
450
|
}
|
451
|
continue;
|
452
|
}
|
453
|
if (qualifier == 'L')
|
454
|
num = va_arg(args, long long);
|
455
|
else if (qualifier == 'l') {
|
456
|
num = va_arg(args, unsigned long);
|
457
|
if (flags & SIGN)
|
458
|
num = (signed long) num;
|
459
|
} else if (qualifier == 'Z' || qualifier == 'z') {
|
460
|
num = va_arg(args, size_t);
|
461
|
} else if (qualifier == 't') {
|
462
|
num = va_arg(args, ptrdiff_t);
|
463
|
} else if (qualifier == 'h') {
|
464
|
num = (unsigned short) va_arg(args, int);
|
465
|
if (flags & SIGN)
|
466
|
num = (signed short) num;
|
467
|
} else {
|
468
|
num = va_arg(args, unsigned int);
|
469
|
if (flags & SIGN)
|
470
|
num = (signed int) num;
|
471
|
}
|
472
|
str = number(str, end, num, base,
|
473
|
field_width, precision, flags);
|
474
|
}
|
475
|
if (str <= end)
|
476
|
*str = '\0';
|
477
|
else if (size > 0)
|
478
|
/* don't write out a null byte if the buf size is zero */
|
479
|
*end = '\0';
|
480
|
/* the trailing null byte doesn't count towards the total
|
481
|
* ++str;
|
482
|
*/
|
483
|
return str-buf;
|
484
|
}
|
485
|
|
486
|
|
487
|
/**
|
488
|
* vscnprintf - Format a string and place it in a buffer
|
489
|
* @buf: The buffer to place the result into
|
490
|
* @size: The size of the buffer, including the trailing null space
|
491
|
* @fmt: The format string to use
|
492
|
* @args: Arguments for the format string
|
493
|
*
|
494
|
* The return value is the number of characters which have been written into
|
495
|
* the @buf not including the trailing '\0'. If @size is <= 0 the function
|
496
|
* returns 0.
|
497
|
*
|
498
|
* Call this function if you are already dealing with a va_list.
|
499
|
* You probably want scnprintf instead.
|
500
|
*/
|
501
|
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
502
|
{
|
503
|
unsigned int i;
|
504
|
|
505
|
i=vsnprintf(buf,size,fmt,args);
|
506
|
return (i >= size) ? (size - 1) : i;
|
507
|
}
|
508
|
|
509
|
|
510
|
/**
|
511
|
* snprintf - Format a string and place it in a buffer
|
512
|
* @buf: The buffer to place the result into
|
513
|
* @size: The size of the buffer, including the trailing null space
|
514
|
* @fmt: The format string to use
|
515
|
* @...: Arguments for the format string
|
516
|
*
|
517
|
* The return value is the number of characters which would be
|
518
|
* generated for the given input, excluding the trailing null,
|
519
|
* as per ISO C99. If the return is greater than or equal to
|
520
|
* @size, the resulting string is truncated.
|
521
|
*/
|
522
|
int snprintf(char * buf, size_t size, const char *fmt, ...)
|
523
|
{
|
524
|
va_list args;
|
525
|
int i;
|
526
|
|
527
|
va_start(args, fmt);
|
528
|
i=vsnprintf(buf,size,fmt,args);
|
529
|
va_end(args);
|
530
|
return i;
|
531
|
}
|
532
|
|
533
|
|
534
|
/**
|
535
|
* scnprintf - Format a string and place it in a buffer
|
536
|
* @buf: The buffer to place the result into
|
537
|
* @size: The size of the buffer, including the trailing null space
|
538
|
* @fmt: The format string to use
|
539
|
* @...: Arguments for the format string
|
540
|
*
|
541
|
* The return value is the number of characters written into @buf not including
|
542
|
* the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
|
543
|
* greater than or equal to @size, the resulting string is truncated.
|
544
|
*/
|
545
|
|
546
|
int scnprintf(char * buf, size_t size, const char *fmt, ...)
|
547
|
{
|
548
|
va_list args;
|
549
|
unsigned int i;
|
550
|
|
551
|
va_start(args, fmt);
|
552
|
i = vsnprintf(buf, size, fmt, args);
|
553
|
va_end(args);
|
554
|
return (i >= size) ? (size - 1) : i;
|
555
|
}
|
556
|
|
557
|
/**
|
558
|
* vsprintf - Format a string and place it in a buffer
|
559
|
* @buf: The buffer to place the result into
|
560
|
* @fmt: The format string to use
|
561
|
* @args: Arguments for the format string
|
562
|
*
|
563
|
* The function returns the number of characters written
|
564
|
* into @buf. Use vsnprintf or vscnprintf in order to avoid
|
565
|
* buffer overflows.
|
566
|
*
|
567
|
* Call this function if you are already dealing with a va_list.
|
568
|
* You probably want sprintf instead.
|
569
|
*/
|
570
|
int vsprintf(char *buf, const char *fmt, va_list args)
|
571
|
{
|
572
|
return vsnprintf(buf, INT_MAX, fmt, args);
|
573
|
}
|
574
|
|
575
|
|
576
|
/**
|
577
|
* sprintf - Format a string and place it in a buffer
|
578
|
* @buf: The buffer to place the result into
|
579
|
* @fmt: The format string to use
|
580
|
* @...: Arguments for the format string
|
581
|
*
|
582
|
* The function returns the number of characters written
|
583
|
* into @buf. Use snprintf or scnprintf in order to avoid
|
584
|
* buffer overflows.
|
585
|
*/
|
586
|
int sprintf(char * buf, const char *fmt, ...)
|
587
|
{
|
588
|
va_list args;
|
589
|
int i;
|
590
|
|
591
|
va_start(args, fmt);
|
592
|
i=vsnprintf(buf, INT_MAX, fmt, args);
|
593
|
va_end(args);
|
594
|
return i;
|
595
|
}
|
596
|
|
597
|
|
598
|
/**
|
599
|
* vsscanf - Unformat a buffer into a list of arguments
|
600
|
* @buf: input buffer
|
601
|
* @fmt: format of buffer
|
602
|
* @args: arguments
|
603
|
*/
|
604
|
int vsscanf(const char * buf, const char * fmt, va_list args)
|
605
|
{
|
606
|
const char *str = buf;
|
607
|
char *next;
|
608
|
char digit;
|
609
|
int num = 0;
|
610
|
int qualifier;
|
611
|
int base;
|
612
|
int field_width;
|
613
|
int is_sign = 0;
|
614
|
|
615
|
while(*fmt && *str) {
|
616
|
/* skip any white space in format */
|
617
|
/* white space in format matchs any amount of
|
618
|
* white space, including none, in the input.
|
619
|
*/
|
620
|
if (isspace(*fmt)) {
|
621
|
while (isspace(*fmt))
|
622
|
++fmt;
|
623
|
while (isspace(*str))
|
624
|
++str;
|
625
|
}
|
626
|
|
627
|
/* anything that is not a conversion must match exactly */
|
628
|
if (*fmt != '%' && *fmt) {
|
629
|
if (*fmt++ != *str++)
|
630
|
break;
|
631
|
continue;
|
632
|
}
|
633
|
|
634
|
if (!*fmt)
|
635
|
break;
|
636
|
++fmt;
|
637
|
|
638
|
/* skip this conversion.
|
639
|
* advance both strings to next white space
|
640
|
*/
|
641
|
if (*fmt == '*') {
|
642
|
while (!isspace(*fmt) && *fmt)
|
643
|
fmt++;
|
644
|
while (!isspace(*str) && *str)
|
645
|
str++;
|
646
|
continue;
|
647
|
}
|
648
|
|
649
|
/* get field width */
|
650
|
field_width = -1;
|
651
|
if (isdigit(*fmt))
|
652
|
field_width = skip_atoi(&fmt);
|
653
|
|
654
|
/* get conversion qualifier */
|
655
|
qualifier = -1;
|
656
|
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
|
657
|
*fmt == 'Z' || *fmt == 'z') {
|
658
|
qualifier = *fmt++;
|
659
|
if (qualifier == *fmt) {
|
660
|
if (qualifier == 'h') {
|
661
|
qualifier = 'H';
|
662
|
fmt++;
|
663
|
} else if (qualifier == 'l') {
|
664
|
qualifier = 'L';
|
665
|
fmt++;
|
666
|
}
|
667
|
}
|
668
|
}
|
669
|
base = 10;
|
670
|
is_sign = 0;
|
671
|
|
672
|
if (!*fmt || !*str)
|
673
|
break;
|
674
|
|
675
|
switch(*fmt++) {
|
676
|
case 'c':
|
677
|
{
|
678
|
char *s = (char *) va_arg(args,char*);
|
679
|
if (field_width == -1)
|
680
|
field_width = 1;
|
681
|
do {
|
682
|
*s++ = *str++;
|
683
|
} while (--field_width > 0 && *str);
|
684
|
num++;
|
685
|
}
|
686
|
continue;
|
687
|
case 's':
|
688
|
{
|
689
|
char *s = (char *) va_arg(args, char *);
|
690
|
if(field_width == -1)
|
691
|
field_width = INT_MAX;
|
692
|
/* first, skip leading white space in buffer */
|
693
|
while (isspace(*str))
|
694
|
str++;
|
695
|
|
696
|
/* now copy until next white space */
|
697
|
while (*str && !isspace(*str) && field_width--) {
|
698
|
*s++ = *str++;
|
699
|
}
|
700
|
*s = '\0';
|
701
|
num++;
|
702
|
}
|
703
|
continue;
|
704
|
case 'n':
|
705
|
/* return number of characters read so far */
|
706
|
{
|
707
|
int *i = (int *)va_arg(args,int*);
|
708
|
*i = str - buf;
|
709
|
}
|
710
|
continue;
|
711
|
case 'o':
|
712
|
base = 8;
|
713
|
break;
|
714
|
case 'x':
|
715
|
case 'X':
|
716
|
base = 16;
|
717
|
break;
|
718
|
case 'i':
|
719
|
base = 0;
|
720
|
case 'd':
|
721
|
is_sign = 1;
|
722
|
case 'u':
|
723
|
break;
|
724
|
case '%':
|
725
|
/* looking for '%' in str */
|
726
|
if (*str++ != '%')
|
727
|
return num;
|
728
|
continue;
|
729
|
default:
|
730
|
/* invalid format; stop here */
|
731
|
return num;
|
732
|
}
|
733
|
|
734
|
/* have some sort of integer conversion.
|
735
|
* first, skip white space in buffer.
|
736
|
*/
|
737
|
while (isspace(*str))
|
738
|
str++;
|
739
|
|
740
|
digit = *str;
|
741
|
if (is_sign && digit == '-')
|
742
|
digit = *(str + 1);
|
743
|
|
744
|
if (!digit
|
745
|
|| (base == 16 && !isxdigit(digit))
|
746
|
|| (base == 10 && !isdigit(digit))
|
747
|
|| (base == 8 && (!isdigit(digit) || digit > '7'))
|
748
|
|| (base == 0 && !isdigit(digit)))
|
749
|
break;
|
750
|
|
751
|
switch(qualifier) {
|
752
|
case 'H': /* that's 'hh' in format */
|
753
|
if (is_sign) {
|
754
|
signed char *s = (signed char *) va_arg(args,signed char *);
|
755
|
*s = (signed char) simple_strtol(str,&next,base);
|
756
|
} else {
|
757
|
unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
|
758
|
*s = (unsigned char) simple_strtoul(str, &next, base);
|
759
|
}
|
760
|
break;
|
761
|
case 'h':
|
762
|
if (is_sign) {
|
763
|
short *s = (short *) va_arg(args,short *);
|
764
|
*s = (short) simple_strtol(str,&next,base);
|
765
|
} else {
|
766
|
unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
|
767
|
*s = (unsigned short) simple_strtoul(str, &next, base);
|
768
|
}
|
769
|
break;
|
770
|
case 'l':
|
771
|
if (is_sign) {
|
772
|
long *l = (long *) va_arg(args,long *);
|
773
|
*l = simple_strtol(str,&next,base);
|
774
|
} else {
|
775
|
unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
|
776
|
*l = simple_strtoul(str,&next,base);
|
777
|
}
|
778
|
break;
|
779
|
case 'L':
|
780
|
if (is_sign) {
|
781
|
long long *l = (long long*) va_arg(args,long long *);
|
782
|
*l = simple_strtoll(str,&next,base);
|
783
|
} else {
|
784
|
unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
|
785
|
*l = simple_strtoull(str,&next,base);
|
786
|
}
|
787
|
break;
|
788
|
case 'Z':
|
789
|
case 'z':
|
790
|
{
|
791
|
size_t *s = (size_t*) va_arg(args,size_t*);
|
792
|
*s = (size_t) simple_strtoul(str,&next,base);
|
793
|
}
|
794
|
break;
|
795
|
default:
|
796
|
if (is_sign) {
|
797
|
int *i = (int *) va_arg(args, int*);
|
798
|
*i = (int) simple_strtol(str,&next,base);
|
799
|
} else {
|
800
|
unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
|
801
|
*i = (unsigned int) simple_strtoul(str,&next,base);
|
802
|
}
|
803
|
break;
|
804
|
}
|
805
|
num++;
|
806
|
|
807
|
if (!next)
|
808
|
break;
|
809
|
str = next;
|
810
|
}
|
811
|
return num;
|
812
|
}
|
813
|
|
814
|
|
815
|
/**
|
816
|
* sscanf - Unformat a buffer into a list of arguments
|
817
|
* @buf: input buffer
|
818
|
* @fmt: formatting of buffer
|
819
|
* @...: resulting arguments
|
820
|
*/
|
821
|
int sscanf(const char * buf, const char * fmt, ...)
|
822
|
{
|
823
|
va_list args;
|
824
|
int i;
|
825
|
|
826
|
va_start(args,fmt);
|
827
|
i = vsscanf(buf,fmt,args);
|
828
|
va_end(args);
|
829
|
return i;
|
830
|
}
|
831
|
|