source: trunk/packages/xen-3.1/xen-3.1/xen/common/vsprintf.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 15.2 KB
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/stdarg.h>
20#include <xen/ctype.h>
21#include <xen/lib.h>
22#include <asm/div64.h>
23#include <asm/page.h>
24
25/**
26 * simple_strtoul - convert a string to an unsigned long
27 * @cp: The start of the string
28 * @endp: A pointer to the end of the parsed string will be placed here
29 * @base: The number base to use
30 */
31unsigned long simple_strtoul(
32    const char *cp, const char **endp, unsigned int base)
33{
34    unsigned long result = 0,value;
35
36    if (!base) {
37        base = 10;
38        if (*cp == '0') {
39            base = 8;
40            cp++;
41            if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
42                cp++;
43                base = 16;
44            }
45        }
46    } else if (base == 16) {
47        if (cp[0] == '0' && toupper(cp[1]) == 'X')
48            cp += 2;
49    }
50    while (isxdigit(*cp) &&
51           (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
52        result = result*base + value;
53        cp++;
54    }
55    if (endp)
56        *endp = cp;
57    return result;
58}
59
60EXPORT_SYMBOL(simple_strtoul);
61
62/**
63 * simple_strtol - convert a string to a signed long
64 * @cp: The start of the string
65 * @endp: A pointer to the end of the parsed string will be placed here
66 * @base: The number base to use
67 */
68long simple_strtol(const char *cp, const char **endp, unsigned int base)
69{
70    if(*cp=='-')
71        return -simple_strtoul(cp+1,endp,base);
72    return simple_strtoul(cp,endp,base);
73}
74
75EXPORT_SYMBOL(simple_strtol);
76
77/**
78 * simple_strtoull - convert a string to an unsigned long long
79 * @cp: The start of the string
80 * @endp: A pointer to the end of the parsed string will be placed here
81 * @base: The number base to use
82 */
83unsigned long long simple_strtoull(
84    const char *cp, const char **endp, unsigned int base)
85{
86    unsigned long long result = 0,value;
87
88    if (!base) {
89        base = 10;
90        if (*cp == '0') {
91            base = 8;
92            cp++;
93            if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
94                cp++;
95                base = 16;
96            }
97        }
98    } else if (base == 16) {
99        if (cp[0] == '0' && toupper(cp[1]) == 'X')
100            cp += 2;
101    }
102    while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
103                                                               ? toupper(*cp) : *cp)-'A'+10) < base) {
104        result = result*base + value;
105        cp++;
106    }
107    if (endp)
108        *endp = cp;
109    return result;
110}
111
112EXPORT_SYMBOL(simple_strtoull);
113
114/**
115 * simple_strtoll - convert a string to a signed long long
116 * @cp: The start of the string
117 * @endp: A pointer to the end of the parsed string will be placed here
118 * @base: The number base to use
119 */
120long long simple_strtoll(const char *cp,const char **endp,unsigned int base)
121{
122    if(*cp=='-')
123        return -simple_strtoull(cp+1,endp,base);
124    return simple_strtoull(cp,endp,base);
125}
126
127static int skip_atoi(const char **s)
128{
129    int i=0;
130
131    while (isdigit(**s))
132        i = i*10 + *((*s)++) - '0';
133    return i;
134}
135
136#define ZEROPAD 1               /* pad with zero */
137#define SIGN    2               /* unsigned/signed long */
138#define PLUS    4               /* show plus */
139#define SPACE   8               /* space if plus */
140#define LEFT    16              /* left justified */
141#define SPECIAL 32              /* 0x */
142#define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
143
144static char *number(
145    char *buf, char *end, unsigned long long num,
146    int base, int size, int precision, int type)
147{
148    char c,sign,tmp[66];
149    const char *digits;
150    static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
151    static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
152    int i;
153
154    digits = (type & LARGE) ? large_digits : small_digits;
155    if (type & LEFT)
156        type &= ~ZEROPAD;
157    if (base < 2 || base > 36)
158        return NULL;
159    c = (type & ZEROPAD) ? '0' : ' ';
160    sign = 0;
161    if (type & SIGN) {
162        if ((signed long long) num < 0) {
163            sign = '-';
164            num = - (signed long long) num;
165            size--;
166        } else if (type & PLUS) {
167            sign = '+';
168            size--;
169        } else if (type & SPACE) {
170            sign = ' ';
171            size--;
172        }
173    }
174    if (type & SPECIAL) {
175        if (base == 16)
176            size -= 2;
177        else if (base == 8)
178            size--;
179    }
180    i = 0;
181    if (num == 0)
182        tmp[i++]='0';
183    else while (num != 0)
184        tmp[i++] = digits[do_div(num,base)];
185    if (i > precision)
186        precision = i;
187    size -= precision;
188    if (!(type&(ZEROPAD+LEFT))) {
189        while(size-->0) {
190            if (buf <= end)
191                *buf = ' ';
192            ++buf;
193        }
194    }
195    if (sign) {
196        if (buf <= end)
197            *buf = sign;
198        ++buf;
199    }
200    if (type & SPECIAL) {
201        if (base==8) {
202            if (buf <= end)
203                *buf = '0';
204            ++buf;
205        } else if (base==16) {
206            if (buf <= end)
207                *buf = '0';
208            ++buf;
209            if (buf <= end)
210                *buf = digits[33];
211            ++buf;
212        }
213    }
214    if (!(type & LEFT)) {
215        while (size-- > 0) {
216            if (buf <= end)
217                *buf = c;
218            ++buf;
219        }
220    }
221    while (i < precision--) {
222        if (buf <= end)
223            *buf = '0';
224        ++buf;
225    }
226    while (i-- > 0) {
227        if (buf <= end)
228            *buf = tmp[i];
229        ++buf;
230    }
231    while (size-- > 0) {
232        if (buf <= end)
233            *buf = ' ';
234        ++buf;
235    }
236    return buf;
237}
238
239/**
240 * vsnprintf - Format a string and place it in a buffer
241 * @buf: The buffer to place the result into
242 * @size: The size of the buffer, including the trailing null space
243 * @fmt: The format string to use
244 * @args: Arguments for the format string
245 *
246 * The return value is the number of characters which would
247 * be generated for the given input, excluding the trailing
248 * '\0', as per ISO C99. If you want to have the exact
249 * number of characters written into @buf as return value
250 * (not including the trailing '\0'), use vscnprintf. If the
251 * return is greater than or equal to @size, the resulting
252 * string is truncated.
253 *
254 * Call this function if you are already dealing with a va_list.
255 * You probably want snprintf instead.
256 */
257int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
258{
259    int len;
260    unsigned long long num;
261    int i, base;
262    char *str, *end, c;
263    const char *s;
264
265    int flags;          /* flags to number() */
266
267    int field_width;    /* width of output field */
268    int precision;              /* min. # of digits for integers; max
269                                   number of chars for from string */
270    int qualifier;              /* 'h', 'l', or 'L' for integer fields */
271                                /* 'z' support added 23/7/1999 S.H.    */
272                                /* 'z' changed to 'Z' --davidm 1/25/99 */
273
274    /* Reject out-of-range values early */
275    BUG_ON((int)size < 0);
276
277    str = buf;
278    end = buf + size - 1;
279
280    if (end < buf - 1) {
281        end = ((void *) -1);
282        size = end - buf + 1;
283    }
284
285    for (; *fmt ; ++fmt) {
286        if (*fmt != '%') {
287            if (str <= end)
288                *str = *fmt;
289            ++str;
290            continue;
291        }
292
293        /* process flags */
294        flags = 0;
295    repeat:
296        ++fmt;          /* this also skips first '%' */
297        switch (*fmt) {
298        case '-': flags |= LEFT; goto repeat;
299        case '+': flags |= PLUS; goto repeat;
300        case ' ': flags |= SPACE; goto repeat;
301        case '#': flags |= SPECIAL; goto repeat;
302        case '0': flags |= ZEROPAD; goto repeat;
303        }
304
305        /* get field width */
306        field_width = -1;
307        if (isdigit(*fmt))
308            field_width = skip_atoi(&fmt);
309        else if (*fmt == '*') {
310            ++fmt;
311            /* it's the next argument */
312            field_width = va_arg(args, int);
313            if (field_width < 0) {
314                field_width = -field_width;
315                flags |= LEFT;
316            }
317        }
318
319        /* get the precision */
320        precision = -1;
321        if (*fmt == '.') {
322            ++fmt;
323            if (isdigit(*fmt))
324                precision = skip_atoi(&fmt);
325            else if (*fmt == '*') {
326                ++fmt;
327                          /* it's the next argument */
328                precision = va_arg(args, int);
329            }
330            if (precision < 0)
331                precision = 0;
332        }
333
334        /* get the conversion qualifier */
335        qualifier = -1;
336        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
337            *fmt =='Z' || *fmt == 'z') {
338            qualifier = *fmt;
339            ++fmt;
340            if (qualifier == 'l' && *fmt == 'l') {
341                qualifier = 'L';
342                ++fmt;
343            }
344        }
345
346        /* default base */
347        base = 10;
348
349        switch (*fmt) {
350        case 'c':
351            if (!(flags & LEFT)) {
352                while (--field_width > 0) {
353                    if (str <= end)
354                        *str = ' ';
355                    ++str;
356                }
357            }
358            c = (unsigned char) va_arg(args, int);
359            if (str <= end)
360                *str = c;
361            ++str;
362            while (--field_width > 0) {
363                if (str <= end)
364                    *str = ' ';
365                ++str;
366            }
367            continue;
368
369        case 's':
370            s = va_arg(args, char *);
371            if ((unsigned long)s < PAGE_SIZE)
372                s = "<NULL>";
373
374            len = strnlen(s, precision);
375
376            if (!(flags & LEFT)) {
377                while (len < field_width--) {
378                    if (str <= end)
379                        *str = ' ';
380                    ++str;
381                }
382            }
383            for (i = 0; i < len; ++i) {
384                if (str <= end)
385                    *str = *s;
386                ++str; ++s;
387            }
388            while (len < field_width--) {
389                if (str <= end)
390                    *str = ' ';
391                ++str;
392            }
393            continue;
394
395        case 'p':
396            if (field_width == -1) {
397                field_width = 2*sizeof(void *);
398                flags |= ZEROPAD;
399            }
400            str = number(str, end,
401                         (unsigned long) va_arg(args, void *),
402                         16, field_width, precision, flags);
403            continue;
404
405
406        case 'n':
407            /* FIXME:
408             * What does C99 say about the overflow case here? */
409            if (qualifier == 'l') {
410                long * ip = va_arg(args, long *);
411                *ip = (str - buf);
412            } else if (qualifier == 'Z' || qualifier == 'z') {
413                size_t * ip = va_arg(args, size_t *);
414                *ip = (str - buf);
415            } else {
416                int * ip = va_arg(args, int *);
417                *ip = (str - buf);
418            }
419            continue;
420
421        case '%':
422            if (str <= end)
423                *str = '%';
424            ++str;
425            continue;
426
427                        /* integer number formats - set up the flags and "break" */
428        case 'o':
429            base = 8;
430            break;
431
432        case 'X':
433            flags |= LARGE;
434        case 'x':
435            base = 16;
436            break;
437
438        case 'd':
439        case 'i':
440            flags |= SIGN;
441        case 'u':
442            break;
443
444        default:
445            if (str <= end)
446                *str = '%';
447            ++str;
448            if (*fmt) {
449                if (str <= end)
450                    *str = *fmt;
451                ++str;
452            } else {
453                --fmt;
454            }
455            continue;
456        }
457        if (qualifier == 'L')
458            num = va_arg(args, long long);
459        else if (qualifier == 'l') {
460            num = va_arg(args, unsigned long);
461            if (flags & SIGN)
462                num = (signed long) num;
463        } else if (qualifier == 'Z' || qualifier == 'z') {
464            num = va_arg(args, size_t);
465        } else if (qualifier == 'h') {
466            num = (unsigned short) va_arg(args, int);
467            if (flags & SIGN)
468                num = (signed short) num;
469        } else {
470            num = va_arg(args, unsigned int);
471            if (flags & SIGN)
472                num = (signed int) num;
473        }
474
475        str = number(str, end, num, base,
476                     field_width, precision, flags);
477    }
478    if (str <= end)
479        *str = '\0';
480    else if (size > 0)
481        /* don't write out a null byte if the buf size is zero */
482        *end = '\0';
483    /* the trailing null byte doesn't count towards the total
484     * ++str;
485     */
486    return str-buf;
487}
488
489EXPORT_SYMBOL(vsnprintf);
490
491/**
492 * vscnprintf - Format a string and place it in a buffer
493 * @buf: The buffer to place the result into
494 * @size: The size of the buffer, including the trailing null space
495 * @fmt: The format string to use
496 * @args: Arguments for the format string
497 *
498 * The return value is the number of characters which have been written into
499 * the @buf not including the trailing '\0'. If @size is <= 0 the function
500 * returns 0.
501 *
502 * Call this function if you are already dealing with a va_list.
503 * You probably want scnprintf instead.
504 */
505int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
506{
507    int i;
508
509    i=vsnprintf(buf,size,fmt,args);
510    return (i >= size) ? (size - 1) : i;
511}
512
513EXPORT_SYMBOL(vscnprintf);
514
515/**
516 * snprintf - Format a string and place it in a buffer
517 * @buf: The buffer to place the result into
518 * @size: The size of the buffer, including the trailing null space
519 * @fmt: The format string to use
520 * @...: Arguments for the format string
521 *
522 * The return value is the number of characters which would be
523 * generated for the given input, excluding the trailing null,
524 * as per ISO C99.  If the return is greater than or equal to
525 * @size, the resulting string is truncated.
526 */
527int snprintf(char * buf, size_t size, const char *fmt, ...)
528{
529    va_list args;
530    int i;
531
532    va_start(args, fmt);
533    i=vsnprintf(buf,size,fmt,args);
534    va_end(args);
535    return i;
536}
537
538EXPORT_SYMBOL(snprintf);
539
540/**
541 * scnprintf - Format a string and place it in a buffer
542 * @buf: The buffer to place the result into
543 * @size: The size of the buffer, including the trailing null space
544 * @fmt: The format string to use
545 * @...: Arguments for the format string
546 *
547 * The return value is the number of characters written into @buf not including
548 * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
549 * greater than or equal to @size, the resulting string is truncated.
550 */
551
552int scnprintf(char * buf, size_t size, const char *fmt, ...)
553{
554    va_list args;
555    int i;
556
557    va_start(args, fmt);
558    i = vsnprintf(buf, size, fmt, args);
559    va_end(args);
560    return (i >= size) ? (size - 1) : i;
561}
562EXPORT_SYMBOL(scnprintf);
563
564/*
565 * Local variables:
566 * mode: C
567 * c-set-style: "BSD"
568 * c-basic-offset: 4
569 * tab-width: 4
570 * indent-tabs-mode: nil
571 * End:
572 */
Note: See TracBrowser for help on using the repository browser.