plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

t8.c (6231B)


      1 #include "a.h"
      2 /*
      3  * 8. Number Registers
      4  * (Reg register implementation is also here.)
      5  */
      6 
      7 /*
      8  *	\nx		N
      9  *	\n(xx	N
     10  *	\n+x		N+=M
     11  *	\n-x		N-=M
     12  *
     13  *	.nr R ±N M
     14  *	.af R c
     15  *
     16  *	formats
     17  *		1	0, 1, 2, 3, ...
     18  *		001	001, 002, 003, ...
     19  *		i	0, i, ii, iii, iv, v, ...
     20  *		I	0, I, II, III, IV, V, ...
     21  *		a	0, a, b, ..., aa, ab, ..., zz, aaa, ...
     22  *		A	0, A, B, ..., AA, AB, ..., ZZ, AAA, ...
     23  *
     24  *	\gx \g(xx return format of number register
     25  *
     26  *	.rr R
     27  */
     28 
     29 typedef struct Reg Reg;
     30 struct Reg
     31 {
     32 	Reg *next;
     33 	Rune *name;
     34 	Rune *val;
     35 	Rune *fmt;
     36 	int inc;
     37 };
     38 
     39 Reg *dslist;
     40 Reg *nrlist;
     41 
     42 /*
     43  * Define strings and numbers.
     44  */
     45 void
     46 dsnr(Rune *name, Rune *val, Reg **l)
     47 {
     48 	Reg *s;
     49 
     50 	for(s = *l; s != nil; s = *l){
     51 		if(runestrcmp(s->name, name) == 0)
     52 			break;
     53 		l = &s->next;
     54 	}
     55 	if(val == nil){
     56 		if(s){
     57 			*l = s->next;
     58 			free(s->val);
     59 			free(s->fmt);
     60 			free(s);
     61 		}
     62 		return;
     63 	}
     64 	if(s == nil){
     65 		s = emalloc(sizeof(Reg));
     66 		*l = s;
     67 		s->name = erunestrdup(name);
     68 	}else
     69 		free(s->val);
     70 	s->val = erunestrdup(val);
     71 }
     72 
     73 Rune*
     74 getdsnr(Rune *name, Reg *list)
     75 {
     76 	Reg *s;
     77 
     78 	for(s=list; s; s=s->next)
     79 		if(runestrcmp(name, s->name) == 0)
     80 			return s->val;
     81 	return nil;
     82 }
     83 
     84 void
     85 ds(Rune *name, Rune *val)
     86 {
     87 	dsnr(name, val, &dslist);
     88 }
     89 
     90 void
     91 as(Rune *name, Rune *val)
     92 {
     93 	Rune *p, *q;
     94 
     95 	p = getds(name);
     96 	if(p == nil)
     97 		p = L("");
     98 	q = runemalloc(runestrlen(p)+runestrlen(val)+1);
     99 	runestrcpy(q, p);
    100 	runestrcat(q, val);
    101 	ds(name, q);
    102 	free(q);
    103 }
    104 
    105 Rune*
    106 getds(Rune *name)
    107 {
    108 	return getdsnr(name, dslist);
    109 }
    110 
    111 void
    112 printds(int t)
    113 {
    114 	int n, total;
    115 	Reg *s;
    116 
    117 	total = 0;
    118 	for(s=dslist; s; s=s->next){
    119 		if(s->val)
    120 			n = runestrlen(s->val);
    121 		else
    122 			n = 0;
    123 		total += n;
    124 		if(!t)
    125 			fprint(2, "%S\t%d\n", s->name, n);
    126 	}
    127 	fprint(2, "total\t%d\n", total);
    128 }
    129 
    130 void
    131 nr(Rune *name, int val)
    132 {
    133 	Rune buf[20];
    134 
    135 	runesnprint(buf, nelem(buf), "%d", val);
    136 	_nr(name, buf);
    137 }
    138 
    139 void
    140 af(Rune *name, Rune *fmt)
    141 {
    142 	Reg *s;
    143 
    144 	if(_getnr(name) == nil)
    145 		_nr(name, L("0"));
    146 	for(s=nrlist; s; s=s->next)
    147 		if(runestrcmp(s->name, name) == 0)
    148 			s->fmt = erunestrdup(fmt);
    149 }
    150 
    151 Rune*
    152 getaf(Rune *name)
    153 {
    154 	Reg *s;
    155 
    156 	for(s=nrlist; s; s=s->next)
    157 		if(runestrcmp(s->name, name) == 0)
    158 			return s->fmt;
    159 	return nil;
    160 }
    161 
    162 void
    163 printnr(void)
    164 {
    165 	Reg *r;
    166 
    167 	for(r=nrlist; r; r=r->next)
    168 		fprint(2, "%S %S %d\n", r->name, r->val, r->inc);
    169 }
    170 
    171 /*
    172  * Some internal number registers are actually strings,
    173  * so provide _ versions to get at them.
    174  */
    175 void
    176 _nr(Rune *name, Rune *val)
    177 {
    178 	dsnr(name, val, &nrlist);
    179 }
    180 
    181 Rune*
    182 _getnr(Rune *name)
    183 {
    184 	return getdsnr(name, nrlist);
    185 }
    186 
    187 int
    188 getnr(Rune *name)
    189 {
    190 	Rune *p;
    191 
    192 	p = _getnr(name);
    193 	if(p == nil)
    194 		return 0;
    195 	return eval(p);
    196 }
    197 
    198 /* new register */
    199 void
    200 r_nr(int argc, Rune **argv)
    201 {
    202 	Reg *s;
    203 
    204 	if(argc < 2)
    205 		return;
    206 	if(argc < 3)
    207 		nr(argv[1], 0);
    208 	else{
    209 		if(argv[2][0] == '+')
    210 			nr(argv[1], getnr(argv[1])+eval(argv[2]+1));
    211 		else if(argv[2][0] == '-')
    212 			nr(argv[1], getnr(argv[1])-eval(argv[2]+1));
    213 		else
    214 			nr(argv[1], eval(argv[2]));
    215 	}
    216 	if(argc > 3){
    217 		for(s=nrlist; s; s=s->next)
    218 			if(runestrcmp(s->name, argv[1]) == 0)
    219 				s->inc = eval(argv[3]);
    220 	}
    221 }
    222 
    223 /* assign format */
    224 void
    225 r_af(int argc, Rune **argv)
    226 {
    227 	USED(argc);
    228 
    229 	af(argv[1], argv[2]);
    230 }
    231 
    232 /* remove register */
    233 void
    234 r_rr(int argc, Rune **argv)
    235 {
    236 	int i;
    237 
    238 	for(i=1; i<argc; i++)
    239 		_nr(argv[i], nil);
    240 }
    241 
    242 /* fmt integer in base 26 */
    243 void
    244 alpha(Rune *buf, int n, int a)
    245 {
    246 	int i, v;
    247 
    248 	i = 1;
    249 	for(v=n; v>0; v/=26)
    250 		i++;
    251 	if(i == 0)
    252 		i = 1;
    253 	buf[i] = 0;
    254 	while(i > 0){
    255 		buf[--i] = a+n%26;
    256 		n /= 26;
    257 	}
    258 }
    259 
    260 struct romanv {
    261 	char *s;
    262 	int v;
    263 } romanv[] =
    264 {
    265 	"m",	1000,
    266 	"cm", 900,
    267 	"d", 500,
    268 	"cd", 400,
    269 	"c", 100,
    270 	"xc", 90,
    271 	"l", 50,
    272 	"xl", 40,
    273 	"x", 10,
    274 	"ix", 9,
    275 	"v", 5,
    276 	"iv", 4,
    277 	"i", 1
    278 };
    279 
    280 /* fmt integer in roman numerals! */
    281 void
    282 roman(Rune *buf, int n, int upper)
    283 {
    284 	Rune *p;
    285 	char *q;
    286 	struct romanv *r;
    287 
    288 	if(upper)
    289 		upper = 'A' - 'a';
    290 	if(n >= 5000 || n <= 0){
    291 		runestrcpy(buf, L("-"));
    292 		return;
    293 	}
    294 	p = buf;
    295 	r = romanv;
    296 	while(n > 0){
    297 		while(n >= r->v){
    298 			for(q=r->s; *q; q++)
    299 				*p++ = *q + upper;
    300 			n -= r->v;
    301 		}
    302 		r++;
    303 	}
    304 	*p = 0;
    305 }
    306 
    307 Rune*
    308 getname(void)
    309 {
    310 	int i, c, cc;
    311 	static Rune buf[100];
    312 
    313 	/* XXX add [name] syntax as in groff */
    314 	c = getnext();
    315 	if(c < 0)
    316 		return L("");
    317 	if(c == '\n'){
    318 		warn("newline in name\n");
    319 		ungetnext(c);
    320 		return L("");
    321 	}
    322 	if(c == '['){
    323 		for(i=0; i<nelem(buf)-1; i++){
    324 			if((c = getrune()) < 0)
    325 				return L("");
    326 			if(c == ']'){
    327 				buf[i] = 0;
    328 				return buf;
    329 			}
    330 			buf[i] = c;
    331 		}
    332 		return L("");
    333 	}
    334 	if(c != '('){
    335 		buf[0] = c;
    336 		buf[1] = 0;
    337 		return buf;
    338 	}
    339 	c = getnext();
    340 	cc = getnext();
    341 	if(c < 0 || cc < 0)
    342 		return L("");
    343 	if(c == '\n' | cc == '\n'){
    344 		warn("newline in \\n");
    345 		ungetnext(cc);
    346 		if(c == '\n')
    347 			ungetnext(c);
    348 	}
    349 	buf[0] = c;
    350 	buf[1] = cc;
    351 	buf[2] = 0;
    352 	return buf;
    353 }
    354 
    355 /* \n - return number register */
    356 int
    357 e_n(void)
    358 {
    359 	int inc, v, l;
    360 	Rune *name, *fmt, buf[100];
    361 	Reg *s;
    362 
    363 	inc = getnext();
    364 	if(inc < 0)
    365 		return -1;
    366 	if(inc != '+' && inc != '-'){
    367 		ungetnext(inc);
    368 		inc = 0;
    369 	}
    370 	name = getname();
    371 	if(_getnr(name) == nil)
    372 		_nr(name, L("0"));
    373 	for(s=nrlist; s; s=s->next){
    374 		if(runestrcmp(s->name, name) == 0){
    375 			if(s->fmt == nil && !inc && s->val[0]){
    376 				/* might be a string! */
    377 				pushinputstring(s->val);
    378 				return 0;
    379 			}
    380 			v = eval(s->val);
    381 			if(inc){
    382 				if(inc == '+')
    383 					v += s->inc;
    384 				else
    385 					v -= s->inc;
    386 				runesnprint(buf, nelem(buf), "%d", v);
    387 				free(s->val);
    388 				s->val = erunestrdup(buf);
    389 			}
    390 			fmt = s->fmt;
    391 			if(fmt == nil)
    392 				fmt = L("1");
    393 			switch(fmt[0]){
    394 			case 'i':
    395 			case 'I':
    396 				roman(buf, v, fmt[0]=='I');
    397 				break;
    398 			case 'a':
    399 			case 'A':
    400 				alpha(buf, v, fmt[0]);
    401 				break;
    402 			default:
    403 				l = runestrlen(fmt);
    404 				if(l == 0)
    405 					l = 1;
    406 				runesnprint(buf, sizeof buf, "%0*d", l, v);
    407 				break;
    408 			}
    409 			pushinputstring(buf);
    410 			return 0;
    411 		}
    412 	}
    413 	pushinputstring(L(""));
    414 	return 0;
    415 }
    416 
    417 /* \g - number register format */
    418 int
    419 e_g(void)
    420 {
    421 	Rune *p;
    422 
    423 	p = getaf(getname());
    424 	if(p == nil)
    425 		p = L("1");
    426 	pushinputstring(p);
    427 	return 0;
    428 }
    429 
    430 void
    431 r_pnr(int argc, Rune **argv)
    432 {
    433 	USED(argc);
    434 	USED(argv);
    435 	printnr();
    436 }
    437 
    438 void
    439 t8init(void)
    440 {
    441 	addreq(L("nr"), r_nr, -1);
    442 	addreq(L("af"), r_af, 2);
    443 	addreq(L("rr"), r_rr, -1);
    444 	addreq(L("pnr"), r_pnr, 0);
    445 
    446 	addesc('n', e_n, CopyMode|ArgMode|HtmlMode);
    447 	addesc('g', e_g, 0);
    448 }