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