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