• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
strnlen(const char * s,int maxlen)18 static 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) ({ \
38 int __res; \
39 __res = ((unsigned long) n) % (unsigned) base; \
40 n = ((unsigned long) n) / (unsigned) base; \
41 __res; })
42 
number(char * str,long num,int base,int size,int precision,int type)43 static 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... */
112 int sprintf(char *buf, const char *fmt, ...);
113 
vsprintf(char * buf,const char * fmt,va_list args)114 int 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;
137 repeat:
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 
sprintf(char * buf,const char * fmt,...)284 int 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 
printf(const char * fmt,...)295 int 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 }
309