~kris/9p

9hist

42f34f5aa9f9b01101cde6f4f48865d0e832b15f — David du Colombier 33 years ago 26796ed
Plan 9 from Bell Labs 1992-10-24
3 files changed, 472 insertions(+), 189 deletions(-)

M port/devcons.c
M port/lib.h
M port/print.c
M port/devcons.c => port/devcons.c +2 -2
@@ 383,9 383,9 @@ int
readnum(ulong off, char *buf, ulong n, ulong val, int size)
{
	char tmp[64];
	Op op = (Op){ tmp, tmp+sizeof(tmp), &val, size-1, 0, FUNSIGN|FLONG };
	Fconv fconv = (Fconv){ tmp, tmp+sizeof(tmp), size-1, 0, 0, 'd' };

	numbconv(&op, 10);
	numbconv(&val, &fconv);
	tmp[size-1] = ' ';
	if(off >= size)
		return 0;

M port/lib.h => port/lib.h +17 -16
@@ 24,12 24,19 @@ extern	int	strncmp(char*, char*, long);
extern	long	strlen(char*);
extern	int	atoi(char*);

enum
{
	UTFmax		= 3,		/* maximum bytes per rune */
	Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
	Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
	Runeerror	= 0x80,		/* decoding error in UTF */
};

/*
 * rune routines
 */
extern	int	runetochar(char*, Rune*);
extern	int	chartorune(Rune*, char*);
extern	int	countrune(char*);
extern	char*	utfrune(char*, long);
extern	int	utflen(char*);



@@ 38,26 45,20 @@ extern	int	abs(int);
/*
 * print routines
 */

#define	FUNSIGN	4
#define	FSHORT	2
#define	FLONG	1

typedef struct Op	Op;
struct Op
typedef
struct
{
	char	*p;
	char	*ep;
	void	*argp;
	char*	out;		/* pointer to next output */
	char*	eout;		/* pointer to end */
	int	f1;
	int	f2;
	int	f3;
};
typedef void*	Fconv;	/* to allow fcall.h to compile */
extern	void	strconv(char*, Op*, int, int);
extern	int	numbconv(Op*, int);
	int	chr;
} Fconv;
extern	void	strconv(char*, Fconv*);
extern	int	numbconv(void*, Fconv*);
extern	char	*doprint(char*, char*, char*, void*);
extern	int	fmtinstall(char, int (*)(Op*));
extern	int	fmtinstall(int, int (*)(void*, Fconv*));
extern	int	sprint(char*, char*, ...);
extern	int	print(char*, ...);


M port/print.c => port/print.c +453 -171
@@ 1,292 1,574 @@
#include	"u.h"
#include	"../port/lib.h"

enum
{
	SIZE	= 1024,
	IDIGIT	= 30,
	MAXCONV	= 40,
	FDIGIT	= 30,
	FDEFLT	= 6,
	NONE	= -1000,
	MAXFMT	= 512,

	FPLUS	= (1<<0),
	FMINUS	= (1<<1),
	FSHARP	= (1<<2),
	FLONG	= (1<<3),
	FSHORT	= (1<<4),
	FUNSIGN	= (1<<5),
	FVLONG	= (1<<6),
};

#define	PTR	sizeof(char*)
#define	SHORT	sizeof(int)
#define	INT	sizeof(int)
#define	LONG	sizeof(long)
#define	IDIGIT	30
#define	MAXCON	30
#define	VLONG	sizeof(vlong)

static	int	convcount  = { 10 };
int	printcol;

#define	PUT(o, c)	if((o)->p < (o)->ep) *(o)->p++ = c
static	int	convcount;
static	char	fmtindex[MAXFMT];

static	int	noconv(Op*);
static	int	cconv(Op*);
static	int	dconv(Op*);
static	int	hconv(Op*);
static	int	lconv(Op*);
static	int	oconv(Op*);
static	int	sconv(Op*);
static	int	uconv(Op*);
static	int	xconv(Op*);
static	int	percent(Op*);
static	int	noconv(void*, Fconv*);
static	int	flags(void*, Fconv*);

