/root/src/xen/xen/common/vsprintf.c
Line | Count | Source (jump to first uncovered line) |
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 | | */ |
33 | | unsigned long simple_strtoul( |
34 | | const char *cp, const char **endp, unsigned int base) |
35 | 3 | { |
36 | 3 | unsigned long result = 0,value; |
37 | 3 | |
38 | 3 | if (!base) { |
39 | 0 | base = 10; |
40 | 0 | if (*cp == '0') { |
41 | 0 | base = 8; |
42 | 0 | cp++; |
43 | 0 | if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { |
44 | 0 | cp++; |
45 | 0 | base = 16; |
46 | 0 | } |
47 | 0 | } |
48 | 3 | } else if (base == 16) { |
49 | 0 | if (cp[0] == '0' && toupper(cp[1]) == 'X') |
50 | 0 | cp += 2; |
51 | 0 | } |
52 | 11 | while (isxdigit(*cp) && |
53 | 8 | (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { |
54 | 8 | result = result*base + value; |
55 | 8 | cp++; |
56 | 8 | } |
57 | 3 | if (endp) |
58 | 3 | *endp = cp; |
59 | 3 | return result; |
60 | 3 | } |
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 | | */ |
70 | | long simple_strtol(const char *cp, const char **endp, unsigned int base) |
71 | 0 | { |
72 | 0 | if(*cp=='-') |
73 | 0 | return -simple_strtoul(cp+1,endp,base); |
74 | 0 | return simple_strtoul(cp,endp,base); |
75 | 0 | } |
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 | | */ |
85 | | unsigned long long simple_strtoull( |
86 | | const char *cp, const char **endp, unsigned int base) |
87 | 0 | { |
88 | 0 | unsigned long long result = 0,value; |
89 | 0 |
|
90 | 0 | if (!base) { |
91 | 0 | base = 10; |
92 | 0 | if (*cp == '0') { |
93 | 0 | base = 8; |
94 | 0 | cp++; |
95 | 0 | if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { |
96 | 0 | cp++; |
97 | 0 | base = 16; |
98 | 0 | } |
99 | 0 | } |
100 | 0 | } else if (base == 16) { |
101 | 0 | if (cp[0] == '0' && toupper(cp[1]) == 'X') |
102 | 0 | cp += 2; |
103 | 0 | } |
104 | 0 | while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) |
105 | 0 | ? toupper(*cp) : *cp)-'A'+10) < base) { |
106 | 0 | result = result*base + value; |
107 | 0 | cp++; |
108 | 0 | } |
109 | 0 | if (endp) |
110 | 0 | *endp = cp; |
111 | 0 | return result; |
112 | 0 | } |
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 | | */ |
122 | | long long simple_strtoll(const char *cp,const char **endp,unsigned int base) |
123 | 0 | { |
124 | 0 | if(*cp=='-') |
125 | 0 | return -simple_strtoull(cp+1,endp,base); |
126 | 0 | return simple_strtoull(cp,endp,base); |
127 | 0 | } |
128 | | |
129 | | static int skip_atoi(const char **s) |
130 | 593 | { |
131 | 593 | int i=0; |
132 | 593 | |
133 | 1.22k | while (isdigit(**s)) |
134 | 634 | i = i*10 + *((*s)++) - '0'; |
135 | 593 | return i; |
136 | 593 | } |
137 | | |
138 | 2.26k | #define ZEROPAD 1 /* pad with zero */ |
139 | 1.84k | #define SIGN 2 /* unsigned/signed long */ |
140 | 138 | #define PLUS 4 /* show plus */ |
141 | 138 | #define SPACE 8 /* space if plus */ |
142 | 2.97k | #define LEFT 16 /* left justified */ |
143 | 1.84k | #define SPECIAL 32 /* 0x */ |
144 | 978 | #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ |
145 | | |
146 | | static char *number( |
147 | | char *buf, char *end, unsigned long long num, |
148 | | int base, int size, int precision, int type) |
149 | 909 | { |
150 | 909 | char c,sign,tmp[66]; |
151 | 909 | const char *digits; |
152 | 909 | static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; |
153 | 909 | static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
154 | 909 | int i; |
155 | 909 | |
156 | 909 | ASSERT(base >= 2 && base <= 36); |
157 | 909 | |
158 | 909 | digits = (type & LARGE) ? large_digits : small_digits; |
159 | 909 | if (type & LEFT) |
160 | 0 | type &= ~ZEROPAD; |
161 | 909 | c = (type & ZEROPAD) ? '0' : ' '; |
162 | 909 | sign = 0; |
163 | 909 | if (type & SIGN) { |
164 | 140 | if ((signed long long) num < 0) { |
165 | 2 | sign = '-'; |
166 | 2 | num = - (signed long long) num; |
167 | 2 | size--; |
168 | 138 | } else if (type & PLUS) { |
169 | 0 | sign = '+'; |
170 | 0 | size--; |
171 | 138 | } else if (type & SPACE) { |
172 | 0 | sign = ' '; |
173 | 0 | size--; |
174 | 0 | } |
175 | 140 | } |
176 | 909 | if (type & SPECIAL) { |
177 | 27 | if (num == 0) |
178 | 1 | type &= ~SPECIAL; |
179 | 26 | else if (base == 16) |
180 | 26 | size -= 2; |
181 | 0 | else if (base == 8) |
182 | 0 | size--; |
183 | 0 | else |
184 | 0 | type &= ~SPECIAL; |
185 | 27 | } |
186 | 909 | i = 0; |
187 | 909 | if (num == 0) |
188 | 391 | tmp[i++]='0'; |
189 | 2.08k | else while (num != 0) |
190 | 1.56k | tmp[i++] = digits[do_div(num,base)]; |
191 | 909 | if (i > precision) |
192 | 909 | precision = i; |
193 | 909 | size -= precision; |
194 | 909 | if (!(type&(ZEROPAD+LEFT))) { |
195 | 596 | while(size-->0) { |
196 | 129 | if (buf < end) |
197 | 129 | *buf = ' '; |
198 | 129 | ++buf; |
199 | 129 | } |
200 | 467 | } |
201 | 909 | if (sign) { |
202 | 2 | if (buf < end) |
203 | 2 | *buf = sign; |
204 | 2 | ++buf; |
205 | 2 | } |
206 | 909 | if (type & SPECIAL) { |
207 | 26 | if (buf < end) |
208 | 26 | *buf = '0'; |
209 | 26 | ++buf; |
210 | 26 | if (base == 16) { |
211 | 26 | if (buf < end) |
212 | 26 | *buf = digits[33]; |
213 | 26 | ++buf; |
214 | 26 | } |
215 | 26 | } |
216 | 909 | if (!(type & LEFT)) { |
217 | 1.77k | while (size-- > 0) { |
218 | 863 | if (buf < end) |
219 | 863 | *buf = c; |
220 | 863 | ++buf; |
221 | 863 | } |
222 | 909 | } |
223 | 909 | while (i < precision--) { |
224 | 0 | if (buf < end) |
225 | 0 | *buf = '0'; |
226 | 0 | ++buf; |
227 | 0 | } |
228 | 2.86k | while (i-- > 0) { |
229 | 1.95k | if (buf < end) |
230 | 1.95k | *buf = tmp[i]; |
231 | 1.95k | ++buf; |
232 | 1.95k | } |
233 | 909 | while (size-- > 0) { |
234 | 0 | if (buf < end) |
235 | 0 | *buf = ' '; |
236 | 0 | ++buf; |
237 | 0 | } |
238 | 909 | return buf; |
239 | 909 | } |
240 | | |
241 | | static char *string(char *str, char *end, const char *s, |
242 | | int field_width, int precision, int flags) |
243 | 243 | { |
244 | 177 | int i, len = (precision < 0) ? strlen(s) : strnlen(s, precision); |
245 | 243 | |
246 | 243 | if (!(flags & LEFT)) { |
247 | 286 | while (len < field_width--) { |
248 | 43 | if (str < end) |
249 | 43 | *str = ' '; |
250 | 43 | ++str; |
251 | 43 | } |
252 | 243 | } |
253 | 3.09k | for (i = 0; i < len; ++i) { |
254 | 2.85k | if (str < end) |
255 | 2.85k | *str = *s; |
256 | 2.85k | ++str; ++s; |
257 | 2.85k | } |
258 | 243 | while (len < field_width--) { |
259 | 0 | if (str < end) |
260 | 0 | *str = ' '; |
261 | 0 | ++str; |
262 | 0 | } |
263 | 243 | |
264 | 243 | return str; |
265 | 243 | } |
266 | | |
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 | 47 | { |
271 | 47 | const char *fmt = *fmt_ptr, *s; |
272 | 47 | |
273 | 47 | /* Custom %p suffixes. See XEN_ROOT/docs/misc/printk-formats.txt */ |
274 | 47 | switch ( fmt[1] ) |
275 | 47 | { |
276 | 0 | case 'h': /* Raw buffer as hex string. */ |
277 | 0 | { |
278 | 0 | const uint8_t *hex_buffer = arg; |
279 | 0 | char sep = ' '; /* Separator character. */ |
280 | 0 | unsigned int i; |
281 | 0 |
|
282 | 0 | /* Consumed 'h' from the format string. */ |
283 | 0 | ++*fmt_ptr; |
284 | 0 |
|
285 | 0 | /* Bound user count from %* to between 0 and 64 bytes. */ |
286 | 0 | if ( field_width <= 0 ) |
287 | 0 | return str; |
288 | 0 | if ( field_width > 64 ) |
289 | 0 | field_width = 64; |
290 | 0 |
|
291 | 0 | /* |
292 | 0 | * Peek ahead in the format string to see if a recognised separator |
293 | 0 | * modifier is present. |
294 | 0 | */ |
295 | 0 | switch ( fmt[2] ) |
296 | 0 | { |
297 | 0 | case 'C': /* Colons. */ |
298 | 0 | ++*fmt_ptr; |
299 | 0 | sep = ':'; |
300 | 0 | break; |
301 | 0 |
|
302 | 0 | case 'D': /* Dashes. */ |
303 | 0 | ++*fmt_ptr; |
304 | 0 | sep = '-'; |
305 | 0 | break; |
306 | 0 |
|
307 | 0 | case 'N': /* No separator. */ |
308 | 0 | ++*fmt_ptr; |
309 | 0 | sep = 0; |
310 | 0 | break; |
311 | 0 | } |
312 | 0 |
|
313 | 0 | for ( i = 0; ; ) |
314 | 0 | { |
315 | 0 | /* Each byte: 2 chars, 0-padded, base 16, no hex prefix. */ |
316 | 0 | str = number(str, end, hex_buffer[i], 16, 2, -1, ZEROPAD); |
317 | 0 |
|
318 | 0 | if ( ++i == field_width ) |
319 | 0 | return str; |
320 | 0 |
|
321 | 0 | if ( sep ) |
322 | 0 | { |
323 | 0 | if ( str < end ) |
324 | 0 | *str = sep; |
325 | 0 | ++str; |
326 | 0 | } |
327 | 0 | } |
328 | 0 | } |
329 | 0 |
|
330 | 3 | case 's': /* Symbol name with offset and size (iff offset != 0) */ |
331 | 3 | case 'S': /* Symbol name unconditionally with offset and size */ |
332 | 3 | { |
333 | 3 | unsigned long sym_size, sym_offset; |
334 | 3 | char namebuf[KSYM_NAME_LEN+1]; |
335 | 3 | |
336 | 3 | /* Advance parents fmt string, as we have consumed 's' or 'S' */ |
337 | 3 | ++*fmt_ptr; |
338 | 3 | |
339 | 3 | s = symbols_lookup((unsigned long)arg, &sym_size, &sym_offset, namebuf); |
340 | 3 | |
341 | 3 | /* If the symbol is not found, fall back to printing the address */ |
342 | 3 | if ( !s ) |
343 | 3 | break; |
344 | 3 | |
345 | 3 | /* Print symbol name */ |
346 | 0 | str = string(str, end, s, -1, -1, 0); |
347 | 0 |
|
348 | 0 | if ( fmt[1] == 'S' || sym_offset != 0 ) |
349 | 0 | { |
350 | 0 | /* Print '+<offset>/<len>' */ |
351 | 0 | str = number(str, end, sym_offset, 16, -1, -1, SPECIAL|SIGN|PLUS); |
352 | 0 | if ( str < end ) |
353 | 0 | *str = '/'; |
354 | 0 | ++str; |
355 | 0 | str = number(str, end, sym_size, 16, -1, -1, SPECIAL); |
356 | 0 | } |
357 | 0 |
|
358 | 0 | /* |
359 | 0 | * namebuf contents and s for core hypervisor are same but for Live Patch |
360 | 0 | * payloads they differ (namebuf contains the name of the payload). |
361 | 0 | */ |
362 | 0 | if ( namebuf != s ) |
363 | 0 | { |
364 | 0 | str = string(str, end, " [", -1, -1, 0); |
365 | 0 | str = string(str, end, namebuf, -1, -1, 0); |
366 | 0 | str = string(str, end, "]", -1, -1, 0); |
367 | 0 | } |
368 | 0 |
|
369 | 0 | return str; |
370 | 3 | } |
371 | 3 | |
372 | 34 | case 'v': /* d<domain-id>v<vcpu-id> from a struct vcpu */ |
373 | 34 | { |
374 | 34 | const struct vcpu *v = arg; |
375 | 34 | |
376 | 34 | ++*fmt_ptr; |
377 | 34 | if ( unlikely(v->domain->domain_id == DOMID_IDLE) ) |
378 | 1 | str = string(str, end, "IDLE", -1, -1, 0); |
379 | 34 | else |
380 | 33 | { |
381 | 33 | if ( str < end ) |
382 | 33 | *str = 'd'; |
383 | 33 | str = number(str + 1, end, v->domain->domain_id, 10, -1, -1, 0); |
384 | 33 | } |
385 | 34 | if ( str < end ) |
386 | 34 | *str = 'v'; |
387 | 34 | return number(str + 1, end, v->vcpu_id, 10, -1, -1, 0); |
388 | 3 | } |
389 | 47 | } |
390 | 47 | |
391 | 13 | if ( field_width == -1 ) |
392 | 13 | { |
393 | 13 | field_width = 2 * sizeof(void *); |
394 | 13 | flags |= ZEROPAD; |
395 | 13 | } |
396 | 13 | |
397 | 13 | return number(str, end, (unsigned long)arg, |
398 | 13 | 16, field_width, precision, flags); |
399 | 47 | } |
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 | | */ |
419 | | int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) |
420 | 682 | { |
421 | 682 | unsigned long long num; |
422 | 682 | int base; |
423 | 682 | char *str, *end, c; |
424 | 682 | const char *s; |
425 | 682 | |
426 | 682 | int flags; /* flags to number() */ |
427 | 682 | |
428 | 682 | int field_width; /* width of output field */ |
429 | 682 | int precision; /* min. # of digits for integers; max |
430 | 682 | number of chars for from string */ |
431 | 682 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ |
432 | 682 | /* 'z' support added 23/7/1999 S.H. */ |
433 | 682 | /* 'z' changed to 'Z' --davidm 1/25/99 */ |
434 | 682 | |
435 | 682 | /* Reject out-of-range values early */ |
436 | 682 | BUG_ON(((int)size < 0) || ((unsigned int)size != size)); |
437 | 682 | |
438 | 682 | str = buf; |
439 | 682 | end = buf + size; |
440 | 682 | |
441 | 682 | if (end < buf) { |
442 | 0 | end = ((void *) -1); |
443 | 0 | size = end - buf; |
444 | 0 | } |
445 | 682 | |
446 | 13.1k | for (; *fmt ; ++fmt) { |
447 | 12.5k | if (*fmt != '%') { |
448 | 11.3k | if (str < end) |
449 | 11.3k | *str = *fmt; |
450 | 11.3k | ++str; |
451 | 11.3k | continue; |
452 | 11.3k | } |
453 | 12.5k | |
454 | 12.5k | /* process flags */ |
455 | 1.12k | flags = 0; |
456 | 1.57k | repeat: |
457 | 1.57k | ++fmt; /* this also skips first '%' */ |
458 | 1.57k | switch (*fmt) { |
459 | 0 | case '-': flags |= LEFT; goto repeat; |
460 | 0 | case '+': flags |= PLUS; goto repeat; |
461 | 0 | case ' ': flags |= SPACE; goto repeat; |
462 | 27 | case '#': flags |= SPECIAL; goto repeat; |
463 | 429 | case '0': flags |= ZEROPAD; goto repeat; |
464 | 1.57k | } |
465 | 1.57k | |
466 | 1.57k | /* get field width */ |
467 | 1.12k | field_width = -1; |
468 | 1.12k | if (isdigit(*fmt)) |
469 | 527 | field_width = skip_atoi(&fmt); |
470 | 593 | else if (*fmt == '*') { |
471 | 0 | ++fmt; |
472 | 0 | /* it's the next argument */ |
473 | 0 | field_width = va_arg(args, int); |
474 | 0 | if (field_width < 0) { |
475 | 0 | field_width = -field_width; |
476 | 0 | flags |= LEFT; |
477 | 0 | } |
478 | 0 | } |
479 | 1.12k | |
480 | 1.12k | /* get the precision */ |
481 | 1.12k | precision = -1; |
482 | 1.12k | if (*fmt == '.') { |
483 | 66 | ++fmt; |
484 | 66 | if (isdigit(*fmt)) |
485 | 66 | precision = skip_atoi(&fmt); |
486 | 0 | else if (*fmt == '*') { |
487 | 0 | ++fmt; |
488 | 0 | /* it's the next argument */ |
489 | 0 | precision = va_arg(args, int); |
490 | 0 | } |
491 | 66 | if (precision < 0) |
492 | 0 | precision = 0; |
493 | 66 | } |
494 | 1.12k | |
495 | 1.12k | /* get the conversion qualifier */ |
496 | 1.12k | qualifier = -1; |
497 | 1.12k | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || |
498 | 997 | *fmt =='Z' || *fmt == 'z') { |
499 | 123 | qualifier = *fmt; |
500 | 123 | ++fmt; |
501 | 123 | if (qualifier == 'l' && *fmt == 'l') { |
502 | 0 | qualifier = 'L'; |
503 | 0 | ++fmt; |
504 | 0 | } |
505 | 123 | } |
506 | 1.12k | |
507 | 1.12k | /* default base */ |
508 | 1.12k | base = 10; |
509 | 1.12k | |
510 | 1.12k | switch (*fmt) { |
511 | 2 | case 'c': |
512 | 2 | if (!(flags & LEFT)) { |
513 | 2 | while (--field_width > 0) { |
514 | 0 | if (str < end) |
515 | 0 | *str = ' '; |
516 | 0 | ++str; |
517 | 0 | } |
518 | 2 | } |
519 | 2 | c = (unsigned char) va_arg(args, int); |
520 | 2 | if (str < end) |
521 | 2 | *str = c; |
522 | 2 | ++str; |
523 | 2 | while (--field_width > 0) { |
524 | 0 | if (str < end) |
525 | 0 | *str = ' '; |
526 | 0 | ++str; |
527 | 0 | } |
528 | 2 | continue; |
529 | 2 | |
530 | 242 | case 's': |
531 | 242 | s = va_arg(args, char *); |
532 | 242 | if ((unsigned long)s < PAGE_SIZE) |
533 | 0 | s = "<NULL>"; |
534 | 242 | |
535 | 242 | str = string(str, end, s, field_width, precision, flags); |
536 | 242 | continue; |
537 | 2 | |
538 | 47 | case 'p': |
539 | 47 | /* pointer() might advance fmt (%pS for example) */ |
540 | 47 | str = pointer(str, end, &fmt, va_arg(args, const void *), |
541 | 47 | field_width, precision, flags); |
542 | 47 | continue; |
543 | 2 | |
544 | 2 | |
545 | 0 | case 'n': |
546 | 0 | if (qualifier == 'l') { |
547 | 0 | long * ip = va_arg(args, long *); |
548 | 0 | *ip = (str - buf); |
549 | 0 | } else if (qualifier == 'Z' || qualifier == 'z') { |
550 | 0 | size_t * ip = va_arg(args, size_t *); |
551 | 0 | *ip = (str - buf); |
552 | 0 | } else { |
553 | 0 | int * ip = va_arg(args, int *); |
554 | 0 | *ip = (str - buf); |
555 | 0 | } |
556 | 0 | continue; |
557 | 2 | |
558 | 0 | case '%': |
559 | 0 | if (str < end) |
560 | 0 | *str = '%'; |
561 | 0 | ++str; |
562 | 0 | continue; |
563 | 2 | |
564 | 2 | /* integer number formats - set up the flags and "break" */ |
565 | 0 | case 'o': |
566 | 0 | base = 8; |
567 | 0 | break; |
568 | 2 | |
569 | 69 | case 'X': |
570 | 69 | flags |= LARGE; |
571 | 514 | case 'x': |
572 | 514 | base = 16; |
573 | 514 | break; |
574 | 69 | |
575 | 140 | case 'd': |
576 | 140 | case 'i': |
577 | 140 | flags |= SIGN; |
578 | 315 | case 'u': |
579 | 315 | break; |
580 | 140 | |
581 | 0 | default: |
582 | 0 | if (str < end) |
583 | 0 | *str = '%'; |
584 | 0 | ++str; |
585 | 0 | if (*fmt) { |
586 | 0 | if (str < end) |
587 | 0 | *str = *fmt; |
588 | 0 | ++str; |
589 | 0 | } else { |
590 | 0 | --fmt; |
591 | 0 | } |
592 | 0 | continue; |
593 | 1.12k | } |
594 | 829 | if (qualifier == 'L') |
595 | 38 | num = va_arg(args, long long); |
596 | 791 | else if (qualifier == 'l') { |
597 | 85 | num = va_arg(args, unsigned long); |
598 | 85 | if (flags & SIGN) |
599 | 1 | num = (signed long) num; |
600 | 706 | } else if (qualifier == 'Z' || qualifier == 'z') { |
601 | 0 | num = va_arg(args, size_t); |
602 | 706 | } else if (qualifier == 'h') { |
603 | 0 | num = (unsigned short) va_arg(args, int); |
604 | 0 | if (flags & SIGN) |
605 | 0 | num = (signed short) num; |
606 | 706 | } else { |
607 | 706 | num = va_arg(args, unsigned int); |
608 | 706 | if (flags & SIGN) |
609 | 139 | num = (signed int) num; |
610 | 706 | } |
611 | 829 | |
612 | 829 | str = number(str, end, num, base, |
613 | 829 | field_width, precision, flags); |
614 | 829 | } |
615 | 682 | |
616 | 682 | /* don't write out a null byte if the buf size is zero */ |
617 | 682 | if (size > 0) { |
618 | 682 | if (str < end) |
619 | 682 | *str = '\0'; |
620 | 682 | else |
621 | 0 | end[-1] = '\0'; |
622 | 682 | } |
623 | 682 | /* the trailing null byte doesn't count towards the total |
624 | 682 | * ++str; |
625 | 682 | */ |
626 | 682 | return str-buf; |
627 | 682 | } |
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 | | */ |
645 | | int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) |
646 | 0 | { |
647 | 0 | int i; |
648 | 0 |
|
649 | 0 | i = vsnprintf(buf,size,fmt,args); |
650 | 0 | if (i >= size) |
651 | 0 | i = size - 1; |
652 | 0 | return (i > 0) ? i : 0; |
653 | 0 | } |
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 | | */ |
669 | | int snprintf(char * buf, size_t size, const char *fmt, ...) |
670 | 227 | { |
671 | 227 | va_list args; |
672 | 227 | int i; |
673 | 227 | |
674 | 227 | va_start(args, fmt); |
675 | 227 | i=vsnprintf(buf,size,fmt,args); |
676 | 227 | va_end(args); |
677 | 227 | return i; |
678 | 227 | } |
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 | | |
694 | | int scnprintf(char * buf, size_t size, const char *fmt, ...) |
695 | 0 | { |
696 | 0 | va_list args; |
697 | 0 | int i; |
698 | 0 |
|
699 | 0 | va_start(args, fmt); |
700 | 0 | i = vsnprintf(buf, size, fmt, args); |
701 | 0 | va_end(args); |
702 | 0 | if (i >= size) |
703 | 0 | i = size - 1; |
704 | 0 | return (i > 0) ? i : 0; |
705 | 0 | } |
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 | | */ |
720 | | int vasprintf(char **bufp, const char *fmt, va_list args) |
721 | 0 | { |
722 | 0 | va_list args_copy; |
723 | 0 | size_t size; |
724 | 0 | char *buf; |
725 | 0 |
|
726 | 0 | va_copy(args_copy, args); |
727 | 0 | size = vsnprintf(NULL, 0, fmt, args_copy); |
728 | 0 | va_end(args_copy); |
729 | 0 |
|
730 | 0 | buf = xmalloc_array(char, ++size); |
731 | 0 | if ( !buf ) |
732 | 0 | return -ENOMEM; |
733 | 0 |
|
734 | 0 | (void) vsnprintf(buf, size, fmt, args); |
735 | 0 |
|
736 | 0 | *bufp = buf; |
737 | 0 | return 0; |
738 | 0 | } |
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 | | */ |
751 | | int asprintf(char **bufp, const char *fmt, ...) |
752 | 0 | { |
753 | 0 | va_list args; |
754 | 0 | int i; |
755 | 0 |
|
756 | 0 | va_start(args, fmt); |
757 | 0 | i=vasprintf(bufp,fmt,args); |
758 | 0 | va_end(args); |
759 | 0 | return i; |
760 | 0 | } |
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 | | */ |