kern

view src/klibc/stdio.c @ 80:4db99a52863e

fixed the "endianess" of the text messages in the ATA identify info block. this is the first time I've seen wrong byteorder in ascii text, the ATA committee should be commended.
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 06 Dec 2011 13:35:39 +0200
parents 86781ef20689
children
line source
1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
5 static void bwrite(char *buf, size_t buf_sz, char *str, int sz);
6 static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap);
8 /* putchar is defined in term.c */
10 int puts(const char *s)
11 {
12 while(*s) {
13 putchar(*s++);
14 }
15 putchar('\n');
16 return 0;
17 }
19 /* -- printf and friends -- */
21 static char *convc = "dioxXucsfeEgGpn%";
23 #define IS_CONV(c) strchr(convc, c)
25 int printf(const char *fmt, ...)
26 {
27 int res;
28 va_list ap;
30 va_start(ap, fmt);
31 res = intern_printf(0, 0, fmt, ap);
32 va_end(ap);
33 return res;
34 }
36 int vprintf(const char *fmt, va_list ap)
37 {
38 return intern_printf(0, 0, fmt, ap);
39 }
41 int sprintf(char *buf, const char *fmt, ...)
42 {
43 int res;
44 va_list ap;
46 va_start(ap, fmt);
47 res = intern_printf(buf, 0, fmt, ap);
48 va_end(ap);
49 return res;
50 }
52 int vsprintf(char *buf, const char *fmt, va_list ap)
53 {
54 return intern_printf(buf, 0, fmt, ap);
55 }
57 int snprintf(char *buf, size_t sz, const char *fmt, ...)
58 {
59 int res;
60 va_list ap;
62 va_start(ap, fmt);
63 res = intern_printf(buf, sz, fmt, ap);
64 va_end(ap);
65 return res;
66 }
68 int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap)
69 {
70 return intern_printf(buf, sz, fmt, ap);
71 }
74 /* intern_printf provides all the functionality needed by all the printf
75 * variants.
76 * - buf: optional buffer onto which the formatted results are written. If null
77 * then the output goes to the terminal through putchar calls. This is used
78 * by the (v)sprintf variants which write to an array of char.
79 * - sz: optional maximum size of the output, 0 means unlimited. This is used
80 * by the (v)snprintf variants to avoid buffer overflows.
81 * The rest are obvious, format string and variable argument list.
82 */
84 #define BUF(x) ((x) ? (x) + cnum : (x))
85 #define SZ(x) ((x) ? (x) - cnum : (x))
87 static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap)
88 {
89 char conv_buf[32];
90 char *str;
91 int i, slen;
92 const char *fstart = 0;
94 /* state */
95 int cnum = 0;
96 int base = 10;
97 int alt = 0;
98 int fwidth = 0;
99 int padc = ' ';
100 int sign = 0;
101 int left_align = 0; /* not implemented yet */
102 int hex_caps = 0;
103 int unsig = 0;
105 while(*fmt) {
106 if(*fmt == '%') {
107 fstart = fmt++;
108 continue;
109 }
111 if(fstart) {
112 if(IS_CONV(*fmt)) {
113 switch(*fmt) {
114 case 'X':
115 hex_caps = 1;
117 case 'x':
118 case 'p':
119 base = 16;
121 if(alt) {
122 bwrite(BUF(buf), SZ(sz), "0x", 2);
123 }
125 case 'u':
126 unsig = 1;
128 if(0) {
129 case 'o':
130 base = 8;
132 if(alt) {
133 bwrite(BUF(buf), SZ(sz), "0", 1);
134 }
135 }
137 case 'd':
138 case 'i':
139 if(unsig) {
140 utoa(va_arg(ap, unsigned int), conv_buf, base);
141 } else {
142 itoa(va_arg(ap, int), conv_buf, base);
143 }
144 if(hex_caps) {
145 for(i=0; conv_buf[i]; i++) {
146 conv_buf[i] = toupper(conv_buf[i]);
147 }
148 }
150 slen = strlen(conv_buf);
151 for(i=slen; i<fwidth; i++) {
152 bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
153 cnum++;
154 }
156 bwrite(BUF(buf), SZ(sz), conv_buf, strlen(conv_buf));
157 cnum += slen;
158 break;
160 case 'c':
161 {
162 char c = va_arg(ap, int);
163 bwrite(BUF(buf), SZ(sz), &c, 1);
164 cnum++;
165 }
166 break;
168 case 's':
169 str = va_arg(ap, char*);
170 slen = strlen(str);
172 for(i=slen; i<fwidth; i++) {
173 bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
174 cnum++;
175 }
176 bwrite(BUF(buf), SZ(sz), str, slen);
177 cnum += slen;
178 break;
180 case 'n':
181 *va_arg(ap, int*) = cnum;
182 break;
184 default:
185 break;
186 }
188 /* restore default conversion state */
189 base = 10;
190 alt = 0;
191 fwidth = 0;
192 padc = ' ';
193 hex_caps = 0;
195 fstart = 0;
196 fmt++;
197 } else {
198 switch(*fmt) {
199 case '#':
200 alt = 1;
201 break;
203 case '+':
204 sign = 1;
205 break;
207 case '-':
208 left_align = 1;
209 break;
211 case 'l':
212 case 'L':
213 break;
215 case '0':
216 padc = '0';
217 break;
219 default:
220 if(isdigit(*fmt)) {
221 const char *fw = fmt;
222 while(*fmt && isdigit(*fmt)) fmt++;
224 fwidth = atoi(fw);
225 continue;
226 }
227 }
228 fmt++;
229 }
230 } else {
231 bwrite(BUF(buf), SZ(sz), (char*)fmt++, 1);
232 cnum++;
233 }
234 }
236 return 0;
237 }
240 /* bwrite is called by intern_printf to transparently handle writing into a
241 * buffer (if buf is non-null) or to the terminal (if buf is null).
242 */
243 static void bwrite(char *buf, size_t buf_sz, char *str, int sz)
244 {
245 if(buf) {
246 if(buf_sz && buf_sz <= sz) sz = buf_sz - 1;
247 memcpy(buf, str, sz);
249 buf[sz] = 0;
250 } else {
251 int i;
252 for(i=0; i<sz; i++) {
253 putchar(*str++);
254 }
255 }
256 }