1 /* 2 * minimal printf for Human68k DOS 3 * 4 * written by Yasha (ITOH Yasufumi) 5 * public domain 6 * 7 * $NetBSD: xprintf.c,v 1.4 2009/03/14 21:04:17 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(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