Adding upstream version 4.00~pre54+dfsg.
[syslinux-debian/hramrach.git] / sample / printf.c
blob6b7dda249bf3b4cd11ab8382012b82fc10960dd0
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."
7 * Most of this code was shamelessly snarfed from the Linux kernel, then
8 * modified.
10 * FIX THIS: Replace printf() implementation with BSD/MIT-licensed one
11 * from klibc
14 #include <stdarg.h>
16 int puts(const char *);
18 static inline int isdigit(int ch)
20 return (ch >= '0') && (ch <= '9');
23 unsigned int skip_atou(const char **s);
24 unsigned int atou(const char *s);
26 static int strnlen(const char *s, int maxlen)
28 const char *es = s;
29 while (*es && maxlen) {
30 es++;
31 maxlen--;
34 return (es - s);
37 #define ZEROPAD 1 /* pad with zero */
38 #define SIGN 2 /* unsigned/signed long */
39 #define PLUS 4 /* show plus */
40 #define SPACE 8 /* space if plus */
41 #define LEFT 16 /* left justified */
42 #define SPECIAL 32 /* 0x */
43 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
45 #define do_div(n,base) ({ \
46 int __res; \
47 __res = ((unsigned long) n) % (unsigned) base; \
48 n = ((unsigned long) n) / (unsigned) base; \
49 __res; })
51 static char *number(char *str, long num, int base, int size, int precision,
52 int type)
54 char c, sign, tmp[66];
55 const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
56 int i;
58 if (type & LARGE)
59 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
60 if (type & LEFT)
61 type &= ~ZEROPAD;
62 if (base < 2 || base > 36)
63 return 0;
64 c = (type & ZEROPAD) ? '0' : ' ';
65 sign = 0;
66 if (type & SIGN) {
67 if (num < 0) {
68 sign = '-';
69 num = -num;
70 size--;
71 } else if (type & PLUS) {
72 sign = '+';
73 size--;
74 } else if (type & SPACE) {
75 sign = ' ';
76 size--;
79 if (type & SPECIAL) {
80 if (base == 16)
81 size -= 2;
82 else if (base == 8)
83 size--;
85 i = 0;
86 if (num == 0)
87 tmp[i++] = '0';
88 else
89 while (num != 0)
90 tmp[i++] = digits[do_div(num, base)];
91 if (i > precision)
92 precision = i;
93 size -= precision;
94 if (!(type & (ZEROPAD + LEFT)))
95 while (size-- > 0)
96 *str++ = ' ';
97 if (sign)
98 *str++ = sign;
99 if (type & SPECIAL) {
100 if (base == 8)
101 *str++ = '0';
102 else if (base == 16) {
103 *str++ = '0';
104 *str++ = digits[33];
107 if (!(type & LEFT))
108 while (size-- > 0)
109 *str++ = c;
110 while (i < precision--)
111 *str++ = '0';
112 while (i-- > 0)
113 *str++ = tmp[i];
114 while (size-- > 0)
115 *str++ = ' ';
116 return str;
119 /* Forward decl. needed for IP address printing stuff... */
120 int sprintf(char *buf, const char *fmt, ...);
122 int vsprintf(char *buf, const char *fmt, va_list args)
124 int len;
125 unsigned long num;
126 int i, base;
127 char *str;
128 const char *s;
130 int flags; /* flags to number() */
132 int field_width; /* width of output field */
133 int precision; /* min. # of digits for integers; max
134 number of chars for from string */
135 int qualifier; /* 'h', 'l', or 'L' for integer fields */
137 for (str = buf; *fmt; ++fmt) {
138 if (*fmt != '%') {
139 *str++ = *fmt;
140 continue;
143 /* process flags */
144 flags = 0;
145 repeat:
146 ++fmt; /* this also skips first '%' */
147 switch (*fmt) {
148 case '-':
149 flags |= LEFT;
150 goto repeat;
151 case '+':
152 flags |= PLUS;
153 goto repeat;
154 case ' ':
155 flags |= SPACE;
156 goto repeat;
157 case '#':
158 flags |= SPECIAL;
159 goto repeat;
160 case '0':
161 flags |= ZEROPAD;
162 goto repeat;
165 /* get field width */
166 field_width = -1;
167 if (isdigit(*fmt))
168 field_width = skip_atou(&fmt);
169 else if (*fmt == '*') {
170 ++fmt;
171 /* it's the next argument */
172 field_width = va_arg(args, int);
173 if (field_width < 0) {
174 field_width = -field_width;
175 flags |= LEFT;
179 /* get the precision */
180 precision = -1;
181 if (*fmt == '.') {
182 ++fmt;
183 if (isdigit(*fmt))
184 precision = skip_atou(&fmt);
185 else if (*fmt == '*') {
186 ++fmt;
187 /* it's the next argument */
188 precision = va_arg(args, int);
190 if (precision < 0)
191 precision = 0;
194 /* get the conversion qualifier */
195 qualifier = -1;
196 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
197 qualifier = *fmt;
198 ++fmt;
201 /* default base */
202 base = 10;
204 switch (*fmt) {
205 case 'c':
206 if (!(flags & LEFT))
207 while (--field_width > 0)
208 *str++ = ' ';
209 *str++ = (unsigned char)va_arg(args, int);
210 while (--field_width > 0)
211 *str++ = ' ';
212 continue;
214 case 's':
215 s = va_arg(args, char *);
216 len = strnlen(s, precision);
218 if (!(flags & LEFT))
219 while (len < field_width--)
220 *str++ = ' ';
221 for (i = 0; i < len; ++i)
222 *str++ = *s++;
223 while (len < field_width--)
224 *str++ = ' ';
225 continue;
227 case 'p':
228 if (field_width == -1) {
229 field_width = 2 * sizeof(void *);
230 flags |= ZEROPAD;
232 str = number(str,
233 (unsigned long)va_arg(args, void *), 16,
234 field_width, precision, flags);
235 continue;
237 case 'n':
238 if (qualifier == 'l') {
239 long *ip = va_arg(args, long *);
240 *ip = (str - buf);
241 } else {
242 int *ip = va_arg(args, int *);
243 *ip = (str - buf);
245 continue;
247 case '%':
248 *str++ = '%';
249 continue;
251 /* integer number formats - set up the flags and "break" */
252 case 'o':
253 base = 8;
254 break;
256 case 'X':
257 flags |= LARGE;
258 case 'x':
259 base = 16;
260 break;
262 case 'd':
263 case 'i':
264 flags |= SIGN;
265 case 'u':
266 break;
268 default:
269 *str++ = '%';
270 if (*fmt)
271 *str++ = *fmt;
272 else
273 --fmt;
274 continue;
276 if (qualifier == 'l')
277 num = va_arg(args, unsigned long);
278 else if (qualifier == 'h') {
279 num = (unsigned short)va_arg(args, int);
280 if (flags & SIGN)
281 num = (short)num;
282 } else if (flags & SIGN)
283 num = va_arg(args, int);
284 else
285 num = va_arg(args, unsigned int);
286 str = number(str, num, base, field_width, precision, flags);
288 *str = '\0';
289 return str - buf;
292 int sprintf(char *buf, const char *fmt, ...)
294 va_list args;
295 int i;
297 va_start(args, fmt);
298 i = vsprintf(buf, fmt, args);
299 va_end(args);
300 return i;
303 int printf(const char *fmt, ...)
305 char printf_buf[1024];
306 va_list args;
307 int printed;
309 va_start(args, fmt);
310 printed = vsprintf(printf_buf, fmt, args);
311 va_end(args);
313 puts(printf_buf);
315 return printed;