458 lines · 6.5 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "a.h"/* * 8. Number Registers * (Reg register implementation is also here.) */ /* *	\nx		N *	\n(xx	N *	\n+x		N+=M *	\n-x		N-=M * *	.nr R ±N M *	.af R c * *	formats *		1	0, 1, 2, 3, ... *		001	001, 002, 003, ... *		i	0, i, ii, iii, iv, v, ... *		I	0, I, II, III, IV, V, ... *		a	0, a, b, ..., aa, ab, ..., zz, aaa, ... *		A	0, A, B, ..., AA, AB, ..., ZZ, AAA, ... * *	\gx \g(xx return format of number register * *	.rr R */ typedef struct Reg Reg;struct Reg{	Reg *next;	Rune *name;	Rune *val;	Rune *fmt;	int inc;}; Reg *dslist;Reg *nrlist; /* * Define strings and numbers. */voiddsnr(Rune *name, Rune *val, Reg **l){	Reg *s; 	for(s = *l; s != nil; s = *l){		if(runestrcmp(s->name, name) == 0)			break;		l = &s->next;	}	if(val == nil){		if(s){			*l = s->next;			free(s->val);			free(s->fmt);			free(s);		}		return;	}	if(s == nil){		s = emalloc(sizeof(Reg));		*l = s;		s->name = erunestrdup(name);	}else		free(s->val);	s->val = erunestrdup(val);} Rune*getdsnr(Rune *name, Reg *list){	Reg *s;		for(s=list; s; s=s->next)		if(runestrcmp(name, s->name) == 0)			return s->val;	return nil;} voidds(Rune *name, Rune *val){	dsnr(name, val, &dslist);} voidas(Rune *name, Rune *val){	Rune *p, *q;		p = getds(name);	if(p == nil)		p = L("");	q = runemalloc(runestrlen(p)+runestrlen(val)+1);	runestrcpy(q, p);	runestrcat(q, val);	ds(name, q);	free(q);} Rune*getds(Rune *name){	return getdsnr(name, dslist);} voidprintds(int t){	int n, total;	Reg *s;		total = 0;	for(s=dslist; s; s=s->next){		if(s->val)			n = runestrlen(s->val);		else			n = 0;		total += n;		if(!t)			fprint(2, "%S\t%d\n", s->name, n);	}	fprint(2, "total\t%d\n", total);} voidnr(Rune *name, int val){	Rune buf[20];		runesnprint(buf, nelem(buf), "%d", val);	_nr(name, buf);} voidaf(Rune *name, Rune *fmt){	Reg *s; 	if(_getnr(name) == nil)		_nr(name, L("0"));	for(s=nrlist; s; s=s->next)		if(runestrcmp(s->name, name) == 0)			s->fmt = erunestrdup(fmt);} Rune*getaf(Rune *name){	Reg *s;		for(s=nrlist; s; s=s->next)		if(runestrcmp(s->name, name) == 0)			return s->fmt;	return nil;} voidprintnr(void){	Reg *r;		for(r=nrlist; r; r=r->next)		fprint(2, "%S %S %d\n", r->name, r->val, r->inc);} /* * Some internal number registers are actually strings, * so provide _ versions to get at them. */void_nr(Rune *name, Rune *val){	dsnr(name, val, &nrlist);} Rune*_getnr(Rune *name){	return getdsnr(name, nrlist);} intgetnr(Rune *name){	Rune *p; 	p = _getnr(name);	if(p == nil)		return 0;	return eval(p);} /* new register */voidr_nr(int argc, Rune **argv){	Reg *s; 	if(argc < 2)		return;	if(argc < 3)		nr(argv[1], 0);	else{		if(argv[2][0] == '+')			nr(argv[1], getnr(argv[1])+eval(argv[2]+1));		else if(argv[2][0] == '-')			nr(argv[1], getnr(argv[1])-eval(argv[2]+1));		else			nr(argv[1], eval(argv[2]));	}	if(argc > 3){		for(s=nrlist; s; s=s->next)			if(runestrcmp(s->name, argv[1]) == 0)				s->inc = eval(argv[3]);	}} /* assign format */voidr_af(int argc, Rune **argv){	USED(argc);		af(argv[1], argv[2]);} /* remove register */voidr_rr(int argc, Rune **argv){	int i;		for(i=1; i<argc; i++)		_nr(argv[i], nil);} /* fmt integer in base 26 */voidalpha(Rune *buf, int n, int a){	int i, v;		i = 1;	for(v=n; v>0; v/=26)		i++;	if(i == 0)		i = 1;	buf[i] = 0;	while(i > 0){		buf[--i] = a+n%26;		n /= 26;	}} struct romanv {	char *s;	int v;} romanv[] ={	"m",	1000,	"cm", 900,	"d", 500,	"cd", 400,	"c", 100,	"xc", 90,	"l", 50,	"xl", 40,	"x", 10,	"ix", 9,	"v", 5,	"iv", 4,	"i", 1}; /* fmt integer in roman numerals! */voidroman(Rune *buf, int n, int upper){	Rune *p;	char *q;	struct romanv *r;		if(upper)		upper = 'A' - 'a';	if(n >= 5000 || n <= 0){		runestrcpy(buf, L("-"));		return;	}	p = buf;	r = romanv;	while(n > 0){		while(n >= r->v){			for(q=r->s; *q; q++)				*p++ = *q + upper;			n -= r->v;		}		r++;	}	*p = 0;} Rune*getname(void){	int i, c, cc;	static Rune buf[100];		/* XXX add [name] syntax as in groff */	c = getnext();	if(c < 0)		return L("");	if(c == '\n'){		warn("newline in name\n");		ungetnext(c);		return L("");	}	if(c == '['){		for(i=0; i<nelem(buf)-1; i++){			if((c = getrune()) < 0)				return L("");			if(c == ']'){				buf[i] = 0;				return buf;			}			buf[i] = c;		}		return L("");	}	if(c != '('){		buf[0] = c;		buf[1] = 0;		return buf;	}	c = getnext();	cc = getnext();	if(c < 0 || cc < 0)		return L("");	if(c == '\n' | cc == '\n'){		warn("newline in \\n");		ungetnext(cc);		if(c == '\n')			ungetnext(c);	}	buf[0] = c;	buf[1] = cc;	buf[2] = 0;	return buf;} /* \n - return number register */inte_n(void){	int inc, v, l;	Rune *name, *fmt, buf[100];	Reg *s;		inc = getnext();	if(inc < 0)		return -1;	if(inc != '+' && inc != '-'){		ungetnext(inc);		inc = 0;	}	name = getname();	if(_getnr(name) == nil)		_nr(name, L("0"));	for(s=nrlist; s; s=s->next){		if(runestrcmp(s->name, name) == 0){			if(s->fmt == nil && !inc && s->val[0]){				/* might be a string! */				pushinputstring(s->val);				return 0;			}			v = eval(s->val);			if(inc){				if(inc == '+')					v += s->inc;				else					v -= s->inc;				runesnprint(buf, nelem(buf), "%d", v);				free(s->val);				s->val = erunestrdup(buf);			}			fmt = s->fmt;			if(fmt == nil)				fmt = L("1");			switch(fmt[0]){			case 'i':			case 'I':				roman(buf, v, fmt[0]=='I');				break;			case 'a':			case 'A':				alpha(buf, v, fmt[0]);				break;			default:				l = runestrlen(fmt);				if(l == 0)					l = 1;				runesnprint(buf, sizeof buf, "%0*d", l, v);				break;			}			pushinputstring(buf);			return 0;		}	}	pushinputstring(L(""));	return 0;} /* \g - number register format */inte_g(void){	Rune *p; 	p = getaf(getname());	if(p == nil)		p = L("1");	pushinputstring(p);	return 0;} voidr_pnr(int argc, Rune **argv){	USED(argc);	USED(argv);	printnr();} voidt8init(void){	addreq(L("nr"), r_nr, -1);	addreq(L("af"), r_af, 2);	addreq(L("rr"), r_rr, -1);	addreq(L("pnr"), r_pnr, 0);		addesc('n', e_n, CopyMode|ArgMode|HtmlMode);	addesc('g', e_g, 0);}