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