static	int	cconv(void*, Fconv*);
static	int	sconv(void*, Fconv*);
static	int	percent(void*, Fconv*);

int	numbconv(void*, Fconv*);

static
int	(*fmtconv[MAXCON])(Op*) =
int	(*fmtconv[MAXCONV])(void*, Fconv*) =
{
	noconv,
	cconv, dconv, hconv, lconv,
	oconv, sconv, uconv, xconv,
	percent,
	noconv
};

static
char	fmtindex[128] =
void
initfmt(void)
{
	['c'] 1,
	['d'] 2,
	['h'] 3,
	['l'] 4,
	['o'] 5,
	['s'] 6,
	['u'] 7,
	['x'] 8,
	['%'] 9,
};
	int cc;

	cc = 0;
	fmtconv[cc] = noconv;
	cc++;

	fmtconv[cc] = flags;
	fmtindex['+'] = cc;
	fmtindex['-'] = cc;
	fmtindex['#'] = cc;
	fmtindex['h'] = cc;
	fmtindex['l'] = cc;
	fmtindex['u'] = cc;
	cc++;

	fmtconv[cc] = numbconv;
	fmtindex['d'] = cc;
	fmtindex['o'] = cc;
	fmtindex['x'] = cc;
	fmtindex['X'] = cc;
	cc++;

	fmtconv[cc] = cconv;
	fmtindex['c'] = cc;
	fmtindex['C'] = cc;
	cc++;

	fmtconv[cc] = sconv;
	fmtindex['s'] = cc;
	fmtindex['S'] = cc;
	cc++;

	fmtconv[cc] = percent;
	fmtindex['%'] = cc;
	cc++;

	convcount = cc;
}

int
fmtinstall(char c, int (*f)(Op*))
fmtinstall(int c, int (*f)(void*, Fconv*))
{

	c &= 0177;
	if(fmtindex[c] == 0) {
		if(convcount >= MAXCON)
			return 1;
		fmtindex[c] = convcount++;
	}
	fmtconv[fmtindex[c]] = f;
	if(convcount == 0)
		initfmt();
	if(c < 0 || c >= MAXFMT)
		return 1;
	if(convcount >= MAXCONV)
		return 1;
	fmtconv[convcount] = f;
	fmtindex[c] = convcount;
	convcount++;
	return 0;
}

