OSDN Git Service

\e$B%A%1%C%H\e(B #30714 xprintf\e$B%b%8%e!<%k$N:o=|$H\e(Bntstdio\e$B%b%8%e!<%k$NDI2C\e(B
[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 *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 *handle, NTSTDIO_XO xo, NTSTDIO_XI xi)
219 {
220     handle->xo = xo;
221     handle->xi = xi;
222     handle->outptr = 0;
223 }
224
225 void ntstdio_putc(NTSTDIO *handle, char c)
226 {
227     if ((NTSTDIO_CR_CRLF) && (c == '\n')) {
228         ntstdio_putc(handle, '\r');
229     }
230
231     if (handle->outptr) {
232         *(handle->outptr)++ = (unsigned char)c;
233         return;
234     }
235
236     if (handle->xo) {
237         handle->xo((unsigned char)c);
238     }
239 }
240
241 void ntstdio_puts(NTSTDIO *handle, const char *str)
242 {
243     while (*str) {
244         ntstdio_putc(handle, *str++);
245     }
246 }
247
248 void ntstdio_fputs(NTSTDIO *handle, NTSTDIO_XO xo, const char *str)
249 {
250     void (*pf)(unsigned char);
251
252     /* Save current output device */
253     pf = handle->xo;
254     /* Switch output to specified device */
255     handle->xo = xo;
256
257     while (*str) {
258         ntstdio_putc(handle, *str++);
259     }
260
261     /* Restore output device */
262     handle->xo = pf;
263 }
264
265 void ntstdio_printf(NTSTDIO *handle, const char *fmt, ...)
266 {
267     va_list arp;
268     va_start(arp, fmt);
269     xvprintf(handle, fmt, arp);
270     va_end(arp);
271 }
272
273 void ntstdio_sprintf(NTSTDIO *handle, char *buf, const char *fmt, ...)
274 {
275     va_list arp;
276     /* Switch destination for memory */
277     handle->outptr = buf;
278     va_start(arp, fmt);
279     xvprintf(handle, fmt, arp);
280     va_end(arp);
281
282     /* Terminate output string with a \0 */
283     *(handle->outptr) = 0;
284     /* Switch destination for device */
285     handle->outptr = 0;
286 }
287
288 void ntstdio_fprintf(NTSTDIO *handle, NTSTDIO_XO xo, const char *fmt, ...)
289 {
290     va_list arp;
291     void (*pf)(unsigned char);
292
293     /* Save current output device */
294     pf = handle->xo;
295     /* Switch output to specified device */
296     handle->xo = xo;
297
298     va_start(arp, fmt);
299     xvprintf(handle, fmt, arp);
300     va_end(arp);
301
302     /* Restore output device */
303     handle->xo = pf;
304 }
305
306 /* 0:End of stream, 1:A line arrived */
307 int ntstdio_gets(NTSTDIO *handle, char *buf, int len)
308 {
309     int c, i;
310
311     if (!handle->xi) {
312         /* No input function specified */
313         return 0;
314     }
315
316     i = 0;
317     for (;;) {
318         /* Get a char from the incoming stream */
319         c = handle->xi();
320         if (!c) {
321             /* End of stream */
322             return 0;
323         }
324         if (c == '\r') {
325             /* End of line */
326             break;
327         }
328         if ((c == '\b') && i) {
329             /* Back space */
330             i--;
331             if (NTSTDIO_LINE_ECHO) {
332                 ntstdio_putc(handle, c);
333             }
334             continue;
335         }
336         if ((c >= ' ') && (i < len - 1)) {
337             /* Visible chars */
338             buf[i++] = c;
339             if (NTSTDIO_LINE_ECHO) {
340                 ntstdio_putc(handle, c);
341             }
342         }
343     }
344     buf[i] = 0;
345     /* Terminate with a \0 */
346     if (NTSTDIO_LINE_ECHO) {
347         ntstdio_putc(handle, '\n');
348     }
349     return 1;
350 }
351
352 /* 0:End of stream, 1:A line arrived */
353 int ntstdio_fgets(NTSTDIO *handle, NTSTDIO_XI xi, char *buf, int len)
354 {
355     unsigned char (*pf)(void);
356     int n;
357
358     /* Save current input device */
359     pf = handle->xi;
360     /* Switch input to specified device */
361     handle->xi = xi;
362     /* Get a line */
363     n = ntstdio_gets(handle, buf, len);
364     /* Restore input device */
365     handle->xi = pf;
366
367     return n;
368 }
369