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