xref: /netbsd-src/sys/arch/x68k/stand/common/xprintf.c (revision ed461fc193a34ff07bc68b0c28567cb8cfe199e5)
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