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