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 <xen/ctype.h>
20 #include <xen/symbols.h>
21 #include <xen/lib.h>
22 #include <xen/sched.h>
23 #include <xen/livepatch.h>
24 #include <asm/div64.h>
25 #include <asm/page.h>
26
27 /**
28 * simple_strtoul - convert a string to an unsigned long
29 * @cp: The start of the string
30 * @endp: A pointer to the end of the parsed string will be placed here
31 * @base: The number base to use
32 */
simple_strtoul(const char * cp,const char ** endp,unsigned int base)33 unsigned long simple_strtoul(
34 const char *cp, const 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 = 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 */
simple_strtol(const char * cp,const char ** endp,unsigned int base)70 long simple_strtol(const char *cp, const 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 */
simple_strtoull(const char * cp,const char ** endp,unsigned int base)85 unsigned long long simple_strtoull(
86 const char *cp, const char **endp, unsigned int base)
87 {
88 unsigned long long result = 0,value;
89
90 if (!base) {
91 base = 10;
92 if (*cp == '0') {
93 base = 8;
94 cp++;
95 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
96 cp++;
97 base = 16;
98 }
99 }
100 } else if (base == 16) {
101 if (cp[0] == '0' && toupper(cp[1]) == 'X')
102 cp += 2;
103 }
104 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
105 ? toupper(*cp) : *cp)-'A'+10) < base) {
106 result = result*base + value;
107 cp++;
108 }
109 if (endp)
110 *endp = cp;
111 return result;
112 }
113
114 EXPORT_SYMBOL(simple_strtoull);
115
116 /**
117 * simple_strtoll - convert a string to a signed long long
118 * @cp: The start of the string
119 * @endp: A pointer to the end of the parsed string will be placed here
120 * @base: The number base to use
121 */
simple_strtoll(const char * cp,const char ** endp,unsigned int base)122 long long simple_strtoll(const char *cp,const char **endp,unsigned int base)
123 {
124 if(*cp=='-')
125 return -simple_strtoull(cp+1,endp,base);
126 return simple_strtoull(cp,endp,base);
127 }
128
skip_atoi(const char ** s)129 static int skip_atoi(const char **s)
130 {
131 int i=0;
132
133 while (isdigit(**s))
134 i = i*10 + *((*s)++) - '0';
135 return i;
136 }
137
138 #define ZEROPAD 1 /* pad with zero */
139 #define SIGN 2 /* unsigned/signed long */
140 #define PLUS 4 /* show plus */
141 #define SPACE 8 /* space if plus */
142 #define LEFT 16 /* left justified */
143 #define SPECIAL 32 /* 0x */
144 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
145
number(char * buf,char * end,unsigned long long num,int base,int size,int precision,int type)146 static char *number(
147 char *buf, char *end, unsigned long long num,
148 int base, int size, int precision, int type)
149 {
150 char c,sign,tmp[66];
151 const char *digits;
152 static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
153 static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
154 int i;
155
156 ASSERT(base >= 2 && base <= 36);
157
158 digits = (type & LARGE) ? large_digits : small_digits;
159 if (type & LEFT)
160 type &= ~ZEROPAD;
161 c = (type & ZEROPAD) ? '0' : ' ';
162 sign = 0;
163 if (type & SIGN) {
164 if ((signed long long) num < 0) {
165 sign = '-';
166 num = - (signed long long) num;
167 size--;
168 } else if (type & PLUS) {
169 sign = '+';
170 size--;
171 } else if (type & SPACE) {
172 sign = ' ';
173 size--;
174 }
175 }
176 if (type & SPECIAL) {
177 if (num == 0)
178 type &= ~SPECIAL;
179 else if (base == 16)
180 size -= 2;
181 else if (base == 8)
182 size--;
183 else
184 type &= ~SPECIAL;
185 }
186 i = 0;
187 if (num == 0)
188 tmp[i++]='0';
189 else while (num != 0)
190 tmp[i++] = digits[do_div(num,base)];
191 if (i > precision)
192 precision = i;
193 size -= precision;
194 if (!(type&(ZEROPAD+LEFT))) {
195 while(size-->0) {
196 if (buf < end)
197 *buf = ' ';
198 ++buf;
199 }
200 }
201 if (sign) {
202 if (buf < end)
203 *buf = sign;
204 ++buf;
205 }
206 if (type & SPECIAL) {
207 if (buf < end)
208 *buf = '0';
209 ++buf;
210 if (base == 16) {
211 if (buf < end)
212 *buf = digits[33];
213 ++buf;
214 }
215 }
216 if (!(type & LEFT)) {
217 while (size-- > 0) {
218 if (buf < end)
219 *buf = c;
220 ++buf;
221 }
222 }
223 while (i < precision--) {
224 if (buf < end)
225 *buf = '0';
226 ++buf;
227 }
228 while (i-- > 0) {
229 if (buf < end)
230 *buf = tmp[i];
231 ++buf;
232 }
233 while (size-- > 0) {
234 if (buf < end)
235 *buf = ' ';
236 ++buf;
237 }
238 return buf;
239 }
240
string(char * str,char * end,const char * s,int field_width,int precision,int flags)241 static char *string(char *str, char *end, const char *s,
242 int field_width, int precision, int flags)
243 {
244 int i, len = (precision < 0) ? strlen(s) : strnlen(s, precision);
245
246 if (!(flags & LEFT)) {
247 while (len < field_width--) {
248 if (str < end)
249 *str = ' ';
250 ++str;
251 }
252 }
253 for (i = 0; i < len; ++i) {
254 if (str < end)
255 *str = *s;
256 ++str; ++s;
257 }
258 while (len < field_width--) {
259 if (str < end)
260 *str = ' ';
261 ++str;
262 }
263
264 return str;
265 }
266
pointer(char * str,char * end,const char ** fmt_ptr,const void * arg,int field_width,int precision,int flags)267 static char *pointer(char *str, char *end, const char **fmt_ptr,
268 const void *arg, int field_width, int precision,
269 int flags)
270 {
271 const char *fmt = *fmt_ptr, *s;
272
273 /* Custom %p suffixes. See XEN_ROOT/docs/misc/printk-formats.txt */
274 switch ( fmt[1] )
275 {
276 case 'h': /* Raw buffer as hex string. */
277 {
278 const uint8_t *hex_buffer = arg;
279 char sep = ' '; /* Separator character. */
280 unsigned int i;
281
282 /* Consumed 'h' from the format string. */
283 ++*fmt_ptr;
284
285 /* Bound user count from %* to between 0 and 64 bytes. */
286 if ( field_width <= 0 )
287 return str;
288 if ( field_width > 64 )
289 field_width = 64;
290
291 /*
292 * Peek ahead in the format string to see if a recognised separator
293 * modifier is present.
294 */
295 switch ( fmt[2] )
296 {
297 case 'C': /* Colons. */
298 ++*fmt_ptr;
299 sep = ':';
300 break;
301
302 case 'D': /* Dashes. */
303 ++*fmt_ptr;
304 sep = '-';
305 break;
306
307 case 'N': /* No separator. */
308 ++*fmt_ptr;
309 sep = 0;
310 break;
311 }
312
313 for ( i = 0; ; )
314 {
315 /* Each byte: 2 chars, 0-padded, base 16, no hex prefix. */
316 str = number(str, end, hex_buffer[i], 16, 2, -1, ZEROPAD);
317
318 if ( ++i == field_width )
319 return str;
320
321 if ( sep )
322 {
323 if ( str < end )
324 *str = sep;
325 ++str;
326 }
327 }
328 }
329
330 case 's': /* Symbol name with offset and size (iff offset != 0) */
331 case 'S': /* Symbol name unconditionally with offset and size */
332 {
333 unsigned long sym_size, sym_offset;
334 char namebuf[KSYM_NAME_LEN+1];
335
336 /* Advance parents fmt string, as we have consumed 's' or 'S' */
337 ++*fmt_ptr;
338
339 s = symbols_lookup((unsigned long)arg, &sym_size, &sym_offset, namebuf);
340
341 /* If the symbol is not found, fall back to printing the address */
342 if ( !s )
343 break;
344
345 /* Print symbol name */
346 str = string(str, end, s, -1, -1, 0);
347
348 if ( fmt[1] == 'S' || sym_offset != 0 )
349 {
350 /* Print '+<offset>/<len>' */
351 str = number(str, end, sym_offset, 16, -1, -1, SPECIAL|SIGN|PLUS);
352 if ( str < end )
353 *str = '/';
354 ++str;
355 str = number(str, end, sym_size, 16, -1, -1, SPECIAL);
356 }
357
358 /*
359 * namebuf contents and s for core hypervisor are same but for Live Patch
360 * payloads they differ (namebuf contains the name of the payload).
361 */
362 if ( namebuf != s )
363 {
364 str = string(str, end, " [", -1, -1, 0);
365 str = string(str, end, namebuf, -1, -1, 0);
366 str = string(str, end, "]", -1, -1, 0);
367 }
368
369 return str;
370 }
371
372 case 'v': /* d<domain-id>v<vcpu-id> from a struct vcpu */
373 {
374 const struct vcpu *v = arg;
375
376 ++*fmt_ptr;
377 if ( unlikely(v->domain->domain_id == DOMID_IDLE) )
378 str = string(str, end, "IDLE", -1, -1, 0);
379 else
380 {
381 if ( str < end )
382 *str = 'd';
383 str = number(str + 1, end, v->domain->domain_id, 10, -1, -1, 0);
384 }
385 if ( str < end )
386 *str = 'v';
387 return number(str + 1, end, v->vcpu_id, 10, -1, -1, 0);
388 }
389 }
390
391 if ( field_width == -1 )
392 {
393 field_width = 2 * sizeof(void *);
394 flags |= ZEROPAD;
395 }
396
397 return number(str, end, (unsigned long)arg,
398 16, field_width, precision, flags);
399 }
400
401 /**
402 * vsnprintf - Format a string and place it in a buffer
403 * @buf: The buffer to place the result into
404 * @size: The size of the buffer, including the trailing null space
405 * @fmt: The format string to use
406 * @args: Arguments for the format string
407 *
408 * The return value is the number of characters which would
409 * be generated for the given input, excluding the trailing
410 * '\0', as per ISO C99. If you want to have the exact
411 * number of characters written into @buf as return value
412 * (not including the trailing '\0'), use vscnprintf. If the
413 * return is greater than or equal to @size, the resulting
414 * string is truncated.
415 *
416 * Call this function if you are already dealing with a va_list.
417 * You probably want snprintf instead.
418 */
vsnprintf(char * buf,size_t size,const char * fmt,va_list args)419 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
420 {
421 unsigned long long num;
422 int base;
423 char *str, *end, c;
424 const char *s;
425
426 int flags; /* flags to number() */
427
428 int field_width; /* width of output field */
429 int precision; /* min. # of digits for integers; max
430 number of chars for from string */
431 int qualifier; /* 'h', 'l', or 'L' for integer fields */
432 /* 'z' support added 23/7/1999 S.H. */
433 /* 'z' changed to 'Z' --davidm 1/25/99 */
434
435 /* Reject out-of-range values early */
436 BUG_ON(((int)size < 0) || ((unsigned int)size != size));
437
438 str = buf;
439 end = buf + size;
440
441 if (end < buf) {
442 end = ((void *) -1);
443 size = end - buf;
444 }
445
446 for (; *fmt ; ++fmt) {
447 if (*fmt != '%') {
448 if (str < end)
449 *str = *fmt;
450 ++str;
451 continue;
452 }
453
454 /* process flags */
455 flags = 0;
456 repeat:
457 ++fmt; /* this also skips first '%' */
458 switch (*fmt) {
459 case '-': flags |= LEFT; goto repeat;
460 case '+': flags |= PLUS; goto repeat;
461 case ' ': flags |= SPACE; goto repeat;
462 case '#': flags |= SPECIAL; goto repeat;
463 case '0': flags |= ZEROPAD; goto repeat;
464 }
465
466 /* get field width */
467 field_width = -1;
468 if (isdigit(*fmt))
469 field_width = skip_atoi(&fmt);
470 else if (*fmt == '*') {
471 ++fmt;
472 /* it's the next argument */
473 field_width = va_arg(args, int);
474 if (field_width < 0) {
475 field_width = -field_width;
476 flags |= LEFT;
477 }
478 }
479
480 /* get the precision */
481 precision = -1;
482 if (*fmt == '.') {
483 ++fmt;
484 if (isdigit(*fmt))
485 precision = skip_atoi(&fmt);
486 else if (*fmt == '*') {
487 ++fmt;
488 /* it's the next argument */
489 precision = va_arg(args, int);
490 }
491 if (precision < 0)
492 precision = 0;
493 }
494
495 /* get the conversion qualifier */
496 qualifier = -1;
497 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
498 *fmt =='Z' || *fmt == 'z') {
499 qualifier = *fmt;
500 ++fmt;
501 if (qualifier == 'l' && *fmt == 'l') {
502 qualifier = 'L';
503 ++fmt;
504 }
505 }
506
507 /* default base */
508 base = 10;
509
510 switch (*fmt) {
511 case 'c':
512 if (!(flags & LEFT)) {
513 while (--field_width > 0) {
514 if (str < end)
515 *str = ' ';
516 ++str;
517 }
518 }
519 c = (unsigned char) va_arg(args, int);
520 if (str < end)
521 *str = c;
522 ++str;
523 while (--field_width > 0) {
524 if (str < end)
525 *str = ' ';
526 ++str;
527 }
528 continue;
529
530 case 's':
531 s = va_arg(args, char *);
532 if ((unsigned long)s < PAGE_SIZE)
533 s = "<NULL>";
534
535 str = string(str, end, s, field_width, precision, flags);
536 continue;
537
538 case 'p':
539 /* pointer() might advance fmt (%pS for example) */
540 str = pointer(str, end, &fmt, va_arg(args, const void *),
541 field_width, precision, flags);
542 continue;
543
544
545 case 'n':
546 if (qualifier == 'l') {
547 long * ip = va_arg(args, long *);
548 *ip = (str - buf);
549 } else if (qualifier == 'Z' || qualifier == 'z') {
550 size_t * ip = va_arg(args, size_t *);
551 *ip = (str - buf);
552 } else {
553 int * ip = va_arg(args, int *);
554 *ip = (str - buf);
555 }
556 continue;
557
558 case '%':
559 if (str < end)
560 *str = '%';
561 ++str;
562 continue;
563
564 /* integer number formats - set up the flags and "break" */
565 case 'o':
566 base = 8;
567 break;
568
569 case 'X':
570 flags |= LARGE;
571 case 'x':
572 base = 16;
573 break;
574
575 case 'd':
576 case 'i':
577 flags |= SIGN;
578 case 'u':
579 break;
580
581 default:
582 if (str < end)
583 *str = '%';
584 ++str;
585 if (*fmt) {
586 if (str < end)
587 *str = *fmt;
588 ++str;
589 } else {
590 --fmt;
591 }
592 continue;
593 }
594 if (qualifier == 'L')
595 num = va_arg(args, long long);
596 else if (qualifier == 'l') {
597 num = va_arg(args, unsigned long);
598 if (flags & SIGN)
599 num = (signed long) num;
600 } else if (qualifier == 'Z' || qualifier == 'z') {
601 num = va_arg(args, size_t);
602 } else if (qualifier == 'h') {
603 num = (unsigned short) va_arg(args, int);
604 if (flags & SIGN)
605 num = (signed short) num;
606 } else {
607 num = va_arg(args, unsigned int);
608 if (flags & SIGN)
609 num = (signed int) num;
610 }
611
612 str = number(str, end, num, base,
613 field_width, precision, flags);
614 }
615
616 /* don't write out a null byte if the buf size is zero */
617 if (size > 0) {
618 if (str < end)
619 *str = '\0';
620 else
621 end[-1] = '\0';
622 }
623 /* the trailing null byte doesn't count towards the total
624 * ++str;
625 */
626 return str-buf;
627 }
628
629 EXPORT_SYMBOL(vsnprintf);
630
631 /**
632 * vscnprintf - Format a string and place it in a buffer
633 * @buf: The buffer to place the result into
634 * @size: The size of the buffer, including the trailing null space
635 * @fmt: The format string to use
636 * @args: Arguments for the format string
637 *
638 * The return value is the number of characters which have been written into
639 * the @buf not including the trailing '\0'. If @size is <= 0 the function
640 * returns 0.
641 *
642 * Call this function if you are already dealing with a va_list.
643 * You probably want scnprintf instead.
644 */
vscnprintf(char * buf,size_t size,const char * fmt,va_list args)645 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
646 {
647 int i;
648
649 i = vsnprintf(buf,size,fmt,args);
650 if (i >= size)
651 i = size - 1;
652 return (i > 0) ? i : 0;
653 }
654
655 EXPORT_SYMBOL(vscnprintf);
656
657 /**
658 * snprintf - Format a string and place it in a buffer
659 * @buf: The buffer to place the result into
660 * @size: The size of the buffer, including the trailing null space
661 * @fmt: The format string to use
662 * @...: Arguments for the format string
663 *
664 * The return value is the number of characters which would be
665 * generated for the given input, excluding the trailing null,
666 * as per ISO C99. If the return is greater than or equal to
667 * @size, the resulting string is truncated.
668 */
snprintf(char * buf,size_t size,const char * fmt,...)669 int snprintf(char * buf, size_t size, const char *fmt, ...)
670 {
671 va_list args;
672 int i;
673
674 va_start(args, fmt);
675 i=vsnprintf(buf,size,fmt,args);
676 va_end(args);
677 return i;
678 }
679
680 EXPORT_SYMBOL(snprintf);
681
682 /**
683 * scnprintf - Format a string and place it in a buffer
684 * @buf: The buffer to place the result into
685 * @size: The size of the buffer, including the trailing null space
686 * @fmt: The format string to use
687 * @...: Arguments for the format string
688 *
689 * The return value is the number of characters written into @buf not including
690 * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
691 * greater than or equal to @size, the resulting string is truncated.
692 */
693
scnprintf(char * buf,size_t size,const char * fmt,...)694 int scnprintf(char * buf, size_t size, const char *fmt, ...)
695 {
696 va_list args;
697 int i;
698
699 va_start(args, fmt);
700 i = vsnprintf(buf, size, fmt, args);
701 va_end(args);
702 if (i >= size)
703 i = size - 1;
704 return (i > 0) ? i : 0;
705 }
706 EXPORT_SYMBOL(scnprintf);
707
708 /**
709 * vasprintf - Format a string and allocate a buffer to place it in
710 *
711 * @bufp: Pointer to a pointer to receive the allocated buffer
712 * @fmt: The format string to use
713 * @args: Arguments for the format string
714 *
715 * -ENOMEM is returned on failure and @bufp is not touched.
716 * On success, 0 is returned. The buffer passed back is
717 * guaranteed to be null terminated. The memory is allocated
718 * from xenheap, so the buffer should be freed with xfree().
719 */
vasprintf(char ** bufp,const char * fmt,va_list args)720 int vasprintf(char **bufp, const char *fmt, va_list args)
721 {
722 va_list args_copy;
723 size_t size;
724 char *buf;
725
726 va_copy(args_copy, args);
727 size = vsnprintf(NULL, 0, fmt, args_copy);
728 va_end(args_copy);
729
730 buf = xmalloc_array(char, ++size);
731 if ( !buf )
732 return -ENOMEM;
733
734 (void) vsnprintf(buf, size, fmt, args);
735
736 *bufp = buf;
737 return 0;
738 }
739
740 /**
741 * asprintf - Format a string and place it in a buffer
742 * @bufp: Pointer to a pointer to receive the allocated buffer
743 * @fmt: The format string to use
744 * @...: Arguments for the format string
745 *
746 * -ENOMEM is returned on failure and @bufp is not touched.
747 * On success, 0 is returned. The buffer passed back is
748 * guaranteed to be null terminated. The memory is allocated
749 * from xenheap, so the buffer should be freed with xfree().
750 */
asprintf(char ** bufp,const char * fmt,...)751 int asprintf(char **bufp, const char *fmt, ...)
752 {
753 va_list args;
754 int i;
755
756 va_start(args, fmt);
757 i=vasprintf(bufp,fmt,args);
758 va_end(args);
759 return i;
760 }
761
762 /*
763 * Local variables:
764 * mode: C
765 * c-file-style: "BSD"
766 * c-basic-offset: 4
767 * tab-width: 4
768 * indent-tabs-mode: nil
769 * End:
770 */
771