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