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