Home | History | Annotate | Line # | Download | only in common
      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 *
     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
     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
    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
    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
    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
    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__
    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__
    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__
    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__
    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