source: bootcd/isolinux/syslinux-6.03/dos/printf.c @ dd1be7c

Last change on this file since dd1be7c was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/*
2 * Oh, it's a waste of space, but oh-so-yummy for debugging.  It's just
3 * initialization code anyway, so it doesn't take up space when we're
4 * actually running.  This version of printf() does not include 64-bit
5 * support.  "Live with it."
6 *
7 * Most of this code was shamelessly snarfed from the Linux kernel, then
8 * modified.  It's therefore GPL.
9 *
10 * printf() isn't actually needed to build syslinux.com, but during
11 * debugging it's handy.
12 */
13
14#include <stdarg.h>
15#include <stdio.h>
16#include "mystuff.h"
17
18static int strnlen(const char *s, int maxlen)
19{
20    const char *es = s;
21    while (*es && maxlen) {
22        es++;
23        maxlen--;
24    }
25
26    return (es - s);
27}
28
29#define ZEROPAD 1               /* pad with zero */
30#define SIGN    2               /* unsigned/signed long */
31#define PLUS    4               /* show plus */
32#define SPACE   8               /* space if plus */
33#define LEFT    16              /* left justified */
34#define SPECIAL 32              /* 0x */
35#define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
36
37#define do_div(n,base) ({ \
38int __res; \
39__res = ((unsigned long) n) % (unsigned) base; \
40n = ((unsigned long) n) / (unsigned) base; \
41__res; })
42
43static char *number(char *str, long num, int base, int size, int precision,
44                    int type)
45{
46    char c, sign, tmp[66];
47    const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
48    int i;
49
50    if (type & LARGE)
51        digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
52    if (type & LEFT)
53        type &= ~ZEROPAD;
54    if (base < 2 || base > 36)
55        return 0;
56    c = (type & ZEROPAD) ? '0' : ' ';
57    sign = 0;
58    if (type & SIGN) {
59        if (num < 0) {
60            sign = '-';
61            num = -num;
62            size--;
63        } else if (type & PLUS) {
64            sign = '+';
65            size--;
66        } else if (type & SPACE) {
67            sign = ' ';
68            size--;
69        }
70    }
71    if (type & SPECIAL) {
72        if (base == 16)
73            size -= 2;
74        else if (base == 8)
75            size--;
76    }
77    i = 0;
78    if (num == 0)
79        tmp[i++] = '0';
80    else
81        while (num != 0)
82            tmp[i++] = digits[do_div(num, base)];
83    if (i > precision)
84        precision = i;
85    size -= precision;
86    if (!(type & (ZEROPAD + LEFT)))
87        while (size-- > 0)
88            *str++ = ' ';
89    if (sign)
90        *str++ = sign;
91    if (type & SPECIAL) {
92        if (base == 8)
93            *str++ = '0';
94        else if (base == 16) {
95            *str++ = '0';
96            *str++ = digits[33];
97        }
98    }
99    if (!(type & LEFT))
100        while (size-- > 0)
101            *str++ = c;
102    while (i < precision--)
103        *str++ = '0';
104    while (i-- > 0)
105        *str++ = tmp[i];
106    while (size-- > 0)
107        *str++ = ' ';
108    return str;
109}
110
111/* Forward decl. needed for IP address printing stuff... */
112int sprintf(char *buf, const char *fmt, ...);
113
114int vsprintf(char *buf, const char *fmt, va_list args)
115{
116    int len;
117    unsigned long num;
118    int i, base;
119    char *str;
120    const char *s;
121
122    int flags;                  /* flags to number() */
123
124    int field_width;            /* width of output field */
125    int precision;              /* min. # of digits for integers; max
126                                   number of chars for from string */
127    int qualifier;              /* 'h', 'l', or 'L' for integer fields */
128
129    for (str = buf; *fmt; ++fmt) {
130        if (*fmt != '%') {
131            *str++ = *fmt;
132            continue;
133        }
134
135        /* process flags */
136        flags = 0;
137repeat:
138        ++fmt;                  /* this also skips first '%' */
139        switch (*fmt) {
140        case '-':
141            flags |= LEFT;
142            goto repeat;
143        case '+':
144            flags |= PLUS;
145            goto repeat;
146        case ' ':
147            flags |= SPACE;
148            goto repeat;
149        case '#':
150            flags |= SPECIAL;
151            goto repeat;
152        case '0':
153            flags |= ZEROPAD;
154            goto repeat;
155        }
156
157        /* get field width */
158        field_width = -1;
159        if (isdigit(*fmt))
160            field_width = skip_atou(&fmt);
161        else if (*fmt == '*') {
162            ++fmt;
163            /* it's the next argument */
164            field_width = va_arg(args, int);
165            if (field_width < 0) {
166                field_width = -field_width;
167                flags |= LEFT;
168            }
169        }
170
171        /* get the precision */
172        precision = -1;
173        if (*fmt == '.') {
174            ++fmt;
175            if (isdigit(*fmt))
176                precision = skip_atou(&fmt);
177            else if (*fmt == '*') {
178                ++fmt;
179                /* it's the next argument */
180                precision = va_arg(args, int);
181            }
182            if (precision < 0)
183                precision = 0;
184        }
185
186        /* get the conversion qualifier */
187        qualifier = -1;
188        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
189            qualifier = *fmt;
190            ++fmt;
191        }
192
193        /* default base */
194        base = 10;
195
196        switch (*fmt) {
197        case 'c':
198            if (!(flags & LEFT))
199                while (--field_width > 0)
200                    *str++ = ' ';
201            *str++ = (unsigned char)va_arg(args, int);
202            while (--field_width > 0)
203                *str++ = ' ';
204            continue;
205
206        case 's':
207            s = va_arg(args, char *);
208            len = strnlen(s, precision);
209
210            if (!(flags & LEFT))
211                while (len < field_width--)
212                    *str++ = ' ';
213            for (i = 0; i < len; ++i)
214                *str++ = *s++;
215            while (len < field_width--)
216                *str++ = ' ';
217            continue;
218
219        case 'p':
220            if (field_width == -1) {
221                field_width = 2 * sizeof(void *);
222                flags |= ZEROPAD;
223            }
224            str = number(str,
225                         (unsigned long)va_arg(args, void *), 16,
226                         field_width, precision, flags);
227            continue;
228
229        case 'n':
230            if (qualifier == 'l') {
231                long *ip = va_arg(args, long *);
232                *ip = (str - buf);
233            } else {
234                int *ip = va_arg(args, int *);
235                *ip = (str - buf);
236            }
237            continue;
238
239        case '%':
240            *str++ = '%';
241            continue;
242
243            /* integer number formats - set up the flags and "break" */
244        case 'o':
245            base = 8;
246            break;
247
248        case 'X':
249            flags |= LARGE;
250        case 'x':
251            base = 16;
252            break;
253
254        case 'd':
255        case 'i':
256            flags |= SIGN;
257        case 'u':
258            break;
259
260        default:
261            *str++ = '%';
262            if (*fmt)
263                *str++ = *fmt;
264            else
265                --fmt;
266            continue;
267        }
268        if (qualifier == 'l')
269            num = va_arg(args, unsigned long);
270        else if (qualifier == 'h') {
271            num = (unsigned short)va_arg(args, int);
272            if (flags & SIGN)
273                num = (short)num;
274        } else if (flags & SIGN)
275            num = va_arg(args, int);
276        else
277            num = va_arg(args, unsigned int);
278        str = number(str, num, base, field_width, precision, flags);
279    }
280    *str = '\0';
281    return str - buf;
282}
283
284int sprintf(char *buf, const char *fmt, ...)
285{
286    va_list args;
287    int i;
288
289    va_start(args, fmt);
290    i = vsprintf(buf, fmt, args);
291    va_end(args);
292    return i;
293}
294
295int printf(const char *fmt, ...)
296{
297    char printf_buf[1024];
298    va_list args;
299    int printed;
300
301    va_start(args, fmt);
302    printed = vsprintf(printf_buf, fmt, args);
303    va_end(args);
304
305    puts(printf_buf);
306
307    return printed;
308}
Note: See TracBrowser for help on using the repository browser.