OSDN Git Service

5b1ce3a1840116c1263243973b0d228c4372a865
[uzume/uzume_bfin.git] / uzumeapp / kernel / uzume / ntshell / ntstdio.c
1 /**
2  * @file ntstdio.c
3  * @author Shinichiro Nakamura
4  * @brief Natural Tiny Standard I/O Module
5  * @details
6  * The Natural Tiny Standard I/O Module based on xprintf by ChaN.
7  * xprintf is a universal string handler for user console interface.
8  */
9
10 /*------------------------------------------------------------------------/
11 /  Universal string handler for user console interface
12 /-------------------------------------------------------------------------/
13 /
14 /  Copyright (C) 2011, ChaN, all right reserved.
15 /
16 / * This software is a free software and there is NO WARRANTY.
17 / * No restriction on use. You can use, modify and redistribute it for
18 /   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
19 / * Redistributions of source code must retain the above copyright notice.
20 /
21 /-------------------------------------------------------------------------*/
22
23 /*
24  * ===============================================================
25  * Natural Tiny Standard I/O Module
26  * ===============================================================
27  * Copyright (c) 2013 Shinichiro Nakamura
28  *
29  * Permission is hereby granted, free of charge, to any person
30  * obtaining a copy of this software and associated documentation
31  * files (the "Software"), to deal in the Software without
32  * restriction, including without limitation the rights to use,
33  * copy, modify, merge, publish, distribute, sublicense, and/or
34  * sell copies of the Software, and to permit persons to whom the
35  * Software is furnished to do so, subject to the following
36  * conditions:
37  *
38  * The above copyright notice and this permission notice shall be
39  * included in all copies or substantial portions of the Software.
40  *
41  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
42  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
43  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
44  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
45  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
46  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
47  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
48  * OTHER DEALINGS IN THE SOFTWARE.
49  * ===============================================================
50  */
51
52 #include <stdarg.h>
53 #include "ntstdio.h"
54
55 #define FLAG_ZERO_PADDED    (1 << 0)
56 #define FLAG_LEFT_JUSTIFIED (1 << 1)
57 #define FLAG_SIZE_LONG_INT  (1 << 2)
58 #define FLAG_SIGNED_DECIMAL (1 << 3)
59
60 /*
61  * ntstdio_printf("%d", 1234);            "1234"
62  * ntstdio_printf("%6d,%3d%%", -200, 5);  "  -200,  5%"
63  * ntstdio_printf("%-6u", 100);           "100   "
64  * ntstdio_printf("%ld", 12345678L);      "12345678"
65  * ntstdio_printf("%04x", 0xA3);          "00a3"
66  * ntstdio_printf("%08LX", 0x123ABC);     "00123ABC"
67  * ntstdio_printf("%016b", 0x550F);       "0101010100001111"
68  * ntstdio_printf("%s", "String");        "String"
69  * ntstdio_printf("%-4s", "abc");         "abc "
70  * ntstdio_printf("%4s", "abc");          " abc"
71  * ntstdio_printf("%c", 'a');             "a"
72  * ntstdio_printf("%f", 10.0);            <ntstdio_printf lacks floating point support>
73  */
74
75 static void xvprintf(ntstdio_t *handle, const char *fmt, va_list arp)
76 {
77     unsigned int i, j;
78     unsigned int flag, radix, width;
79     unsigned long value;
80     char s[16], c, d, *p;
81
82     while (1) {
83         /*
84          * Get a character.
85          */
86         c = *fmt++;
87         if (!c) {
88             /*
89              * End of the format.
90              */
91             break;
92         }
93         if (c != '%') {
94             /*
95              * Pass through it if not a % sequense
96              */
97             ntstdio_putc(handle, c);
98             continue;
99         }
100
101         /*
102          * Reset the flag.
103          */
104         flag = 0;
105
106         /*
107          * Get the first character of the sequense.
108          */
109         c = *fmt++;
110         if (c == '0') {
111             flag = FLAG_ZERO_PADDED;
112             c = *fmt++;
113         } else {
114             if (c == '-') {
115                 flag = FLAG_LEFT_JUSTIFIED;
116                 c = *fmt++;
117             }
118         }
119         /*
120          * Calculate the minimum width.
121          */
122         for (width = 0; (c >= '0') && (c <= '9'); c = *fmt++) {
123             width = (width * 10) + (c - '0');
124         }
125         if ((c == 'l') || (c == 'L')) {
126             flag |= FLAG_SIZE_LONG_INT;
127             c = *fmt++;
128         }
129         if (!c) {
130             /*
131              * End of the format.
132              */
133             break;
134         }
135         d = c;
136         if (d >= 'a') {
137             d -= 0x20;
138         }
139         /* Type is... */
140         switch (d) {
141             case 'S' :
142                 /* String */
143                 p = va_arg(arp, char*);
144                 for (j = 0; p[j]; j++) {
145                 }
146                 while (!(flag & FLAG_LEFT_JUSTIFIED) && (j++ < width)) {
147                     ntstdio_putc(handle, ' ');
148                 }
149                 ntstdio_puts(handle, p);
150                 while (j++ < width) {
151                     ntstdio_putc(handle, ' ');
152                 }
153                 continue;
154             case 'C' :
155                 /* Character */
156                 ntstdio_putc(handle, (char)va_arg(arp, int));
157                 continue;
158             case 'B' :
159                 /* Binary */
160                 radix = 2;
161                 break;
162             case 'O' :
163                 /* Octal */
164                 radix = 8;
165                 break;
166             case 'D' :
167                 /* Signed decimal */
168                 radix = 10;
169                 break;
170             case 'U' :
171                 /* Unsigned decimal */
172                 radix = 10;
173                 break;
174             case 'X' :
175                 /* Hexdecimal */
176                 radix = 16;
177                 break;
178             default:
179                 /* Unknown type (passthrough) */
180                 ntstdio_putc(handle, c);
181                 continue;
182         }
183
184         /*
185          * Get an argument and put it in numeral.
186          */
187         value = (flag & FLAG_SIZE_LONG_INT) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int));
188         if ((d == 'D') && (value & 0x80000000)) {
189             value = 0 - value;
190             flag |= FLAG_SIGNED_DECIMAL;
191         }
192         i = 0;
193         do {
194             d = (char)(value % radix);
195             value /= radix;
196             if (d > 9) {
197                 d += (c == 'x') ? 0x27 : 0x07;
198             }
199             s[i++] = d + '0';
200         } while (value && (i < sizeof(s)));
201         if (flag & FLAG_SIGNED_DECIMAL) {
202             s[i++] = '-';
203         }
204         j = i;
205         d = (flag & FLAG_ZERO_PADDED) ? '0' : ' ';
206         while (!(flag & FLAG_LEFT_JUSTIFIED) && (j++ < width)) {
207             ntstdio_putc(handle, d);
208         }
209         do {
210             ntstdio_putc(handle, s[--i]);
211         } while(i);
212         while (j++ < width) {
213             ntstdio_putc(handle, ' ');
214         }
215     }
216 }
217
218 void ntstdio_init(ntstdio_t *handle, unsigned int option, NTSTDIO_XI xi, NTSTDIO_XO xo)
219 {
220     handle->xi = xi;
221     handle->xo = xo;
222     handle->outptr = 0;
223     handle->option = option;
224 }
225
226 void ntstdio_putc(ntstdio_t *handle, char c)
227 {
228     if ((handle->option & NTSTDIO_OPTION_CR_CRLF) && (c == '\n')) {
229         ntstdio_putc(handle, '\r');
230     }
231
232     if (handle->outptr) {
233         *(handle->outptr)++ = (unsigned char)c;
234         return;
235     }
236
237     if (handle->xo) {
238         handle->xo((unsigned char)c);
239     }
240 }
241
242 void ntstdio_puts(ntstdio_t *handle, const char *str)
243 {
244     while (*str) {
245         ntstdio_putc(handle, *str++);
246     }
247 }
248
249 void ntstdio_fputs(ntstdio_t *handle, NTSTDIO_XO xo, const char *str)
250 {
251     void (*pf)(unsigned char);
252
253     /* Save current output device */
254     pf = handle->xo;
255     /* Switch output to specified device */
256     handle->xo = xo;
257
258     while (*str) {
259         ntstdio_putc(handle, *str++);
260     }
261
262     /* Restore output device */
263     handle->xo = pf;
264 }
265
266 void ntstdio_printf(ntstdio_t *handle, const char *fmt, ...)
267 {
268     va_list arp;
269     va_start(arp, fmt);
270     xvprintf(handle, fmt, arp);
271     va_end(arp);
272 }
273
274 void ntstdio_sprintf(ntstdio_t *handle, char *buf, const char *fmt, ...)
275 {
276     va_list arp;
277     /* Switch destination for memory */
278     handle->outptr = buf;
279     va_start(arp, fmt);
280     xvprintf(handle, fmt, arp);
281     va_end(arp);
282
283     /* Terminate output string with a \0 */
284     *(handle->outptr) = 0;
285     /* Switch destination for device */
286     handle->outptr = 0;
287 }
288
289 void ntstdio_fprintf(ntstdio_t *handle, NTSTDIO_XO xo, const char *fmt, ...)
290 {
291     va_list arp;
292     void (*pf)(unsigned char);
293
294     /* Save current output device */
295     pf = handle->xo;
296     /* Switch output to specified device */
297     handle->xo = xo;
298
299     va_start(arp, fmt);
300     xvprintf(handle, fmt, arp);
301     va_end(arp);
302
303     /* Restore output device */
304     handle->xo = pf;
305 }
306
307 /* 0:End of stream, 1:A line arrived */
308 int ntstdio_gets(ntstdio_t *handle, char *buf, int len)
309 {
310     int c, i;
311
312     if (!handle->xi) {
313         /* No input function specified */
314         return 0;
315     }
316
317     i = 0;
318     for (;;) {
319         /* Get a char from the incoming stream */
320         c = handle->xi();
321         if (!c) {
322             /* End of stream */
323             return 0;
324         }
325         if (c == '\r') {
326             /* End of line */
327             break;
328         }
329         if ((c == '\b') && i) {
330             /* Back space */
331             i--;
332             if (handle->option & NTSTDIO_OPTION_LINE_ECHO) {
333                 ntstdio_putc(handle, c);
334             }
335             continue;
336         }
337         if ((c >= ' ') && (i < len - 1)) {
338             /* Visible chars */
339             buf[i++] = c;
340             if (handle->option & NTSTDIO_OPTION_LINE_ECHO) {
341                 ntstdio_putc(handle, c);
342             }
343         }
344     }
345     buf[i] = 0;
346     /* Terminate with a \0 */
347     if (handle->option & NTSTDIO_OPTION_LINE_ECHO) {
348         ntstdio_putc(handle, '\n');
349     }
350     return 1;
351 }
352
353 /* 0:End of stream, 1:A line arrived */
354 int ntstdio_fgets(ntstdio_t *handle, NTSTDIO_XI xi, char *buf, int len)
355 {
356     unsigned char (*pf)(void);
357     int n;
358
359     /* Save current input device */
360     pf = handle->xi;
361     /* Switch input to specified device */
362     handle->xi = xi;
363     /* Get a line */
364     n = ntstdio_gets(handle, buf, len);
365     /* Restore input device */
366     handle->xi = pf;
367
368     return n;
369 }
370