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,const char * end,unsigned long long num,int base,int size,int precision,int type)146 static char *number(
147     char *buf, const 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,const char * end,const char * s,int field_width,int precision,int flags)241 static char *string(char *str, const 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 
267 /* Print a bitmap as '0-3,6-15' */
print_bitmap_list(char * str,const char * end,const unsigned long * bitmap,unsigned int nr_bits)268 static char *print_bitmap_list(char *str, const char *end,
269                                const unsigned long *bitmap,
270                                unsigned int nr_bits)
271 {
272     /* current bit is 'cur', most recently seen range is [rbot, rtop] */
273     unsigned int cur, rbot, rtop;
274     bool first = true;
275 
276     rbot = cur = find_first_bit(bitmap, nr_bits);
277     while ( cur < nr_bits )
278     {
279         rtop = cur;
280         cur = find_next_bit(bitmap, nr_bits, cur + 1);
281 
282         if ( cur < nr_bits && cur <= rtop + 1 )
283             continue;
284 
285         if ( !first )
286         {
287             if ( str < end )
288                 *str = ',';
289             str++;
290         }
291         first = false;
292 
293         str = number(str, end, rbot, 10, -1, -1, 0);
294         if ( rbot < rtop )
295         {
296             if ( str < end )
297                 *str = '-';
298             str++;
299 
300             str = number(str, end, rtop, 10, -1, -1, 0);
301         }
302 
303         rbot = cur;
304     }
305 
306     return str;
307 }
308 
309 /* Print a bitmap as a comma separated hex string. */
print_bitmap_string(char * str,const char * end,const unsigned long * bitmap,unsigned int nr_bits)310 static char *print_bitmap_string(char *str, const char *end,
311                                  const unsigned long *bitmap,
312                                  unsigned int nr_bits)
313 {
314     const unsigned int CHUNKSZ = 32;
315     unsigned int chunksz;
316     int i;
317     bool first = true;
318 
319     chunksz = nr_bits & (CHUNKSZ - 1);
320     if ( chunksz == 0 )
321         chunksz = CHUNKSZ;
322 
323     /*
324      * First iteration copes with the trailing partial word if nr_bits isn't a
325      * round multiple of CHUNKSZ.  All subsequent iterations work on a
326      * complete CHUNKSZ block.
327      */
328     for ( i = ROUNDUP(nr_bits, CHUNKSZ) - CHUNKSZ; i >= 0; i -= CHUNKSZ )
329     {
330         unsigned int chunkmask = (1ull << chunksz) - 1;
331         unsigned int word      = i / BITS_PER_LONG;
332         unsigned int offset    = i % BITS_PER_LONG;
333         unsigned long val      = (bitmap[word] >> offset) & chunkmask;
334 
335         if ( !first )
336         {
337             if ( str < end )
338                 *str = ',';
339             str++;
340         }
341         first = false;
342 
343         str = number(str, end, val, 16, DIV_ROUND_UP(chunksz, 4), -1, ZEROPAD);
344 
345         chunksz = CHUNKSZ;
346     }
347 
348     return str;
349 }
350 
351 /* Print a domain id, using names for system domains.  (e.g. d0 or d[IDLE]) */
print_domain(char * str,const char * end,const struct domain * d)352 static char *print_domain(char *str, const char *end, const struct domain *d)
353 {
354     const char *name = NULL;
355 
356     /* Some debugging may have an optionally-NULL pointer. */
357     if ( unlikely(!d) )
358         return string(str, end, "NULL", -1, -1, 0);
359 
360     switch ( d->domain_id )
361     {
362     case DOMID_IO:   name = "[IO]";   break;
363     case DOMID_XEN:  name = "[XEN]";  break;
364     case DOMID_COW:  name = "[COW]";  break;
365     case DOMID_IDLE: name = "[IDLE]"; break;
366         /*
367          * In principle, we could ASSERT_UNREACHABLE() in the default case.
368          * However, this path is used to print out crash information, which
369          * risks recursing infinitely and not printing any useful information.
370          */
371     }
372 
373     if ( str < end )
374         *str = 'd';
375 
376     if ( name )
377         return string(str + 1, end, name, -1, -1, 0);
378     else
379         return number(str + 1, end, d->domain_id, 10, -1, -1, 0);
380 }
381 
382 /* Print a vcpu id.  (e.g. d0v1 or d[IDLE]v0) */
print_vcpu(char * str,const char * end,const struct vcpu * v)383 static char *print_vcpu(char *str, const char *end, const struct vcpu *v)
384 {
385     /* Some debugging may have an optionally-NULL pointer. */
386     if ( unlikely(!v) )
387         return string(str, end, "NULL", -1, -1, 0);
388 
389     str = print_domain(str, end, v->domain);
390 
391     if ( str < end )
392         *str = 'v';
393 
394     return number(str + 1, end, v->vcpu_id, 10, -1, -1, 0);
395 }
396 
pointer(char * str,const char * end,const char ** fmt_ptr,const void * arg,int field_width,int precision,int flags)397 static char *pointer(char *str, const char *end, const char **fmt_ptr,
398                      const void *arg, int field_width, int precision,
399                      int flags)
400 {
401     const char *fmt = *fmt_ptr, *s;
402 
403     /* Custom %p suffixes. See XEN_ROOT/docs/misc/printk-formats.txt */
404     switch ( fmt[1] )
405     {
406     case 'b': /* Bitmap as hex, or list */
407         ++*fmt_ptr;
408 
409         if ( field_width < 0 )
410             return str;
411 
412         if ( fmt[2] == 'l' )
413         {
414             ++*fmt_ptr;
415 
416             return print_bitmap_list(str, end, arg, field_width);
417         }
418 
419         return print_bitmap_string(str, end, arg, field_width);
420 
421     case 'd': /* Domain ID from a struct domain *. */
422         ++*fmt_ptr;
423         return print_domain(str, end, arg);
424 
425     case 'h': /* Raw buffer as hex string. */
426     {
427         const uint8_t *hex_buffer = arg;
428         char sep = ' '; /* Separator character. */
429         unsigned int i;
430 
431         /* Consumed 'h' from the format string. */
432         ++*fmt_ptr;
433 
434         /* Bound user count from %* to between 0 and 64 bytes. */
435         if ( field_width <= 0 )
436             return str;
437         if ( field_width > 64 )
438             field_width = 64;
439 
440         /*
441          * Peek ahead in the format string to see if a recognised separator
442          * modifier is present.
443          */
444         switch ( fmt[2] )
445         {
446         case 'C': /* Colons. */
447             ++*fmt_ptr;
448             sep = ':';
449             break;
450 
451         case 'D': /* Dashes. */
452             ++*fmt_ptr;
453             sep = '-';
454             break;
455 
456         case 'N': /* No separator. */
457             ++*fmt_ptr;
458             sep = 0;
459             break;
460         }
461 
462         for ( i = 0; ; )
463         {
464             /* Each byte: 2 chars, 0-padded, base 16, no hex prefix. */
465             str = number(str, end, hex_buffer[i], 16, 2, -1, ZEROPAD);
466 
467             if ( ++i == field_width )
468                 return str;
469 
470             if ( sep )
471             {
472                 if ( str < end )
473                     *str = sep;
474                 ++str;
475             }
476         }
477     }
478 
479     case 's': /* Symbol name with offset and size (iff offset != 0) */
480     case 'S': /* Symbol name unconditionally with offset and size */
481     {
482         unsigned long sym_size, sym_offset;
483         char namebuf[KSYM_NAME_LEN+1];
484 
485         /* Advance parents fmt string, as we have consumed 's' or 'S' */
486         ++*fmt_ptr;
487 
488         s = symbols_lookup((unsigned long)arg, &sym_size, &sym_offset, namebuf);
489 
490         /* If the symbol is not found, fall back to printing the address */
491         if ( !s )
492             break;
493 
494         /* Print symbol name */
495         str = string(str, end, s, -1, -1, 0);
496 
497         if ( fmt[1] == 'S' || sym_offset != 0 )
498         {
499             /* Print '+<offset>/<len>' */
500             str = number(str, end, sym_offset, 16, -1, -1, SPECIAL|SIGN|PLUS);
501             if ( str < end )
502                 *str = '/';
503             ++str;
504             str = number(str, end, sym_size, 16, -1, -1, SPECIAL);
505         }
506 
507         /*
508          * namebuf contents and s for core hypervisor are same but for Live Patch
509          * payloads they differ (namebuf contains the name of the payload).
510          */
511         if ( namebuf != s )
512         {
513             str = string(str, end, " [", -1, -1, 0);
514             str = string(str, end, namebuf, -1, -1, 0);
515             str = string(str, end, "]", -1, -1, 0);
516         }
517 
518         return str;
519     }
520 
521     case 'v': /* d<domain-id>v<vcpu-id> from a struct vcpu */
522         ++*fmt_ptr;
523         return print_vcpu(str, end, arg);
524     }
525 
526     if ( field_width == -1 )
527     {
528         field_width = 2 * sizeof(void *);
529         flags |= ZEROPAD;
530     }
531 
532     return number(str, end, (unsigned long)arg,
533                   16, field_width, precision, flags);
534 }
535 
536 /**
537  * vsnprintf - Format a string and place it in a buffer
538  * @buf: The buffer to place the result into
539  * @size: The size of the buffer, including the trailing null space
540  * @fmt: The format string to use
541  * @args: Arguments for the format string
542  *
543  * The return value is the number of characters which would
544  * be generated for the given input, excluding the trailing
545  * '\0', as per ISO C99. If you want to have the exact
546  * number of characters written into @buf as return value
547  * (not including the trailing '\0'), use vscnprintf. If the
548  * return is greater than or equal to @size, the resulting
549  * string is truncated.
550  *
551  * Call this function if you are already dealing with a va_list.
552  * You probably want snprintf instead.
553  */
vsnprintf(char * buf,size_t size,const char * fmt,va_list args)554 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
555 {
556     unsigned long long num;
557     int base;
558     char *str, *end, c;
559     const char *s;
560 
561     int flags;          /* flags to number() */
562 
563     int field_width;    /* width of output field */
564     int precision;              /* min. # of digits for integers; max
565                                    number of chars for from string */
566     int qualifier;              /* 'h', 'l', or 'L' for integer fields */
567                                 /* 'z' support added 23/7/1999 S.H.    */
568                                 /* 'z' changed to 'Z' --davidm 1/25/99 */
569 
570     /* Reject out-of-range values early */
571     BUG_ON(((int)size < 0) || ((unsigned int)size != size));
572 
573     str = buf;
574     end = buf + size;
575 
576     if (end < buf) {
577         end = ((void *) -1);
578         size = end - buf;
579     }
580 
581     for (; *fmt ; ++fmt) {
582         if (*fmt != '%') {
583             if (str < end)
584                 *str = *fmt;
585             ++str;
586             continue;
587         }
588 
589         /* process flags */
590         flags = 0;
591     repeat:
592         ++fmt;          /* this also skips first '%' */
593         switch (*fmt) {
594         case '-': flags |= LEFT; goto repeat;
595         case '+': flags |= PLUS; goto repeat;
596         case ' ': flags |= SPACE; goto repeat;
597         case '#': flags |= SPECIAL; goto repeat;
598         case '0': flags |= ZEROPAD; goto repeat;
599         }
600 
601         /* get field width */
602         field_width = -1;
603         if (isdigit(*fmt))
604             field_width = skip_atoi(&fmt);
605         else if (*fmt == '*') {
606             ++fmt;
607             /* it's the next argument */
608             field_width = va_arg(args, int);
609             if (field_width < 0) {
610                 field_width = -field_width;
611                 flags |= LEFT;
612             }
613         }
614 
615         /* get the precision */
616         precision = -1;
617         if (*fmt == '.') {
618             ++fmt;
619             if (isdigit(*fmt))
620                 precision = skip_atoi(&fmt);
621             else if (*fmt == '*') {
622                 ++fmt;
623                           /* it's the next argument */
624                 precision = va_arg(args, int);
625             }
626             if (precision < 0)
627                 precision = 0;
628         }
629 
630         /* get the conversion qualifier */
631         qualifier = -1;
632         if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
633             *fmt =='Z' || *fmt == 'z') {
634             qualifier = *fmt;
635             ++fmt;
636             if (qualifier == 'l' && *fmt == 'l') {
637                 qualifier = 'L';
638                 ++fmt;
639             }
640         }
641 
642         /* default base */
643         base = 10;
644 
645         switch (*fmt) {
646         case 'c':
647             if (!(flags & LEFT)) {
648                 while (--field_width > 0) {
649                     if (str < end)
650                         *str = ' ';
651                     ++str;
652                 }
653             }
654             c = (unsigned char) va_arg(args, int);
655             if (str < end)
656                 *str = c;
657             ++str;
658             while (--field_width > 0) {
659                 if (str < end)
660                     *str = ' ';
661                 ++str;
662             }
663             continue;
664 
665         case 's':
666             s = va_arg(args, char *);
667             if ((unsigned long)s < PAGE_SIZE)
668                 s = "<NULL>";
669 
670             str = string(str, end, s, field_width, precision, flags);
671             continue;
672 
673         case 'p':
674             /* pointer() might advance fmt (%pS for example) */
675             str = pointer(str, end, &fmt, va_arg(args, const void *),
676                           field_width, precision, flags);
677             continue;
678 
679 
680         case 'n':
681             if (qualifier == 'l') {
682                 long * ip = va_arg(args, long *);
683                 *ip = (str - buf);
684             } else if (qualifier == 'Z' || qualifier == 'z') {
685                 size_t * ip = va_arg(args, size_t *);
686                 *ip = (str - buf);
687             } else {
688                 int * ip = va_arg(args, int *);
689                 *ip = (str - buf);
690             }
691             continue;
692 
693         case '%':
694             if (str < end)
695                 *str = '%';
696             ++str;
697             continue;
698 
699             /* integer number formats - set up the flags and "break" */
700         case 'o':
701             base = 8;
702             break;
703 
704         case 'X':
705             flags |= LARGE;
706         case 'x':
707             base = 16;
708             break;
709 
710         case 'd':
711         case 'i':
712             flags |= SIGN;
713         case 'u':
714             break;
715 
716         default:
717             if (str < end)
718                 *str = '%';
719             ++str;
720             if (*fmt) {
721                 if (str < end)
722                     *str = *fmt;
723                 ++str;
724             } else {
725                 --fmt;
726             }
727             continue;
728         }
729         if (qualifier == 'L')
730             num = va_arg(args, long long);
731         else if (qualifier == 'l') {
732             num = va_arg(args, unsigned long);
733             if (flags & SIGN)
734                 num = (signed long) num;
735         } else if (qualifier == 'Z' || qualifier == 'z') {
736             num = va_arg(args, size_t);
737         } else if (qualifier == 'h') {
738             num = (unsigned short) va_arg(args, int);
739             if (flags & SIGN)
740                 num = (signed short) num;
741         } else {
742             num = va_arg(args, unsigned int);
743             if (flags & SIGN)
744                 num = (signed int) num;
745         }
746 
747         str = number(str, end, num, base,
748                      field_width, precision, flags);
749     }
750 
751     /* don't write out a null byte if the buf size is zero */
752     if (size > 0) {
753         if (str < end)
754             *str = '\0';
755         else
756             end[-1] = '\0';
757     }
758     /* the trailing null byte doesn't count towards the total
759      * ++str;
760      */
761     return str-buf;
762 }
763 
764 EXPORT_SYMBOL(vsnprintf);
765 
766 /**
767  * vscnprintf - Format a string and place it in a buffer
768  * @buf: The buffer to place the result into
769  * @size: The size of the buffer, including the trailing null space
770  * @fmt: The format string to use
771  * @args: Arguments for the format string
772  *
773  * The return value is the number of characters which have been written into
774  * the @buf not including the trailing '\0'. If @size is <= 0 the function
775  * returns 0.
776  *
777  * Call this function if you are already dealing with a va_list.
778  * You probably want scnprintf instead.
779  */
vscnprintf(char * buf,size_t size,const char * fmt,va_list args)780 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
781 {
782     int i;
783 
784     i = vsnprintf(buf,size,fmt,args);
785     if (i >= size)
786         i = size - 1;
787     return (i > 0) ? i : 0;
788 }
789 
790 EXPORT_SYMBOL(vscnprintf);
791 
792 /**
793  * snprintf - Format a string and place it in a buffer
794  * @buf: The buffer to place the result into
795  * @size: The size of the buffer, including the trailing null space
796  * @fmt: The format string to use
797  * @...: Arguments for the format string
798  *
799  * The return value is the number of characters which would be
800  * generated for the given input, excluding the trailing null,
801  * as per ISO C99.  If the return is greater than or equal to
802  * @size, the resulting string is truncated.
803  */
snprintf(char * buf,size_t size,const char * fmt,...)804 int snprintf(char * buf, size_t size, const char *fmt, ...)
805 {
806     va_list args;
807     int i;
808 
809     va_start(args, fmt);
810     i=vsnprintf(buf,size,fmt,args);
811     va_end(args);
812     return i;
813 }
814 
815 EXPORT_SYMBOL(snprintf);
816 
817 /**
818  * scnprintf - Format a string and place it in a buffer
819  * @buf: The buffer to place the result into
820  * @size: The size of the buffer, including the trailing null space
821  * @fmt: The format string to use
822  * @...: Arguments for the format string
823  *
824  * The return value is the number of characters written into @buf not including
825  * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
826  * greater than or equal to @size, the resulting string is truncated.
827  */
828 
scnprintf(char * buf,size_t size,const char * fmt,...)829 int scnprintf(char * buf, size_t size, const char *fmt, ...)
830 {
831     va_list args;
832     int i;
833 
834     va_start(args, fmt);
835     i = vsnprintf(buf, size, fmt, args);
836     va_end(args);
837     if (i >= size)
838         i = size - 1;
839     return (i > 0) ? i : 0;
840 }
841 EXPORT_SYMBOL(scnprintf);
842 
843 /**
844  * vasprintf - Format a string and allocate a buffer to place it in
845  *
846  * @bufp: Pointer to a pointer to receive the allocated buffer
847  * @fmt: The format string to use
848  * @args: Arguments for the format string
849  *
850  * -ENOMEM is returned on failure and @bufp is not touched.
851  * On success, 0 is returned. The buffer passed back is
852  * guaranteed to be null terminated. The memory is allocated
853  * from xenheap, so the buffer should be freed with xfree().
854  */
vasprintf(char ** bufp,const char * fmt,va_list args)855 int vasprintf(char **bufp, const char *fmt, va_list args)
856 {
857     va_list args_copy;
858     size_t size;
859     char *buf;
860 
861     va_copy(args_copy, args);
862     size = vsnprintf(NULL, 0, fmt, args_copy);
863     va_end(args_copy);
864 
865     buf = xmalloc_array(char, ++size);
866     if ( !buf )
867         return -ENOMEM;
868 
869     (void) vsnprintf(buf, size, fmt, args);
870 
871     *bufp = buf;
872     return 0;
873 }
874 
875 /**
876  * asprintf - Format a string and place it in a buffer
877  * @bufp: Pointer to a pointer to receive the allocated buffer
878  * @fmt: The format string to use
879  * @...: Arguments for the format string
880  *
881  * -ENOMEM is returned on failure and @bufp is not touched.
882  * On success, 0 is returned. The buffer passed back is
883  * guaranteed to be null terminated. The memory is allocated
884  * from xenheap, so the buffer should be freed with xfree().
885  */
asprintf(char ** bufp,const char * fmt,...)886 int asprintf(char **bufp, const char *fmt, ...)
887 {
888     va_list args;
889     int i;
890 
891     va_start(args, fmt);
892     i=vasprintf(bufp,fmt,args);
893     va_end(args);
894     return i;
895 }
896 
897 /*
898  * Local variables:
899  * mode: C
900  * c-file-style: "BSD"
901  * c-basic-offset: 4
902  * tab-width: 4
903  * indent-tabs-mode: nil
904  * End:
905  */
906