NetBSD/sys/arch/x68k/stand/common/xprintf.c
1998-09-01 19:51:56 +00:00

371 lines
5.6 KiB
C

/*
* minimal printf for Human68k DOS
*
* written by Yasha (ITOH Yasufumi)
* public domain
*
* $NetBSD: xprintf.c,v 1.1 1998/09/01 19:51:57 itohy Exp $
*/
#include <sys/types.h>
#ifdef __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include <dos.h>
#include <dos_errno.h>
#include "xprintf.h"
/*
* From ISO/IEC 9899:1990
* 7.9.6.1 The fprintf function
* ...
* Environment limit
* The minimum value for the maximum number of characters
* produced by any single conversion shall be 509.
*
* so the following value shall not be smaller than 510
* if you want to conform ANSI C (it is only a guideline
* and maybe no sense on this code, of course :-).
*/
#define PRINTF_BUFSZ 4096
/*
* Shift-JIS kanji support
* (No special handling needed for EUC)
*/
#define SJIS
#ifdef SJIS
#define UC(c) ((unsigned char) (c))
#define IS_SJIS1(c) ((UC(c) > 0x80 && UC(c) < 0xa0) || \
(UC(c) >= 0xe0 && UC(c) <= 0xfc))
#define IS_SJIS2(c) (UC(c) >= 0x40 && UC(c) <= 0xfc && UC(c) != 0x7f)
#endif
#if !defined(__STDC__) && !defined(const)
#define const
#endif
extern const char *const __progname;
static char * numstr __P((char *buf, long val, int base, int sign));
/*
* convert number to string
* buf must have enough space
*/
static char *
numstr(buf, val, base, sign)
char *buf;
long val;
int base, sign;
{
unsigned long v;
char rev[32];
char *r = rev, *b = buf;
/* negative? */
if (sign && val < 0) {
v = -val;
*b++ = '-';
} else {
v = val;
}
/* inverse order */
do {
*r++ = "0123456789abcdef"[v % base];
v /= base;
} while (v);
/* reverse string */
while (r > rev)
*b++ = *--r;
*b = '\0';
return buf;
}
/*
* supported format: %x, %p, %s, %c, %d, %u, %o
* \n is converted to \r\n
*
* XXX argument/parameter types are not strictly handled
*/
size_t
xvsnprintf(buf, len, fmt, ap)
char *buf;
size_t len;
const char *fmt;
va_list ap;
{
char *b = buf;
const char *s;
char numbuf[32];
while (*fmt && len > 1) {
if (*fmt != '%') {
#ifdef SJIS
if (IS_SJIS1(*fmt) && IS_SJIS2(fmt[1])) {
if (len <= 2)
break; /* not enough space */
*b++ = *fmt++;
len--;
}
#endif
if (*fmt == '\n' && (b == buf || b[-1] != '\r')) {
if (len <= 2)
break;
*b++ = '\r';
len--;
}
*b++ = *fmt++;
len--;
continue;
}
/* %? */
fmt++;
switch (*fmt++) {
case '%': /* "%%" -> literal % */
*b++ = '%';
len--;
break;
case 'd':
s = numstr(numbuf, va_arg(ap, long), 10, 1);
copy_string:
for ( ; *s && len > 1; len--)
*b++ = *s++;
break;
case 'u':
s = numstr(numbuf, va_arg(ap, long), 10, 0);
goto copy_string;
case 'p':
*b++ = '0';
len--;
if (len > 1) {
*b++ = 'x';
len--;
}
/* FALLTHROUGH */
case 'x':
s = numstr(numbuf, va_arg(ap, long), 16, 0);
goto copy_string;
case 'o':
s = numstr(numbuf, va_arg(ap, long), 8, 0);
goto copy_string;
case 's':
s = va_arg(ap, char *);
while (*s && len > 1) {
#ifdef SJIS
if (IS_SJIS1(*s) && IS_SJIS2(s[1])) {
if (len <= 2)
goto break_loop;
*b++ = *s++;
len--;
}
#endif
if (*s == '\n' && (b == buf || b[-1] != '\r')) {
if (len <= 2)
goto break_loop;
*b++ = '\r';
len--;
}
*b++ = *s++;
len--;
}
break;
case 'c':
*b++ = va_arg(ap, int);
len--;
break;
}
}
break_loop:
*b = '\0';
return (char *)b - buf;
}
#ifdef __STDC__
#define VA_START(a, v) va_start(a, v)
#else
#define VA_START(a, v) va_start(a)
#endif
#ifdef __STDC__
size_t
xsnprintf(char *buf, size_t len, const char *fmt, ...)
#else
size_t
xsnprintf(buf, len, fmt, va_alist)
char *buf;
size_t len;
const char *fmt;
va_dcl
#endif
{
va_list ap;
size_t ret;
VA_START(ap, fmt);
ret = xvsnprintf(buf, len, fmt, ap);
va_end(ap);
return ret;
}
size_t
xvfdprintf(fd, fmt, ap)
int fd;
const char *fmt;
va_list ap;
{
char buf[PRINTF_BUFSZ];
size_t ret;
ret = xvsnprintf(buf, sizeof buf, fmt, ap);
if (ret)
ret = DOS_WRITE(fd, buf, ret);
return ret;
}
#ifdef __STDC__
size_t
xprintf(const char *fmt, ...)
#else
size_t
xprintf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list ap;
size_t ret;
VA_START(ap, fmt);
ret = xvfdprintf(1, fmt, ap);
va_end(ap);
return ret;
}
#ifdef __STDC__
size_t
xerrprintf(const char *fmt, ...)
#else
size_t
xerrprintf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list ap;
size_t ret;
VA_START(ap, fmt);
ret = xvfdprintf(2, fmt, ap);
va_end(ap);
return ret;
}
__dead void
#ifdef __STDC__
xerr(int eval, const char *fmt, ...)
#else
xerr(eval, fmt, va_alist)
int eval;
const char *fmt;
va_dcl
#endif
{
int e = dos_errno;
va_list ap;
xerrprintf("%s: ", __progname);
if (fmt) {
VA_START(ap, fmt);
xvfdprintf(2, fmt, ap);
va_end(ap);
xerrprintf(": ");
}
xerrprintf("%s\n", dos_strerror(e));
DOS_EXIT2(eval);
}
__dead void
#ifdef __STDC__
xerrx(int eval, const char *fmt, ...)
#else
xerrx(eval, fmt, va_alist)
int eval;
const char *fmt;
va_dcl
#endif
{
va_list ap;
xerrprintf("%s: ", __progname);
if (fmt) {
VA_START(ap, fmt);
xvfdprintf(2, fmt, ap);
va_end(ap);
}
xerrprintf("\n");
DOS_EXIT2(eval);
}
void
#ifdef __STDC__
xwarn(const char *fmt, ...)
#else
xwarn(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
int e = dos_errno;
va_list ap;
xerrprintf("%s: ", __progname);
if (fmt) {
VA_START(ap, fmt);
xvfdprintf(2, fmt, ap);
va_end(ap);
xerrprintf(": ");
}
xerrprintf("%s\n", dos_strerror(e));
}
void
#ifdef __STDC__
xwarnx(const char *fmt, ...)
#else
xwarnx(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list ap;
xerrprintf("%s: ", __progname);
if (fmt) {
VA_START(ap, fmt);
xvfdprintf(2, fmt, ap);
va_end(ap);
}
xerrprintf("\n");
}