Reformat ...
[linux-2.6/linux-mips.git] / lib / vsprintf.c
blobf790458f4520a56310f920014a736cf11cc8be49
1 /*
2 * linux/lib/vsprintf.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8 /*
9 * Wirzenius wrote this portably, Torvalds fucked it up :-)
12 /*
13 * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
14 * - changed to provide snprintf and vsnprintf functions
17 #include <stdarg.h>
18 #include <linux/types.h>
19 #include <linux/string.h>
20 #include <linux/ctype.h>
21 #include <linux/kernel.h>
23 #include <asm/div64.h>
25 /**
26 * simple_strtoul - convert a string to an unsigned long
27 * @cp: The start of the string
28 * @endp: A pointer to the end of the parsed string will be placed here
29 * @base: The number base to use
31 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
33 unsigned long result = 0,value;
35 if (!base) {
36 base = 10;
37 if (*cp == '0') {
38 base = 8;
39 cp++;
40 if ((*cp == 'x') && isxdigit(cp[1])) {
41 cp++;
42 base = 16;
46 while (isxdigit(*cp) &&
47 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
48 result = result*base + value;
49 cp++;
51 if (endp)
52 *endp = (char *)cp;
53 return result;
56 /**
57 * simple_strtol - convert a string to a signed long
58 * @cp: The start of the string
59 * @endp: A pointer to the end of the parsed string will be placed here
60 * @base: The number base to use
62 long simple_strtol(const char *cp,char **endp,unsigned int base)
64 if(*cp=='-')
65 return -simple_strtoul(cp+1,endp,base);
66 return simple_strtoul(cp,endp,base);
69 /**
70 * simple_strtoull - convert a string to an unsigned long long
71 * @cp: The start of the string
72 * @endp: A pointer to the end of the parsed string will be placed here
73 * @base: The number base to use
75 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
77 unsigned long long result = 0,value;
79 if (!base) {
80 base = 10;
81 if (*cp == '0') {
82 base = 8;
83 cp++;
84 if ((*cp == 'x') && isxdigit(cp[1])) {
85 cp++;
86 base = 16;
90 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
91 ? toupper(*cp) : *cp)-'A'+10) < base) {
92 result = result*base + value;
93 cp++;
95 if (endp)
96 *endp = (char *)cp;
97 return result;
101 * simple_strtoll - convert a string to a signed long long
102 * @cp: The start of the string
103 * @endp: A pointer to the end of the parsed string will be placed here
104 * @base: The number base to use
106 long long simple_strtoll(const char *cp,char **endp,unsigned int base)
108 if(*cp=='-')
109 return -simple_strtoull(cp+1,endp,base);
110 return simple_strtoull(cp,endp,base);
113 static int skip_atoi(const char **s)
115 int i=0;
117 while (isdigit(**s))
118 i = i*10 + *((*s)++) - '0';
119 return i;
122 #define ZEROPAD 1 /* pad with zero */
123 #define SIGN 2 /* unsigned/signed long */
124 #define PLUS 4 /* show plus */
125 #define SPACE 8 /* space if plus */
126 #define LEFT 16 /* left justified */
127 #define SPECIAL 32 /* 0x */
128 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
130 static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type)
132 char c,sign,tmp[66];
133 const char *digits;
134 static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
135 static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
136 int i;
138 digits = (type & LARGE) ? large_digits : small_digits;
139 if (type & LEFT)
140 type &= ~ZEROPAD;
141 if (base < 2 || base > 36)
142 return 0;
143 c = (type & ZEROPAD) ? '0' : ' ';
144 sign = 0;
145 if (type & SIGN) {
146 if (num < 0) {
147 sign = '-';
148 num = -num;
149 size--;
150 } else if (type & PLUS) {
151 sign = '+';
152 size--;
153 } else if (type & SPACE) {
154 sign = ' ';
155 size--;
158 if (type & SPECIAL) {
159 if (base == 16)
160 size -= 2;
161 else if (base == 8)
162 size--;
164 i = 0;
165 if (num == 0)
166 tmp[i++]='0';
167 else while (num != 0)
168 tmp[i++] = digits[do_div(num,base)];
169 if (i > precision)
170 precision = i;
171 size -= precision;
172 if (!(type&(ZEROPAD+LEFT))) {
173 while(size-->0) {
174 if (buf <= end)
175 *buf = ' ';
176 ++buf;
179 if (sign) {
180 if (buf <= end)
181 *buf = sign;
182 ++buf;
184 if (type & SPECIAL) {
185 if (base==8) {
186 if (buf <= end)
187 *buf = '0';
188 ++buf;
189 } else if (base==16) {
190 if (buf <= end)
191 *buf = '0';
192 ++buf;
193 if (buf <= end)
194 *buf = digits[33];
195 ++buf;
198 if (!(type & LEFT)) {
199 while (size-- > 0) {
200 if (buf <= end)
201 *buf = c;
202 ++buf;
205 while (i < precision--) {
206 if (buf <= end)
207 *buf = '0';
208 ++buf;
210 while (i-- > 0) {
211 if (buf <= end)
212 *buf = tmp[i];
213 ++buf;
215 while (size-- > 0) {
216 if (buf <= end)
217 *buf = ' ';
218 ++buf;
220 return buf;
224 * vsnprintf - Format a string and place it in a buffer
225 * @buf: The buffer to place the result into
226 * @size: The size of the buffer, including the trailing null space
227 * @fmt: The format string to use
228 * @args: Arguments for the format string
230 * Call this function if you are already dealing with a va_list.
231 * You probably want snprintf instead.
233 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
235 int len;
236 unsigned long long num;
237 int i, base;
238 char *str, *end, c;
239 const char *s;
241 int flags; /* flags to number() */
243 int field_width; /* width of output field */
244 int precision; /* min. # of digits for integers; max
245 number of chars for from string */
246 int qualifier; /* 'h', 'l', or 'L' for integer fields */
247 /* 'z' support added 23/7/1999 S.H. */
248 /* 'z' changed to 'Z' --davidm 1/25/99 */
250 str = buf;
251 end = buf + size - 1;
253 if (end < buf - 1) {
254 end = ((void *) -1);
255 size = end - buf + 1;
258 for (; *fmt ; ++fmt) {
259 if (*fmt != '%') {
260 if (str <= end)
261 *str = *fmt;
262 ++str;
263 continue;
266 /* process flags */
267 flags = 0;
268 repeat:
269 ++fmt; /* this also skips first '%' */
270 switch (*fmt) {
271 case '-': flags |= LEFT; goto repeat;
272 case '+': flags |= PLUS; goto repeat;
273 case ' ': flags |= SPACE; goto repeat;
274 case '#': flags |= SPECIAL; goto repeat;
275 case '0': flags |= ZEROPAD; goto repeat;
278 /* get field width */
279 field_width = -1;
280 if (isdigit(*fmt))
281 field_width = skip_atoi(&fmt);
282 else if (*fmt == '*') {
283 ++fmt;
284 /* it's the next argument */
285 field_width = va_arg(args, int);
286 if (field_width < 0) {
287 field_width = -field_width;
288 flags |= LEFT;
292 /* get the precision */
293 precision = -1;
294 if (*fmt == '.') {
295 ++fmt;
296 if (isdigit(*fmt))
297 precision = skip_atoi(&fmt);
298 else if (*fmt == '*') {
299 ++fmt;
300 /* it's the next argument */
301 precision = va_arg(args, int);
303 if (precision < 0)
304 precision = 0;
307 /* get the conversion qualifier */
308 qualifier = -1;
309 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
310 *fmt =='Z' || *fmt == 'z') {
311 qualifier = *fmt;
312 ++fmt;
313 if (qualifier == 'l' && *fmt == 'l') {
314 qualifier = 'L';
315 ++fmt;
319 /* default base */
320 base = 10;
322 switch (*fmt) {
323 case 'c':
324 if (!(flags & LEFT)) {
325 while (--field_width > 0) {
326 if (str <= end)
327 *str = ' ';
328 ++str;
331 c = (unsigned char) va_arg(args, int);
332 if (str <= end)
333 *str = c;
334 ++str;
335 while (--field_width > 0) {
336 if (str <= end)
337 *str = ' ';
338 ++str;
340 continue;
342 case 's':
343 s = va_arg(args, char *);
344 if (!s)
345 s = "<NULL>";
347 len = strnlen(s, precision);
349 if (!(flags & LEFT)) {
350 while (len < field_width--) {
351 if (str <= end)
352 *str = ' ';
353 ++str;
356 for (i = 0; i < len; ++i) {
357 if (str <= end)
358 *str = *s;
359 ++str; ++s;
361 while (len < field_width--) {
362 if (str <= end)
363 *str = ' ';
364 ++str;
366 continue;
368 case 'p':
369 if (field_width == -1) {
370 field_width = 2*sizeof(void *);
371 flags |= ZEROPAD;
373 str = number(str, end,
374 (unsigned long) va_arg(args, void *),
375 16, field_width, precision, flags);
376 continue;
379 case 'n':
380 /* FIXME:
381 * What does C99 say about the overflow case here? */
382 if (qualifier == 'l') {
383 long * ip = va_arg(args, long *);
384 *ip = (str - buf);
385 } else if (qualifier == 'Z' || qualifier == 'z') {
386 size_t * ip = va_arg(args, size_t *);
387 *ip = (str - buf);
388 } else {
389 int * ip = va_arg(args, int *);
390 *ip = (str - buf);
392 continue;
394 case '%':
395 if (str <= end)
396 *str = '%';
397 ++str;
398 continue;
400 /* integer number formats - set up the flags and "break" */
401 case 'o':
402 base = 8;
403 break;
405 case 'X':
406 flags |= LARGE;
407 case 'x':
408 base = 16;
409 break;
411 case 'd':
412 case 'i':
413 flags |= SIGN;
414 case 'u':
415 break;
417 default:
418 if (str <= end)
419 *str = '%';
420 ++str;
421 if (*fmt) {
422 if (str <= end)
423 *str = *fmt;
424 ++str;
425 } else {
426 --fmt;
428 continue;
430 if (qualifier == 'L')
431 num = va_arg(args, long long);
432 else if (qualifier == 'l') {
433 num = va_arg(args, unsigned long);
434 if (flags & SIGN)
435 num = (signed long) num;
436 } else if (qualifier == 'Z' || qualifier == 'z') {
437 num = va_arg(args, size_t);
438 } else if (qualifier == 'h') {
439 num = (unsigned short) va_arg(args, int);
440 if (flags & SIGN)
441 num = (signed short) num;
442 } else {
443 num = va_arg(args, unsigned int);
444 if (flags & SIGN)
445 num = (signed int) num;
447 str = number(str, end, num, base,
448 field_width, precision, flags);
450 if (str <= end)
451 *str = '\0';
452 else if (size > 0)
453 /* don't write out a null byte if the buf size is zero */
454 *end = '\0';
455 /* the trailing null byte doesn't count towards the total
456 * ++str;
458 return str-buf;
462 * snprintf - Format a string and place it in a buffer
463 * @buf: The buffer to place the result into
464 * @size: The size of the buffer, including the trailing null space
465 * @fmt: The format string to use
466 * @...: Arguments for the format string
468 int snprintf(char * buf, size_t size, const char *fmt, ...)
470 va_list args;
471 int i;
473 va_start(args, fmt);
474 i=vsnprintf(buf,size,fmt,args);
475 va_end(args);
476 return i;
480 * vsprintf - Format a string and place it in a buffer
481 * @buf: The buffer to place the result into
482 * @fmt: The format string to use
483 * @args: Arguments for the format string
485 * Call this function if you are already dealing with a va_list.
486 * You probably want sprintf instead.
488 int vsprintf(char *buf, const char *fmt, va_list args)
490 return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args);
495 * sprintf - Format a string and place it in a buffer
496 * @buf: The buffer to place the result into
497 * @fmt: The format string to use
498 * @...: Arguments for the format string
500 int sprintf(char * buf, const char *fmt, ...)
502 va_list args;
503 int i;
505 va_start(args, fmt);
506 i=vsprintf(buf,fmt,args);
507 va_end(args);
508 return i;
512 * vsscanf - Unformat a buffer into a list of arguments
513 * @buf: input buffer
514 * @fmt: format of buffer
515 * @args: arguments
517 int vsscanf(const char * buf, const char * fmt, va_list args)
519 const char *str = buf;
520 char *next;
521 char digit;
522 int num = 0;
523 int qualifier;
524 int base;
525 int field_width;
526 int is_sign = 0;
528 while(*fmt && *str) {
529 /* skip any white space in format */
530 /* white space in format matchs any amount of
531 * white space, including none, in the input.
533 if (isspace(*fmt)) {
534 while (isspace(*fmt))
535 ++fmt;
536 while (isspace(*str))
537 ++str;
540 /* anything that is not a conversion must match exactly */
541 if (*fmt != '%' && *fmt) {
542 if (*fmt++ != *str++)
543 break;
544 continue;
547 if (!*fmt)
548 break;
549 ++fmt;
551 /* skip this conversion.
552 * advance both strings to next white space
554 if (*fmt == '*') {
555 while (!isspace(*fmt) && *fmt)
556 fmt++;
557 while (!isspace(*str) && *str)
558 str++;
559 continue;
562 /* get field width */
563 field_width = -1;
564 if (isdigit(*fmt))
565 field_width = skip_atoi(&fmt);
567 /* get conversion qualifier */
568 qualifier = -1;
569 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
570 *fmt == 'Z' || *fmt == 'z') {
571 qualifier = *fmt;
572 fmt++;
574 base = 10;
575 is_sign = 0;
577 if (!*fmt || !*str)
578 break;
580 switch(*fmt++) {
581 case 'c':
583 char *s = (char *) va_arg(args,char*);
584 if (field_width == -1)
585 field_width = 1;
586 do {
587 *s++ = *str++;
588 } while(field_width-- > 0 && *str);
589 num++;
591 continue;
592 case 's':
594 char *s = (char *) va_arg(args, char *);
595 if(field_width == -1)
596 field_width = INT_MAX;
597 /* first, skip leading white space in buffer */
598 while (isspace(*str))
599 str++;
601 /* now copy until next white space */
602 while (*str && !isspace(*str) && field_width--) {
603 *s++ = *str++;
605 *s = '\0';
606 num++;
608 continue;
609 case 'n':
610 /* return number of characters read so far */
612 int *i = (int *)va_arg(args,int*);
613 *i = str - buf;
615 continue;
616 case 'o':
617 base = 8;
618 break;
619 case 'x':
620 case 'X':
621 base = 16;
622 break;
623 case 'i':
624 base = 0;
625 case 'd':
626 is_sign = 1;
627 case 'u':
628 break;
629 case '%':
630 /* looking for '%' in str */
631 if (*str++ != '%')
632 return num;
633 continue;
634 default:
635 /* invalid format; stop here */
636 return num;
639 /* have some sort of integer conversion.
640 * first, skip white space in buffer.
642 while (isspace(*str))
643 str++;
645 digit = *str;
646 if (is_sign && digit == '-')
647 digit = *(str + 1);
649 if (!digit
650 || (base == 16 && !isxdigit(digit))
651 || (base == 10 && !isdigit(digit))
652 || (base == 8 && (!isdigit(digit) || digit > '7'))
653 || (base == 0 && !isdigit(digit)))
654 break;
656 switch(qualifier) {
657 case 'h':
658 if (is_sign) {
659 short *s = (short *) va_arg(args,short *);
660 *s = (short) simple_strtol(str,&next,base);
661 } else {
662 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
663 *s = (unsigned short) simple_strtoul(str, &next, base);
665 break;
666 case 'l':
667 if (is_sign) {
668 long *l = (long *) va_arg(args,long *);
669 *l = simple_strtol(str,&next,base);
670 } else {
671 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
672 *l = simple_strtoul(str,&next,base);
674 break;
675 case 'L':
676 if (is_sign) {
677 long long *l = (long long*) va_arg(args,long long *);
678 *l = simple_strtoll(str,&next,base);
679 } else {
680 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
681 *l = simple_strtoull(str,&next,base);
683 break;
684 case 'Z':
685 case 'z':
687 size_t *s = (size_t*) va_arg(args,size_t*);
688 *s = (size_t) simple_strtoul(str,&next,base);
690 break;
691 default:
692 if (is_sign) {
693 int *i = (int *) va_arg(args, int*);
694 *i = (int) simple_strtol(str,&next,base);
695 } else {
696 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
697 *i = (unsigned int) simple_strtoul(str,&next,base);
699 break;
701 num++;
703 if (!next)
704 break;
705 str = next;
707 return num;
711 * sscanf - Unformat a buffer into a list of arguments
712 * @buf: input buffer
713 * @fmt: formatting of buffer
714 * @...: resulting arguments
716 int sscanf(const char * buf, const char * fmt, ...)
718 va_list args;
719 int i;
721 va_start(args,fmt);
722 i = vsscanf(buf,fmt,args);
723 va_end(args);
724 return i;