char*
doprint(char *p, char *ep, char *fmt, void *argp)
doprint(char *s, char *es, char *fmt, void *argp)
{
	int sf1, c;
	Op o;
	int n, c;
	Rune rune;
	Fconv local;

	o.p = p;
	o.ep = ep;
	o.argp = argp;
	local.out = s;
	local.eout = es-4;		/* room for multi-byte character and 0 */

loop:
	c = *fmt++;
	if(c != '%') {
		if(c == 0) {
			if(o.p < o.ep)
				*o.p = 0;
			return o.p;
		}
		PUT(&o, c);
	c = *fmt & 0xff;
	if(c >= Runeself) {
		n = chartorune(&rune, fmt);
		fmt += n;
		c = rune;
	} else
		fmt++;
	switch(c) {
	case 0:
		*local.out = 0;
		return local.out;
	
	default:
		printcol++;
		goto common;

	case '\n':
		printcol = 0;
		goto common;

	case '\t':
		printcol = (printcol+8) & ~7;
		goto common;

	common:
		if(local.out < local.eout)
			if(c >= Runeself) {
				rune = c;
				n = runetochar(local.out, &rune);	/* BUG */
				local.out += n;
			} else
				*local.out++ = c;
		goto loop;

	case '%':
		break;
	}
	o.f1 = 0;
	o.f2 = -1;
	o.f3 = 0;
	c = *fmt++;
	sf1 = 0;
	if(c == '-') {
		sf1 = 1;
		c = *fmt++;
	local.f1 = NONE;
	local.f2 = NONE;
	local.f3 = 0;

	/*
	 * read one of the following
	 *	1. number, => f1, f2 in order.
	 *	2. '*' same as number (from args)
	 *	3. '.' ignored (separates numbers)
	 *	4. flag => f3
	 *	5. verb and terminate
	 */
l0:
	c = *fmt & 0xff;
	if(c >= Runeself) {
		n = chartorune(&rune, fmt);
		fmt += n;
		c = rune;
	} else
		fmt++;

l1:
	if(c == 0) {
		fmt--;
		goto loop;
	}
	while(c >= '0' && c <= '9') {
		o.f1 = o.f1*10 + c-'0';
		c = *fmt++;
	if(c == '.') {
		if(local.f1 == NONE)
			local.f1 = 0;
		local.f2 = 0;
		goto l0;
	}
	if(sf1)
		o.f1 = -o.f1;
	if(c != '.')
	if((c >= '1' && c <= '9') ||
	   (c == '0' && local.f1 != NONE)) {	/* '0' is a digit for f2 */
		n = 0;
		while(c >= '0' && c <= '9') {
			n = n*10 + c-'0';
			c = *fmt++;
		}
		if(local.f1 == NONE)
			local.f1 = n;
		else
			local.f2 = n;
		goto l1;
	c = *fmt++;
	while(c >= '0' && c <= '9') {
		if(o.f2 < 0)
			o.f2 = 0;
		o.f2 = o.f2*10 + c-'0';
		c = *fmt++;
	}
l1:
	if(c == 0)
		fmt--;
	c = (*fmtconv[fmtindex[c&0177]])(&o);
	if(c < 0) {
		o.f3 |= -c;
		c = *fmt++;
		goto l1;
	if(c == '*') {
		n = *(int*)argp;
		argp = (char*)argp + INT;
		if(local.f1 == NONE)
			local.f1 = n;
		else
			local.f2 = n;
		goto l0;
	}
	o.argp = (char*)o.argp + c;
	n = 0;
	if(c >= 0 && c < MAXFMT)
		n = fmtindex[c];
	local.chr = c;
	n = (*fmtconv[n])(argp, &local);
	if(n < 0) {
		local.f3 |= -n;
		goto l0;
	}
	argp = (char*)argp + n;
	goto loop;
}

int
numbconv(Op *op, int base)
numbconv(void *o, Fconv *fp)
{
	char b[IDIGIT];
	int i, f, n, r;
	long v;
	char s[IDIGIT];
	int i, f, n, r, b, ucase;
	short h;
	long v;
	vlong vl;

	SET(v);
	SET(vl);

	ucase = 0;
	b = fp->chr;
	switch(fp->chr) {
	case 'u':
		fp->f3 |= FUNSIGN;
	case 'd':
		b = 10;
		break;

	case 'o':
		b = 8;
		break;

	case 'X':
		ucase = 1;
	case 'x':
		b = 16;
		break;
	}

	f = 0;
	switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) {
	switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) {
	case FVLONG|FLONG:
		vl = *(vlong*)o;
		r = VLONG;
		break;

	case FLONG:
		v = *(long*)op->argp;
		v = *(long*)o;
		r = LONG;
		break;

	case FUNSIGN|FLONG:
		v = *(unsigned long*)op->argp;
		v = *(ulong*)o;
		r = LONG;
		break;

	case FSHORT:
		h = *(int*)op->argp;
		h = *(int*)o;
		v = h;
		r = SHORT;
		break;

	case FUNSIGN|FSHORT:
		h = *(int*)op->argp;
		v = (unsigned short)h;
		h = *(int*)o;
		v = (ushort)h;
		r = SHORT;
		break;

	default:
		v = *(int*)op->argp;
		v = *(int*)o;
		r = INT;
		break;

	case FUNSIGN:
		v = *(unsigned*)op->argp;
		v = *(unsigned*)o;
		r = INT;
		break;
	}
	if(!(op->f3 & FUNSIGN) && v < 0) {
	if(!(fp->f3 & FUNSIGN) && v < 0) {
		v = -v;
		f = 1;
	}
	b[IDIGIT-1] = 0;
	s[IDIGIT-1] = 0;
	for(i = IDIGIT-2;; i--) {
		n = (unsigned long)v % base;
		if(fp->f3 & FVLONG)
			n = vl % b;
		else
			n = (ulong)v % b;
		n += '0';
		if(n > '9')
		if(n > '9') {
			n += 'a' - ('9'+1);
		b[i] = n;
			if(ucase)
				n += 'A'-'a';
		}
		s[i] = n;
		if(i < 2)
			break;
		v = (unsigned long)v / base;
		if(op->f2 >= 0 && i >= IDIGIT-op->f2)
		if(fp->f3 & FVLONG)
			vl = vl / b;
		else
			v = (ulong)v / b;
		if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
			continue;
		if(fp->f3 & FVLONG)
			if(vl <= 0)
				break;
		if(v <= 0)
			break;
	}
sout:
	if(fp->f3 & FSHARP)
	if(s[i] != '0') {
		if(b == 8)
			s[--i] = '0';
		else
		if(b == 16) {
			if(ucase)
				s[--i] = 'X';
			else
				s[--i] = 'x';
			s[--i] = '0';
		}
	}
	if(f)
		b[--i] = '-';
	strconv(b+i, op, op->f1, -1);
		s[--i] = '-';
	fp->f2 = NONE;
	strconv(s+i, fp);
	return r;
}

void
strconv(char *o, Op *op, int f1, int f2)
Strconv(Rune *s, Fconv *fp)
{
	int n, c;
	char *p;

	n = strlen(o);
	if(f1 >= 0)
		while(n < f1) {
			PUT(op, ' ');
	int n, c, i;
	Rune rune;

	if(fp->f3 & FMINUS)
		fp->f1 = -fp->f1;
	n = 0;
	if(fp->f1 != NONE && fp->f1 >= 0) {
		for(; s[n]; n++)
			;
		while(n < fp->f1) {
			if(fp->out < fp->eout)
				*fp->out++ = ' ';
			printcol++;
			n++;
		}
	for(p=o; c = *p++;)
		if(f2 != 0) {
			PUT(op, c);
			f2--;
	}
	for(;;) {
		c = *s++;
		if(c == 0)
			break;
		n++;
		if(fp->f2 == NONE || fp->f2 > 0) {
			if(fp->out < fp->eout)
				if(c >= Runeself) {
					rune = c;
					i = runetochar(fp->out, &rune);
					fp->out += i;
				} else
					*fp->out++ = c;
			if(fp->f2 != NONE)
				fp->f2--;
			switch(c) {
			default:
				printcol++;
				break;
			case '\n':
				printcol = 0;
				break;
			case '\t':
				printcol = (printcol+8) & ~7;
				break;
			}
		}
	if(f1 < 0) {
		f1 = -f1;
		while(n < f1) {
			PUT(op, ' ');
	}
	if(fp->f1 != NONE && fp->f1 < 0) {
		fp->f1 = -fp->f1;
		while(n < fp->f1) {
			if(fp->out < fp->eout)
				*fp->out++ = ' ';
			printcol++;
			n++;
		}
	}
}

static	int
noconv(Op *op)
void
strconv(char *s, Fconv *fp)
{

	strconv("***", op, 0, -1);
	return 0;
	int n, c, i;
	Rune rune;

	if(fp->f3 & FMINUS)
		fp->f1 = -fp->f1;
	n = 0;
	if(fp->f1 != NONE && fp->f1 >= 0) {
		n = utflen(s);
		while(n < fp->f1) {
			if(fp->out < fp->eout)
				*fp->out++ = ' ';
			printcol++;
			n++;
		}
	}
	for(;;) {
		c = *s & 0xff;
		if(c >= Runeself) {
			i = chartorune(&rune, s);
			s += i;
			c = rune;
		} else
			s++;
		if(c == 0)
			break;
		n++;
		if(fp->f2 == NONE || fp->f2 > 0) {
			if(fp->out < fp->eout)
				if(c >= Runeself) {
					rune = c;
					i = runetochar(fp->out, &rune);
					fp->out += i;
				} else
					*fp->out++ = c;
			if(fp->f2 != NONE)
				fp->f2--;
			switch(c) {
			default:
				printcol++;
				break;
			case '\n':
				printcol = 0;
				break;
			case '\t':
				printcol = (printcol+8) & ~7;
				break;
			}
		}
	}
	if(fp->f1 != NONE && fp->f1 < 0) {
		fp->f1 = -fp->f1;
		while(n < fp->f1) {
			if(fp->out < fp->eout)
				*fp->out++ = ' ';
			printcol++;
			n++;
		}
	}
}

static	int
cconv(Op *op)
static
int
noconv(void *o, Fconv *fp)
{
	char b[2];

	b[0] = *(int*)op->argp;
	b[1] = 0;
	strconv(b, op, op->f1, -1);
	return INT;
	int n;
	char s[10];

	if(convcount == 0) {
		initfmt();
		n = 0;
		if(fp->chr >= 0 && fp->chr < MAXFMT)
			n = fmtindex[fp->chr];
		return (*fmtconv[n])(o, fp);
	}
	sprint(s, "*%c*", fp->chr);
	fp->f1 = 0;
	fp->f2 = NONE;
	fp->f3 = 0;
	strconv(s, fp);
	return 0;
}

static	int
dconv(Op *op)
static
int
cconv(void *o, Fconv *fp)
{
	char s[10];
	Rune rune;

	return numbconv(op, 10);
}
	rune = *(int*)o;
	if(fp->chr == 'c')
		rune &= 0xff;
	s[runetochar(s, &rune)] = 0;

static	int
hconv(Op *op)
{

	USED(op);
	return -FSHORT;
	fp->f2 = NONE;
	strconv(s, fp);
	return INT;
}

static	int
lconv(Op *op)
static
int
sconv(void *o, Fconv *fp)
{

	USED(op);
	return -FLONG;
	char *s;
	Rune *r;

	if(fp->chr == 's') {
		s = *(char**)o;
		if(s == 0)
			s = "<null>";
		strconv(s, fp);
	} else {
		r = *(Rune**)o;
		if(r == 0)
			r = L"<null>";
		Strconv(r, fp);
	}
	return PTR;
}

static	int
oconv(Op *op)
static
int
percent(void *o, Fconv *fp)
{

	return numbconv(op, 8);
	USED(o);
	if(fp->out < fp->eout)
		*fp->out++ = '%';
	return 0;
}

static	int
sconv(Op *op)
static
int
flags(void *o, Fconv *fp)
{
	int f;

	strconv(*(char**)op->argp, op, op->f1, op->f2);
	return PTR;
}
	USED(o);

static	int
uconv(Op *op)
{
	f = 0;
	switch(fp->chr) {
	case '+':
		f = FPLUS;
		break;

	USED(op);
	return -FUNSIGN;
}
	case '-':
		f = FMINUS;
		break;

static	int
xconv(Op *op)
{
	case '#':
		f = FSHARP;
		break;

	return numbconv(op, 16);
}
	case 'h':
		f = FSHORT;
		break;

static	int
percent(Op *op)
{
	case 'l':
		f = FLONG;
		if(fp->f3 & FLONG)
			f = FVLONG;
		break;

	PUT(op, '%');
	return 0;
	case 'u':
		f = FUNSIGN;
		break;
	}
	return -f;
}