source: trunk/packages/xen-common/xen-common/xen/arch/powerpc/of_handler/snprintf.c @ 34

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

Add xen and xen-common

File size: 7.5 KB
Line 
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
15 *
16 * Copyright (C) IBM Corp. 2005
17 *
18 * Authors: Jimi Xenidis <jimix@watson.ibm.com>
19 */
20
21#include <xen/types.h>
22#include <stdarg.h>
23
24#define UPPER   0x00001
25#define SIGNED  0x00010
26#define ZERO    0x00100
27#define PTR 0x01000
28
29#define NUMBUFSZ 24     /* fits a 64bit value formatted in octal */
30
31/* do we need to handle 128 bits? */
32static ulong
33digits(char *buf, uint64_t val, ulong radix, ulong width, ulong flgs)
34{
35    const char hex[] = "0123456789abcdefx";
36    const char Hex[] = "0123456789ABCDEFX";
37    const char *dig;
38    char *b = buf;
39    char num[NUMBUFSZ];
40    ulong i;
41
42    if (radix == 0 || radix > 16) {
43        radix = 16;
44    }
45   
46    if (flgs & UPPER) {
47        dig = Hex;
48    } else {
49        dig = hex;
50    }
51   
52    /* sign */
53    if (flgs & SIGNED && radix == 10) {
54        /* there are corner cases here, for sure */
55        if ((int64_t)val < 0) {
56            *b++ = '-';
57            val *= -1;
58        }
59    }
60
61    /* ptr */
62    if (flgs & PTR && radix == 16) {
63        *b++ = '0';
64        *b++ = dig[16];
65    }
66
67    /* put it in t backwards */
68    i = 0;
69    if (val == 0) {
70        num[i++] = '0';
71    } else {
72        while (val > 0) {
73            num[i++] = dig[val % radix];
74            val /= radix;
75        }
76    }
77
78    /* pad */
79    if (flgs & ZERO && width > i) {
80        while (width-- > i) {
81            *b++ = '0';
82        }
83    }
84
85    /* number */
86    while (i-- > 0) {
87        *b++ = num[i];
88    }
89
90    return (b - buf);
91}
92
93/*
94 * yeah, I dislike goto's too, but ...
95 */
96int
97vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
98{
99    int c;
100    int nullify;
101    ulong used = 0;
102    ulong sz;
103    unsigned ells;
104    ulong flgs;
105    const char *str;
106    uint64_t val = 0;
107    ulong radix;
108    ulong width;
109    char num[NUMBUFSZ];
110
111    /* there must always be a trailing null */
112    if (size == 0) {
113        /* but don't write anything is size is zero */
114        nullify = 0;
115    } else {
116        --size;
117        nullify = 1;
118    }
119
120    while ((c = *fmt++) != '\0') {
121        if (c != '%') {
122            if (used++ < size) {
123                *buf++ = c;
124            }
125            continue;
126        }
127        /* deal with format */
128        ells = 0;
129        flgs = 0;
130
131        /* check for a given width */
132        width = 0;
133       
134        c = *fmt;
135        if (c >= '0' && c <= '9') {
136            flgs |= ZERO;
137            ++fmt;
138            while (c >= '0' && c <= '9') {
139                width = (width * 10) + (c - '0');
140                c = *fmt++;
141            }
142            --fmt;
143        }
144       
145loop:
146        c = *fmt++;
147        switch (c) {
148        case 'l':
149            ++ells;
150            goto loop;
151            /*NOTREACHED*/
152            break;
153
154        case 'h':   /* support linux kernel 'h'  for short */
155            ells = 0;
156            goto loop;
157            /*NOTREACHED*/
158            break;
159
160        case 'L':   /* support linux kernel 'L'  for long long */
161            ells = 2;
162            goto loop;
163            /*NOTREACHED*/
164            break;
165
166        case 'Z':   /* support linux kernel 'Z'  for [s]size_t */
167            /* I think it is safe to assume that 'long'
168             * just gets it right but, the compiler should
169             * do the right thing here anyway */
170            if (sizeof (size_t) > sizeof (unsigned)) {
171                ells = 1;
172            }
173            goto loop;
174            /*NOTREACHED*/
175            break;
176        case 's':
177            str = va_arg(ap, char *);
178            if (str == NULL) {
179                str = "(nil)";
180            }
181
182            /* copy over only what fits */
183            sz = 0;
184            while (*str != '\0') {
185                c = *str++;
186                if (used++ < size) {
187                    *buf++ = c;
188                }
189            }
190            break;
191        case 'c':
192            c = (char)va_arg(ap, int);
193            /*FALLTHRU*/
194        case '%':
195            if (used++ < size) {
196                *buf++ = c;
197            }
198            break;
199
200        case 'n':
201            /* totally untested */
202            switch (ells) {
203            case 0: {
204                unsigned *pval = va_arg(ap, unsigned *);
205                *pval = used;
206            }
207                break;
208            case 1: {
209                unsigned long *pval;
210                pval = va_arg(ap, unsigned long *);
211                *pval = used;
212            }
213                break;
214            default: {
215                unsigned long long *pval;
216                pval = va_arg(ap, unsigned long long *);
217                *pval = used;
218            }
219                break;
220            }
221           
222            break;
223        case 'p':
224            flgs |= (PTR | ZERO);
225            radix = 16;
226            val = (unsigned long) va_arg(ap, void *);
227            /* pad to max type by default */
228            if (sizeof (long) == sizeof (long long)) {
229                width = 16;
230            } else {
231                width = 8;
232            }
233            goto print_value;
234
235        case 'd': case 'i':
236            flgs |= SIGNED;
237            radix = 10;
238            switch (ells) {
239            case 0:
240                val = va_arg(ap, int);
241                break;
242            case 1:
243                val = va_arg(ap, long);
244                break;
245            default:
246                val = va_arg(ap, long long);
247                break;
248            }
249            goto print_value;
250
251        case 'u':
252            radix = 10;
253            goto print_ulongue;
254            break;
255
256        case 'o':
257            radix = 8;
258            goto print_ulongue;
259            break;
260
261        case 'X':
262            flgs |= UPPER;
263            /*FALLTHRU*/
264        case 'x':
265            radix = 16;
266print_ulongue:
267            switch (ells) {
268            case 0:
269                val = va_arg(ap, unsigned);
270                break;
271            case 1:
272                val = va_arg(ap, unsigned long);
273                break;
274            default:
275                val = va_arg(ap, unsigned long long);
276                break;
277            }
278
279print_value:
280            /* get the number */
281            sz = digits(num, val, radix, width, flgs);
282
283            str = num;
284            while (sz-- > 0) {
285                c = *str++;
286                if (used++ < size) {
287                    *buf++ = c;
288                }
289            }
290            break;
291           
292           
293        default:
294            break;
295        }
296    }
297    if (nullify) {
298        /* stuff a nul char but don't include it in return */
299        *buf++ = '\0';
300    }
301    return used;
302}
303
304int
305snprintf(char *buf, size_t size, const char *fmt, ...)
306{
307    va_list ap;
308    signed int ret;
309
310    va_start(ap, fmt);
311    ret = vsnprintf(buf, size, fmt, ap);
312    va_end(ap);
313    return ret;
314}
315
316int
317vsprintf(char *buf, const char *fmt, va_list ap)
318{
319    return vsnprintf(buf, ~0UL, fmt, ap);
320}
321
322int
323sprintf(char *buf, const char *fmt, ...)
324{
325    va_list ap;
326    signed int ret;
327
328    va_start(ap, fmt);
329    ret = vsprintf(buf, fmt, ap);
330    va_end(ap);
331    return ret;
332}
Note: See TracBrowser for help on using the repository browser.