1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8  *   Boston MA 02111-1307, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12 
13 /*
14  * conio.c
15  *
16  * Output to the screen
17  */
18 
19 #include <stdint.h>
20 #include "memdisk.h"
21 #include "conio.h"
22 
putchar(int ch)23 int putchar(int ch)
24 {
25     com32sys_t regs;
26     memset(&regs, 0, sizeof regs);
27 
28     if (ch == '\n') {
29 	/* \n -> \r\n */
30 	putchar('\r');
31     }
32 
33     regs.eax.w[0] = 0x0e00 | (ch & 0xff);
34     intcall(0x10, &regs, NULL);
35 
36     return ch;
37 }
38 
puts(const char * s)39 int puts(const char *s)
40 {
41     int count = 0;
42 
43     while (*s) {
44 	putchar(*s);
45 	count++;
46 	s++;
47     }
48 
49     return count;
50 }
51 
52 /*
53  * Oh, it's a waste of space, but oh-so-yummy for debugging.  It's just
54  * initialization code anyway, so it doesn't take up space when we're
55  * actually running.  This version of printf() does not include 64-bit
56  * support.  "Live with it."
57  *
58  * Most of this code was shamelessly snarfed from the Linux kernel, then
59  * modified.
60  */
61 
isdigit(int ch)62 static inline int isdigit(int ch)
63 {
64     return (ch >= '0') && (ch <= '9');
65 }
66 
skip_atoi(const char ** s)67 static int skip_atoi(const char **s)
68 {
69     int i = 0;
70 
71     while (isdigit(**s))
72 	i = i * 10 + *((*s)++) - '0';
73     return i;
74 }
75 
atou(const char * s)76 unsigned int atou(const char *s)
77 {
78     unsigned int i = 0;
79     while (isdigit(*s))
80 	i = i * 10 + (*s++ - '0');
81     return i;
82 }
83 
strnlen(const char * s,int maxlen)84 static int strnlen(const char *s, int maxlen)
85 {
86     const char *es = s;
87     while (*es && maxlen) {
88 	es++;
89 	maxlen--;
90     }
91 
92     return (es - s);
93 }
94 
95 #define ZEROPAD	1		/* pad with zero */
96 #define SIGN	2		/* unsigned/signed long */
97 #define PLUS	4		/* show plus */
98 #define SPACE	8		/* space if plus */
99 #define LEFT	16		/* left justified */
100 #define SPECIAL	32		/* 0x */
101 #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
102 
103 #define do_div(n,base) ({ \
104 int __res; \
105 __res = ((unsigned long) n) % (unsigned) base; \
106 n = ((unsigned long) n) / (unsigned) base; \
107 __res; })
108 
number(char * str,long num,int base,int size,int precision,int type)109 static char *number(char *str, long num, int base, int size, int precision,
110 		    int type)
111 {
112     char c, sign, tmp[66];
113     const char *digits = "0123456789abcdef";
114     int i;
115 
116     if (type & LARGE)
117 	digits = "0123456789ABCDEF";
118     if (type & LEFT)
119 	type &= ~ZEROPAD;
120     if (base < 2 || base > 36)
121 	return 0;
122     c = (type & ZEROPAD) ? '0' : ' ';
123     sign = 0;
124     if (type & SIGN) {
125 	if (num < 0) {
126 	    sign = '-';
127 	    num = -num;
128 	    size--;
129 	} else if (type & PLUS) {
130 	    sign = '+';
131 	    size--;
132 	} else if (type & SPACE) {
133 	    sign = ' ';
134 	    size--;
135 	}
136     }
137     if (type & SPECIAL) {
138 	if (base == 16)
139 	    size -= 2;
140 	else if (base == 8)
141 	    size--;
142     }
143     i = 0;
144     if (num == 0)
145 	tmp[i++] = '0';
146     else
147 	while (num != 0)
148 	    tmp[i++] = digits[do_div(num, base)];
149     if (i > precision)
150 	precision = i;
151     size -= precision;
152     if (!(type & (ZEROPAD + LEFT)))
153 	while (size-- > 0)
154 	    *str++ = ' ';
155     if (sign)
156 	*str++ = sign;
157     if (type & SPECIAL) {
158 	if (base == 8)
159 	    *str++ = '0';
160 	else if (base == 16) {
161 	    *str++ = '0';
162 	    *str++ = digits[33];
163 	}
164     }
165     if (!(type & LEFT))
166 	while (size-- > 0)
167 	    *str++ = c;
168     while (i < precision--)
169 	*str++ = '0';
170     while (i-- > 0)
171 	*str++ = tmp[i];
172     while (size-- > 0)
173 	*str++ = ' ';
174     return str;
175 }
176 
vsprintf(char * buf,const char * fmt,va_list args)177 int vsprintf(char *buf, const char *fmt, va_list args)
178 {
179     int len;
180     unsigned long num;
181     int i, base;
182     char *str;
183     const char *s;
184 
185     int flags;			/* flags to number() */
186 
187     int field_width;		/* width of output field */
188     int precision;		/* min. # of digits for integers; max
189 				   number of chars for from string */
190     int qualifier;		/* 'h', 'l', or 'L' for integer fields */
191 
192     for (str = buf; *fmt; ++fmt) {
193 	if (*fmt != '%') {
194 	    *str++ = *fmt;
195 	    continue;
196 	}
197 
198 	/* process flags */
199 	flags = 0;
200 repeat:
201 	++fmt;			/* this also skips first '%' */
202 	switch (*fmt) {
203 	case '-':
204 	    flags |= LEFT;
205 	    goto repeat;
206 	case '+':
207 	    flags |= PLUS;
208 	    goto repeat;
209 	case ' ':
210 	    flags |= SPACE;
211 	    goto repeat;
212 	case '#':
213 	    flags |= SPECIAL;
214 	    goto repeat;
215 	case '0':
216 	    flags |= ZEROPAD;
217 	    goto repeat;
218 	}
219 
220 	/* get field width */
221 	field_width = -1;
222 	if (isdigit(*fmt))
223 	    field_width = skip_atoi(&fmt);
224 	else if (*fmt == '*') {
225 	    ++fmt;
226 	    /* it's the next argument */
227 	    field_width = va_arg(args, int);
228 	    if (field_width < 0) {
229 		field_width = -field_width;
230 		flags |= LEFT;
231 	    }
232 	}
233 
234 	/* get the precision */
235 	precision = -1;
236 	if (*fmt == '.') {
237 	    ++fmt;
238 	    if (isdigit(*fmt))
239 		precision = skip_atoi(&fmt);
240 	    else if (*fmt == '*') {
241 		++fmt;
242 		/* it's the next argument */
243 		precision = va_arg(args, int);
244 	    }
245 	    if (precision < 0)
246 		precision = 0;
247 	}
248 
249 	/* get the conversion qualifier */
250 	qualifier = -1;
251 	if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
252 	    qualifier = *fmt;
253 	    ++fmt;
254 	}
255 
256 	/* default base */
257 	base = 10;
258 
259 	switch (*fmt) {
260 	case 'c':
261 	    if (!(flags & LEFT))
262 		while (--field_width > 0)
263 		    *str++ = ' ';
264 	    *str++ = (unsigned char)va_arg(args, int);
265 	    while (--field_width > 0)
266 		*str++ = ' ';
267 	    continue;
268 
269 	case 's':
270 	    s = va_arg(args, char *);
271 	    len = strnlen(s, precision);
272 
273 	    if (!(flags & LEFT))
274 		while (len < field_width--)
275 		    *str++ = ' ';
276 	    for (i = 0; i < len; ++i)
277 		*str++ = *s++;
278 	    while (len < field_width--)
279 		*str++ = ' ';
280 	    continue;
281 
282 	case 'p':
283 	    if (field_width == -1) {
284 		field_width = 2 * sizeof(void *);
285 		flags |= ZEROPAD;
286 	    }
287 	    str = number(str,
288 			 (unsigned long)va_arg(args, void *), 16,
289 			 field_width, precision, flags);
290 	    continue;
291 
292 	case 'n':
293 	    if (qualifier == 'l') {
294 		long *ip = va_arg(args, long *);
295 		*ip = (str - buf);
296 	    } else {
297 		int *ip = va_arg(args, int *);
298 		*ip = (str - buf);
299 	    }
300 	    continue;
301 
302 	case '%':
303 	    *str++ = '%';
304 	    continue;
305 
306 	    /* integer number formats - set up the flags and "break" */
307 	case 'o':
308 	    base = 8;
309 	    break;
310 
311 	case 'X':
312 	    flags |= LARGE;
313 	case 'x':
314 	    base = 16;
315 	    break;
316 
317 	case 'd':
318 	case 'i':
319 	    flags |= SIGN;
320 	case 'u':
321 	    break;
322 
323 	default:
324 	    *str++ = '%';
325 	    if (*fmt)
326 		*str++ = *fmt;
327 	    else
328 		--fmt;
329 	    continue;
330 	}
331 	if (qualifier == 'l')
332 	    num = va_arg(args, unsigned long);
333 	else if (qualifier == 'h') {
334 	    num = (unsigned short)va_arg(args, int);
335 	    if (flags & SIGN)
336 		num = (short)num;
337 	} else if (flags & SIGN)
338 	    num = va_arg(args, int);
339 	else
340 	    num = va_arg(args, unsigned int);
341 	str = number(str, num, base, field_width, precision, flags);
342     }
343     *str = '\0';
344     return str - buf;
345 }
346 
347 #if 0
348 int sprintf(char *buf, const char *fmt, ...)
349 {
350     va_list args;
351     int i;
352 
353     va_start(args, fmt);
354     i = vsprintf(buf, fmt, args);
355     va_end(args);
356     return i;
357 }
358 #endif
359 
vprintf(const char * fmt,va_list args)360 int vprintf(const char *fmt, va_list args)
361 {
362     char printf_buf[2048];
363     int printed;
364 
365     printed = vsprintf(printf_buf, fmt, args);
366     puts(printf_buf);
367     return printed;
368 }
369 
printf(const char * fmt,...)370 int printf(const char *fmt, ...)
371 {
372     va_list args;
373     int printed;
374 
375     va_start(args, fmt);
376     printed = vprintf(fmt, args);
377     va_end(args);
378     return printed;
379 }
380 
381 /*
382  * Jump here if all hope is gone...
383  */
die(const char * fmt,...)384 void __attribute__ ((noreturn)) die(const char *fmt, ...)
385 {
386     va_list ap;
387 
388     va_start(ap, fmt);
389     vprintf(fmt, ap);
390     va_end(ap);
391 
392     sti();
393     for (;;)
394 	asm volatile("hlt");
395 }
396