kern

view src/klibc/stdio.c @ 73:b4b7198986a6

fixed a potential null dereference when deleting a bug in the redblack tree
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 15 Oct 2011 08:06:10 +0300
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 }