Merge commit 'origin/master' into adv
[profile/ivi/syslinux.git] / memdisk / conio.c
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
23 int putchar(int ch)
24 {
25   com32sys_t regs;
26
27   if ( ch == '\n' ) {
28     /* \n -> \r\n */
29     putchar('\r');
30   }
31
32   regs.eax.w[0] = 0x0e00|(ch&0xff);
33   syscall(0x10, &regs, NULL);
34
35   return ch;
36 }
37
38 int puts(const char *s)
39 {
40   int count = 0;
41
42   while ( *s ) {
43     putchar(*s);
44     count++;
45     s++;
46   }
47
48   return count;
49 }
50
51 /*
52  * Oh, it's a waste of space, but oh-so-yummy for debugging.  It's just
53  * initialization code anyway, so it doesn't take up space when we're
54  * actually running.  This version of printf() does not include 64-bit
55  * support.  "Live with it."
56  *
57  * Most of this code was shamelessly snarfed from the Linux kernel, then
58  * modified.
59  */
60
61 static inline int
62 isdigit(int ch)
63 {
64   return (ch >= '0') && (ch <= '9');
65 }
66
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
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
84 static int strnlen(const char *s, int maxlen)
85 {
86   const char *es = s;
87   while ( *es && maxlen ) {
88     es++; maxlen--;
89   }
90
91   return (es-s);
92 }
93
94 #define ZEROPAD 1               /* pad with zero */
95 #define SIGN    2               /* unsigned/signed long */
96 #define PLUS    4               /* show plus */
97 #define SPACE   8               /* space if plus */
98 #define LEFT    16              /* left justified */
99 #define SPECIAL 32              /* 0x */
100 #define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
101
102 #define do_div(n,base) ({ \
103 int __res; \
104 __res = ((unsigned long) n) % (unsigned) base; \
105 n = ((unsigned long) n) / (unsigned) base; \
106 __res; })
107
108 static char * number(char * str, long num, int base, int size, int precision
109         ,int type)
110 {
111   char c,sign,tmp[66];
112   const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
113   int i;
114
115   if (type & LARGE)
116     digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
117   if (type & LEFT)
118     type &= ~ZEROPAD;
119   if (base < 2 || base > 36)
120     return 0;
121   c = (type & ZEROPAD) ? '0' : ' ';
122   sign = 0;
123   if (type & SIGN) {
124     if (num < 0) {
125       sign = '-';
126       num = -num;
127       size--;
128     } else if (type & PLUS) {
129       sign = '+';
130       size--;
131     } else if (type & SPACE) {
132       sign = ' ';
133       size--;
134     }
135   }
136   if (type & SPECIAL) {
137     if (base == 16)
138       size -= 2;
139     else if (base == 8)
140       size--;
141   }
142   i = 0;
143   if (num == 0)
144     tmp[i++]='0';
145   else while (num != 0)
146     tmp[i++] = digits[do_div(num,base)];
147   if (i > precision)
148     precision = i;
149   size -= precision;
150   if (!(type&(ZEROPAD+LEFT)))
151     while(size-->0)
152       *str++ = ' ';
153   if (sign)
154     *str++ = sign;
155   if (type & SPECIAL) {
156     if (base==8)
157       *str++ = '0';
158     else if (base==16) {
159       *str++ = '0';
160       *str++ = digits[33];
161     }
162   }
163   if (!(type & LEFT))
164     while (size-- > 0)
165       *str++ = c;
166   while (i < precision--)
167     *str++ = '0';
168   while (i-- > 0)
169     *str++ = tmp[i];
170   while (size-- > 0)
171     *str++ = ' ';
172   return str;
173 }
174
175 /* Forward decl. needed for IP address printing stuff... */
176 int sprintf(char * buf, const char *fmt, ...);
177
178 int vsprintf(char *buf, const char *fmt, va_list args)
179 {
180   int len;
181   unsigned long num;
182   int i, base;
183   char * str;
184   const char *s;
185
186   int flags;            /* flags to number() */
187
188   int field_width;      /* width of output field */
189   int precision;                /* min. # of digits for integers; max
190                                    number of chars for from string */
191   int qualifier;                /* 'h', 'l', or 'L' for integer fields */
192
193   for (str=buf ; *fmt ; ++fmt) {
194     if (*fmt != '%') {
195       *str++ = *fmt;
196       continue;
197     }
198
199     /* process flags */
200     flags = 0;
201   repeat:
202     ++fmt;              /* this also skips first '%' */
203     switch (*fmt) {
204     case '-': flags |= LEFT; goto repeat;
205     case '+': flags |= PLUS; goto repeat;
206     case ' ': flags |= SPACE; goto repeat;
207     case '#': flags |= SPECIAL; goto repeat;
208     case '0': flags |= ZEROPAD; goto repeat;
209     }
210
211     /* get field width */
212     field_width = -1;
213     if (isdigit(*fmt))
214       field_width = skip_atoi(&fmt);
215     else if (*fmt == '*') {
216       ++fmt;
217       /* it's the next argument */
218       field_width = va_arg(args, int);
219       if (field_width < 0) {
220         field_width = -field_width;
221         flags |= LEFT;
222       }
223     }
224
225     /* get the precision */
226     precision = -1;
227     if (*fmt == '.') {
228       ++fmt;
229       if (isdigit(*fmt))
230         precision = skip_atoi(&fmt);
231       else if (*fmt == '*') {
232         ++fmt;
233         /* it's the next argument */
234         precision = va_arg(args, int);
235       }
236       if (precision < 0)
237         precision = 0;
238     }
239
240     /* get the conversion qualifier */
241     qualifier = -1;
242     if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
243       qualifier = *fmt;
244       ++fmt;
245     }
246
247     /* default base */
248     base = 10;
249
250     switch (*fmt) {
251     case 'c':
252       if (!(flags & LEFT))
253         while (--field_width > 0)
254           *str++ = ' ';
255       *str++ = (unsigned char) va_arg(args, int);
256       while (--field_width > 0)
257         *str++ = ' ';
258       continue;
259
260     case 's':
261       s = va_arg(args, char *);
262       len = strnlen(s, precision);
263
264       if (!(flags & LEFT))
265         while (len < field_width--)
266           *str++ = ' ';
267       for (i = 0; i < len; ++i)
268         *str++ = *s++;
269       while (len < field_width--)
270         *str++ = ' ';
271       continue;
272
273     case 'p':
274       if (field_width == -1) {
275         field_width = 2*sizeof(void *);
276         flags |= ZEROPAD;
277       }
278       str = number(str,
279                    (unsigned long) va_arg(args, void *), 16,
280                    field_width, precision, flags);
281       continue;
282
283
284     case 'n':
285       if (qualifier == 'l') {
286         long * ip = va_arg(args, long *);
287         *ip = (str - buf);
288       } else {
289         int * ip = va_arg(args, int *);
290         *ip = (str - buf);
291       }
292       continue;
293
294     case '%':
295       *str++ = '%';
296       continue;
297
298       /* integer number formats - set up the flags and "break" */
299     case 'o':
300       base = 8;
301       break;
302
303     case 'X':
304       flags |= LARGE;
305     case 'x':
306       base = 16;
307       break;
308
309     case 'd':
310     case 'i':
311       flags |= SIGN;
312     case 'u':
313       break;
314
315     default:
316       *str++ = '%';
317       if (*fmt)
318         *str++ = *fmt;
319       else
320         --fmt;
321       continue;
322     }
323     if (qualifier == 'l')
324       num = va_arg(args, unsigned long);
325     else if (qualifier == 'h') {
326       num = (unsigned short) va_arg(args, int);
327       if (flags & SIGN)
328         num = (short) num;
329     } else if (flags & SIGN)
330       num = va_arg(args, int);
331     else
332       num = va_arg(args, unsigned int);
333     str = number(str, num, base, field_width, precision, flags);
334   }
335   *str = '\0';
336   return str-buf;
337 }
338
339 int sprintf(char * buf, const char *fmt, ...)
340 {
341   va_list args;
342   int i;
343
344   va_start(args, fmt);
345   i=vsprintf(buf,fmt,args);
346   va_end(args);
347   return i;
348 }
349
350 int printf(const char *fmt, ...)
351 {
352   char printf_buf[1024];
353   va_list args;
354   int printed;
355
356   va_start(args, fmt);
357   printed = vsprintf(printf_buf, fmt, args);
358   va_end(args);
359
360   puts(printf_buf);
361
362   return printed;
363 }