xref: /netbsd/sys/arch/x68k/stand/common/xprintf.c (revision bf9ec67e)
1 /*
2  *	minimal printf for Human68k DOS
3  *
4  *	written by Yasha (ITOH Yasufumi)
5  *	public domain
6  *
7  *	$NetBSD: xprintf.c,v 1.1 1998/09/01 19:51:57 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 __P((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