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