xprintf.c revision 1.2 1 /*
2 * minimal printf for Human68k DOS
3 *
4 * written by Yasha (ITOH Yasufumi)
5 * public domain
6 *
7 * $NetBSD: xprintf.c,v 1.2 2009/03/14 14:46:07 dsl Exp $
8 */
9
10 #include <sys/types.h>
11 #ifdef __STDC__
12 # include <stdarg.h>
13 #else
14 # include <varargs.h>
15 #endif
16
17 #include <dos.h>
18 #include <dos_errno.h>
19
20 #include "xprintf.h"
21
22 /*
23 * From ISO/IEC 9899:1990
24 * 7.9.6.1 The fprintf function
25 * ...
26 * Environment limit
27 * The minimum value for the maximum number of characters
28 * produced by any single conversion shall be 509.
29 *
30 * so the following value shall not be smaller than 510
31 * if you want to conform ANSI C (it is only a guideline
32 * and maybe no sense on this code, of course :-).
33 */
34 #define PRINTF_BUFSZ 4096
35
36 /*
37 * Shift-JIS kanji support
38 * (No special handling needed for EUC)
39 */
40 #define SJIS
41
42 #ifdef SJIS
43 #define UC(c) ((unsigned char) (c))
44 #define IS_SJIS1(c) ((UC(c) > 0x80 && UC(c) < 0xa0) || \
45 (UC(c) >= 0xe0 && UC(c) <= 0xfc))
46 #define IS_SJIS2(c) (UC(c) >= 0x40 && UC(c) <= 0xfc && UC(c) != 0x7f)
47 #endif
48
49 #if !defined(__STDC__) && !defined(const)
50 #define const
51 #endif
52
53 extern const char *const __progname;
54
55 static char * numstr(char *buf, long val, int base, int sign);
56
57 /*
58 * convert number to string
59 * buf must have enough space
60 */
61 static char *
62 numstr(buf, val, base, sign)
63 char *buf;
64 long val;
65 int base, sign;
66 {
67 unsigned long v;
68 char rev[32];
69 char *r = rev, *b = buf;
70
71 /* negative? */
72 if (sign && val < 0) {
73 v = -val;
74 *b++ = '-';
75 } else {
76 v = val;
77 }
78
79 /* inverse order */
80 do {
81 *r++ = "0123456789abcdef"[v % base];
82 v /= base;
83 } while (v);
84
85 /* reverse string */
86 while (r > rev)
87 *b++ = *--r;
88
89 *b = '\0';
90 return buf;
91 }
92
93 /*
94 * supported format: %x, %p, %s, %c, %d, %u, %o
95 * \n is converted to \r\n
96 *
97 * XXX argument/parameter types are not strictly handled
98 */
99 size_t
100 xvsnprintf(buf, len, fmt, ap)
101 char *buf;
102 size_t len;
103 const char *fmt;
104 va_list ap;
105 {
106 char *b = buf;
107 const char *s;
108 char numbuf[32];
109
110 while (*fmt && len > 1) {
111 if (*fmt != '%') {
112 #ifdef SJIS
113 if (IS_SJIS1(*fmt) && IS_SJIS2(fmt[1])) {
114 if (len <= 2)
115 break; /* not enough space */
116 *b++ = *fmt++;
117 len--;
118 }
119 #endif
120 if (*fmt == '\n' && (b == buf || b[-1] != '\r')) {
121 if (len <= 2)
122 break;
123 *b++ = '\r';
124 len--;
125 }
126 *b++ = *fmt++;
127 len--;
128 continue;
129 }
130
131 /* %? */
132 fmt++;
133 switch (*fmt++) {
134 case '%': /* "%%" -> literal % */
135 *b++ = '%';
136 len--;
137 break;
138
139 case 'd':
140 s = numstr(numbuf, va_arg(ap, long), 10, 1);
141 copy_string:
142 for ( ; *s && len > 1; len--)
143 *b++ = *s++;
144 break;
145
146 case 'u':
147 s = numstr(numbuf, va_arg(ap, long), 10, 0);
148 goto copy_string;
149
150 case 'p':
151 *b++ = '0';
152 len--;
153 if (len > 1) {
154 *b++ = 'x';
155 len--;
156 }
157 /* FALLTHROUGH */
158 case 'x':
159 s = numstr(numbuf, va_arg(ap, long), 16, 0);
160 goto copy_string;
161
162 case 'o':
163 s = numstr(numbuf, va_arg(ap, long), 8, 0);
164 goto copy_string;
165
166 case 's':
167 s = va_arg(ap, char *);
168 while (*s && len > 1) {
169 #ifdef SJIS
170 if (IS_SJIS1(*s) && IS_SJIS2(s[1])) {
171 if (len <= 2)
172 goto break_loop;
173 *b++ = *s++;
174 len--;
175 }
176 #endif
177 if (*s == '\n' && (b == buf || b[-1] != '\r')) {
178 if (len <= 2)
179 goto break_loop;
180 *b++ = '\r';
181 len--;
182 }
183 *b++ = *s++;
184 len--;
185 }
186 break;
187
188 case 'c':
189 *b++ = va_arg(ap, int);
190 len--;
191 break;
192 }
193 }
194 break_loop:
195
196 *b = '\0';
197 return (char *)b - buf;
198 }
199
200 #ifdef __STDC__
201 #define VA_START(a, v) va_start(a, v)
202 #else
203 #define VA_START(a, v) va_start(a)
204 #endif
205
206 #ifdef __STDC__
207 size_t
208 xsnprintf(char *buf, size_t len, const char *fmt, ...)
209 #else
210 size_t
211 xsnprintf(buf, len, fmt, va_alist)
212 char *buf;
213 size_t len;
214 const char *fmt;
215 va_dcl
216 #endif
217 {
218 va_list ap;
219 size_t ret;
220
221 VA_START(ap, fmt);
222 ret = xvsnprintf(buf, len, fmt, ap);
223 va_end(ap);
224
225 return ret;
226 }
227
228 size_t
229 xvfdprintf(fd, fmt, ap)
230 int fd;
231 const char *fmt;
232 va_list ap;
233 {
234 char buf[PRINTF_BUFSZ];
235 size_t ret;
236
237 ret = xvsnprintf(buf, sizeof buf, fmt, ap);
238 if (ret)
239 ret = DOS_WRITE(fd, buf, ret);
240
241 return ret;
242 }
243
244 #ifdef __STDC__
245 size_t
246 xprintf(const char *fmt, ...)
247 #else
248 size_t
249 xprintf(fmt, va_alist)
250 const char *fmt;
251 va_dcl
252 #endif
253 {
254 va_list ap;
255 size_t ret;
256
257 VA_START(ap, fmt);
258 ret = xvfdprintf(1, fmt, ap);
259 va_end(ap);
260
261 return ret;
262 }
263
264 #ifdef __STDC__
265 size_t
266 xerrprintf(const char *fmt, ...)
267 #else
268 size_t
269 xerrprintf(fmt, va_alist)
270 const char *fmt;
271 va_dcl
272 #endif
273 {
274 va_list ap;
275 size_t ret;
276
277 VA_START(ap, fmt);
278 ret = xvfdprintf(2, fmt, ap);
279 va_end(ap);
280
281 return ret;
282 }
283
284 __dead void
285 #ifdef __STDC__
286 xerr(int eval, const char *fmt, ...)
287 #else
288 xerr(eval, fmt, va_alist)
289 int eval;
290 const char *fmt;
291 va_dcl
292 #endif
293 {
294 int e = dos_errno;
295 va_list ap;
296
297 xerrprintf("%s: ", __progname);
298 if (fmt) {
299 VA_START(ap, fmt);
300 xvfdprintf(2, fmt, ap);
301 va_end(ap);
302 xerrprintf(": ");
303 }
304 xerrprintf("%s\n", dos_strerror(e));
305 DOS_EXIT2(eval);
306 }
307
308 __dead void
309 #ifdef __STDC__
310 xerrx(int eval, const char *fmt, ...)
311 #else
312 xerrx(eval, fmt, va_alist)
313 int eval;
314 const char *fmt;
315 va_dcl
316 #endif
317 {
318 va_list ap;
319
320 xerrprintf("%s: ", __progname);
321 if (fmt) {
322 VA_START(ap, fmt);
323 xvfdprintf(2, fmt, ap);
324 va_end(ap);
325 }
326 xerrprintf("\n");
327 DOS_EXIT2(eval);
328 }
329
330 void
331 #ifdef __STDC__
332 xwarn(const char *fmt, ...)
333 #else
334 xwarn(fmt, va_alist)
335 const char *fmt;
336 va_dcl
337 #endif
338 {
339 int e = dos_errno;
340 va_list ap;
341
342 xerrprintf("%s: ", __progname);
343 if (fmt) {
344 VA_START(ap, fmt);
345 xvfdprintf(2, fmt, ap);
346 va_end(ap);
347 xerrprintf(": ");
348 }
349 xerrprintf("%s\n", dos_strerror(e));
350 }
351
352 void
353 #ifdef __STDC__
354 xwarnx(const char *fmt, ...)
355 #else
356 xwarnx(fmt, va_alist)
357 const char *fmt;
358 va_dcl
359 #endif
360 {
361 va_list ap;
362
363 xerrprintf("%s: ", __progname);
364 if (fmt) {
365 VA_START(ap, fmt);
366 xvfdprintf(2, fmt, ap);
367 va_end(ap);
368 }
369 xerrprintf("\n");
370 }
371