1 /*
2 * minimal printf for Human68k DOS
3 *
4 * written by ITOH Yasufumi
5 * public domain
6 *
7 * $NetBSD: xprintf.c,v 1.5 2011/02/21 02:31:58 itohy 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 *
numstr(char * buf,long val,int base,int sign)62 numstr(char *buf, long val, int base, int sign)
63 {
64 unsigned long v;
65 char rev[32];
66 char *r = rev, *b = buf;
67
68 /* negative? */
69 if (sign && val < 0) {
70 v = -val;
71 *b++ = '-';
72 } else {
73 v = val;
74 }
75
76 /* inverse order */
77 do {
78 *r++ = "0123456789abcdef"[v % base];
79 v /= base;
80 } while (v);
81
82 /* reverse string */
83 while (r > rev)
84 *b++ = *--r;
85
86 *b = '\0';
87 return buf;
88 }
89
90 /*
91 * supported format: %x, %p, %s, %c, %d, %u, %o
92 * \n is converted to \r\n
93 *
94 * XXX argument/parameter types are not strictly handled
95 */
96 size_t
xvsnprintf(char * buf,size_t len,const char * fmt,va_list ap)97 xvsnprintf(char *buf, size_t len, const char *fmt, va_list ap)
98 {
99 char *b = buf;
100 const char *s;
101 char numbuf[32];
102
103 while (*fmt && len > 1) {
104 if (*fmt != '%') {
105 #ifdef SJIS
106 if (IS_SJIS1(*fmt) && IS_SJIS2(fmt[1])) {
107 if (len <= 2)
108 break; /* not enough space */
109 *b++ = *fmt++;
110 len--;
111 }
112 #endif
113 if (*fmt == '\n' && (b == buf || b[-1] != '\r')) {
114 if (len <= 2)
115 break;
116 *b++ = '\r';
117 len--;
118 }
119 *b++ = *fmt++;
120 len--;
121 continue;
122 }
123
124 /* %? */
125 fmt++;
126 switch (*fmt++) {
127 case '%': /* "%%" -> literal % */
128 *b++ = '%';
129 len--;
130 break;
131
132 case 'd':
133 s = numstr(numbuf, va_arg(ap, long), 10, 1);
134 copy_string:
135 for ( ; *s && len > 1; len--)
136 *b++ = *s++;
137 break;
138
139 case 'u':
140 s = numstr(numbuf, va_arg(ap, long), 10, 0);
141 goto copy_string;
142
143 case 'p':
144 *b++ = '0';
145 len--;
146 if (len > 1) {
147 *b++ = 'x';
148 len--;
149 }
150 /* FALLTHROUGH */
151 case 'x':
152 s = numstr(numbuf, va_arg(ap, long), 16, 0);
153 goto copy_string;
154
155 case 'o':
156 s = numstr(numbuf, va_arg(ap, long), 8, 0);
157 goto copy_string;
158
159 case 's':
160 s = va_arg(ap, char *);
161 while (*s && len > 1) {
162 #ifdef SJIS
163 if (IS_SJIS1(*s) && IS_SJIS2(s[1])) {
164 if (len <= 2)
165 goto break_loop;
166 *b++ = *s++;
167 len--;
168 }
169 #endif
170 if (*s == '\n' && (b == buf || b[-1] != '\r')) {
171 if (len <= 2)
172 goto break_loop;
173 *b++ = '\r';
174 len--;
175 }
176 *b++ = *s++;
177 len--;
178 }
179 break;
180
181 case 'c':
182 *b++ = va_arg(ap, int);
183 len--;
184 break;
185 }
186 }
187 break_loop:
188
189 *b = '\0';
190 return (char *)b - buf;
191 }
192
193 #ifdef __STDC__
194 #define VA_START(a, v) va_start(a, v)
195 #else
196 #define VA_START(a, v) va_start(a)
197 #endif
198
199 #ifdef __STDC__
200 size_t
xsnprintf(char * buf,size_t len,const char * fmt,...)201 xsnprintf(char *buf, size_t len, const char *fmt, ...)
202 #else
203 size_t
204 xsnprintf(buf, len, fmt, va_alist)
205 char *buf;
206 size_t len;
207 const char *fmt;
208 va_dcl
209 #endif
210 {
211 va_list ap;
212 size_t ret;
213
214 VA_START(ap, fmt);
215 ret = xvsnprintf(buf, len, fmt, ap);
216 va_end(ap);
217
218 return ret;
219 }
220
221 size_t
xvfdprintf(int fd,const char * fmt,va_list ap)222 xvfdprintf(int fd, const char *fmt, va_list ap)
223 {
224 char buf[PRINTF_BUFSZ];
225 size_t ret;
226
227 ret = xvsnprintf(buf, sizeof buf, fmt, ap);
228 if (ret)
229 ret = DOS_WRITE(fd, buf, ret);
230
231 return ret;
232 }
233
234 #ifdef __STDC__
235 size_t
xprintf(const char * fmt,...)236 xprintf(const char *fmt, ...)
237 #else
238 size_t
239 xprintf(fmt, va_alist)
240 const char *fmt;
241 va_dcl
242 #endif
243 {
244 va_list ap;
245 size_t ret;
246
247 VA_START(ap, fmt);
248 ret = xvfdprintf(1, fmt, ap);
249 va_end(ap);
250
251 return ret;
252 }
253
254 #ifdef __STDC__
255 size_t
xerrprintf(const char * fmt,...)256 xerrprintf(const char *fmt, ...)
257 #else
258 size_t
259 xerrprintf(fmt, va_alist)
260 const char *fmt;
261 va_dcl
262 #endif
263 {
264 va_list ap;
265 size_t ret;
266
267 VA_START(ap, fmt);
268 ret = xvfdprintf(2, fmt, ap);
269 va_end(ap);
270
271 return ret;
272 }
273
274 __dead void
275 #ifdef __STDC__
xerr(int eval,const char * fmt,...)276 xerr(int eval, const char *fmt, ...)
277 #else
278 xerr(eval, fmt, va_alist)
279 int eval;
280 const char *fmt;
281 va_dcl
282 #endif
283 {
284 int e = dos_errno;
285 va_list ap;
286
287 xerrprintf("%s: ", __progname);
288 if (fmt) {
289 VA_START(ap, fmt);
290 xvfdprintf(2, fmt, ap);
291 va_end(ap);
292 xerrprintf(": ");
293 }
294 xerrprintf("%s\n", dos_strerror(e));
295 DOS_EXIT2(eval);
296 }
297
298 __dead void
299 #ifdef __STDC__
xerrx(int eval,const char * fmt,...)300 xerrx(int eval, const char *fmt, ...)
301 #else
302 xerrx(eval, fmt, va_alist)
303 int eval;
304 const char *fmt;
305 va_dcl
306 #endif
307 {
308 va_list ap;
309
310 xerrprintf("%s: ", __progname);
311 if (fmt) {
312 VA_START(ap, fmt);
313 xvfdprintf(2, fmt, ap);
314 va_end(ap);
315 }
316 xerrprintf("\n");
317 DOS_EXIT2(eval);
318 }
319
320 void
321 #ifdef __STDC__
xwarn(const char * fmt,...)322 xwarn(const char *fmt, ...)
323 #else
324 xwarn(fmt, va_alist)
325 const char *fmt;
326 va_dcl
327 #endif
328 {
329 int e = dos_errno;
330 va_list ap;
331
332 xerrprintf("%s: ", __progname);
333 if (fmt) {
334 VA_START(ap, fmt);
335 xvfdprintf(2, fmt, ap);
336 va_end(ap);
337 xerrprintf(": ");
338 }
339 xerrprintf("%s\n", dos_strerror(e));
340 }
341
342 void
343 #ifdef __STDC__
xwarnx(const char * fmt,...)344 xwarnx(const char *fmt, ...)
345 #else
346 xwarnx(fmt, va_alist)
347 const char *fmt;
348 va_dcl
349 #endif
350 {
351 va_list ap;
352
353 xerrprintf("%s: ", __progname);
354 if (fmt) {
355 VA_START(ap, fmt);
356 xvfdprintf(2, fmt, ap);
357 va_end(ap);
358 }
359 xerrprintf("\n");
360 }
361