9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

n4.c (12317B)


      1 /*
      2  * troff4.c
      3  *
      4  * number registers, conversion, arithmetic
      5  */
      6 
      7 #include "tdef.h"
      8 #include "fns.h"
      9 #include "ext.h"
     10 
     11 
     12 int	regcnt = NNAMES;
     13 int	falsef	= 0;	/* on if inside false branch of if */
     14 
     15 #define	NHASHSIZE	128	/* must be 2**n */
     16 #define	NHASH(i)	((i>>6)^i) & (NHASHSIZE-1)
     17 Numtab	*nhash[NHASHSIZE];
     18 
     19 Numtab *numtabp = NULL;
     20 #define NDELTA 400
     21 int ncnt = 0;
     22 
     23 void setn(void)
     24 {
     25 	int i, j, f;
     26 	Tchar ii;
     27 	Uchar *p;
     28 	char buf[NTM];		/* for \n(.S */
     29 
     30 	f = nform = 0;
     31 	if ((i = cbits(ii = getach())) == '+')
     32 		f = 1;
     33 	else if (i == '-')
     34 		f = -1;
     35 	else if (ii)	/* don't put it back if it's already back (thanks to jaap) */
     36 		ch = ii;
     37 	if (falsef)
     38 		f = 0;
     39 	if ((i = getsn()) == 0)
     40 		return;
     41 	p = unpair(i);
     42 	if (p[0] == '.')
     43 		switch (p[1]) {
     44 		case 's':
     45 			i = pts;
     46 			break;
     47 		case 'v':
     48 			i = lss;
     49 			break;
     50 		case 'f':
     51 			i = font;
     52 			break;
     53 		case 'p':
     54 			i = pl;
     55 			break;
     56 		case 't':
     57 			i = findt1();
     58 			break;
     59 		case 'o':
     60 			i = po;
     61 			break;
     62 		case 'l':
     63 			i = ll;
     64 			break;
     65 		case 'i':
     66 			i = in;
     67 			break;
     68 		case '$':
     69 			i = frame->nargs;
     70 			break;
     71 		case 'A':
     72 			i = ascii;
     73 			break;
     74 		case 'c':
     75 			i = numtabp[CD].val;
     76 			break;
     77 		case 'n':
     78 			i = lastl;
     79 			break;
     80 		case 'a':
     81 			i = ralss;
     82 			break;
     83 		case 'h':
     84 			i = dip->hnl;
     85 			break;
     86 		case 'd':
     87 			if (dip != d)
     88 				i = dip->dnl;
     89 			else
     90 				i = numtabp[NL].val;
     91 			break;
     92 		case 'u':
     93 			i = fi;
     94 			break;
     95 		case 'j':
     96 			i = ad + 2 * admod;
     97 			break;
     98 		case 'w':
     99 			i = widthp;
    100 			break;
    101 		case 'x':
    102 			i = nel;
    103 			break;
    104 		case 'y':
    105 			i = un;
    106 			break;
    107 		case 'T':
    108 			i = dotT;
    109 			break;	 /* -Tterm used in nroff */
    110 		case 'V':
    111 			i = VERT;
    112 			break;
    113 		case 'H':
    114 			i = HOR;
    115 			break;
    116 		case 'k':
    117 			i = ne;
    118 			break;
    119 		case 'P':
    120 			i = print;
    121 			break;
    122 		case 'L':
    123 			i = ls;
    124 			break;
    125 		case 'R':	/* maximal # of regs that can be addressed */
    126 			i = 255*256 - regcnt; 
    127 			break;
    128 		case 'z':
    129 			p = unpair(dip->curd);
    130 			*pbp++ = p[1];	/* watch order */
    131 			*pbp++ = p[0];
    132 			return;
    133 		case 'b':
    134 			i = bdtab[font];
    135 			break;
    136 		case 'F':
    137 			cpushback(cfname[ifi]);
    138 			return;
    139  		case 'S':
    140  			buf[0] = j = 0;	
    141  			for( i = 0; tabtab[i] != 0 && i < NTAB; i++) {
    142  				if (i > 0)
    143  					buf[j++] = ' ';
    144  				sprintf(&buf[j], "%ld", tabtab[i] & TABMASK);
    145  				j = strlen(buf);
    146  				if ( tabtab[i] & RTAB)
    147  					sprintf(&buf[j], "uR");
    148  				else if (tabtab[i] & CTAB)
    149  					sprintf(&buf[j], "uC");
    150  				else
    151  					sprintf(&buf[j], "uL");
    152  				j += 2;
    153  			}
    154  			cpushback(buf);
    155  			return;
    156 		default:
    157 			goto s0;
    158 		}
    159 	else {
    160 s0:
    161 		if ((j = findr(i)) == -1)
    162 			i = 0;
    163 		else {
    164 			i = numtabp[j].val = numtabp[j].val + numtabp[j].inc * f;
    165 			nform = numtabp[j].fmt;
    166 		}
    167 	}
    168 	setn1(i, nform, (Tchar) 0);
    169 }
    170 
    171 Tchar	numbuf[25];
    172 Tchar	*numbufp;
    173 
    174 int wrc(Tchar i)
    175 {
    176 	if (numbufp >= &numbuf[24])
    177 		return(0);
    178 	*numbufp++ = i;
    179 	return(1);
    180 }
    181 
    182 
    183 
    184 /* insert into input number i, in format form, with size-font bits bits */
    185 void setn1(int i, int form, Tchar bits)
    186 {
    187 	numbufp = numbuf;
    188 	nrbits = bits;
    189 	nform = form;
    190 	fnumb(i, wrc);
    191 	*numbufp = 0;
    192 	pushback(numbuf);
    193 }
    194 
    195 void prnumtab(Numtab *p)
    196 {
    197 	int i;
    198 	for (i = 0; i < ncnt; i++)
    199 		if (p)
    200 			if (p[i].r != 0)
    201 				fprintf(stderr, "slot %d, %s, val %d\n", i, unpair(p[i].r), p[i].val);
    202 			else
    203 				fprintf(stderr, "slot %d empty\n", i);
    204 		else
    205 			fprintf(stderr, "slot %d empty\n", i);
    206 }
    207 
    208 void nnspace(void)
    209 {
    210 	ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA;
    211 	numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab));
    212 	if (numtabp == NULL) {
    213 		ERROR "not enough memory for registers (%d)", ncnt WARN;
    214 		exit(1);
    215 	}
    216 	numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab,
    217 							sizeof(numtab));
    218 	if (numtabp == NULL) {
    219 		ERROR "Cannot initialize registers" WARN;
    220 		exit(1);
    221 	}
    222 }
    223 
    224 void grownumtab(void)
    225 {
    226 	ncnt += NDELTA;
    227 	numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab));
    228 	if (numtabp == NULL) {
    229 		ERROR "Too many number registers (%d)", ncnt WARN;
    230 		done2(04);
    231 	} else {
    232 		memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab),
    233 						0, NDELTA * sizeof(Numtab));
    234 		nrehash();
    235 	}
    236 }
    237 
    238 void nrehash(void)
    239 {
    240 	Numtab *p;
    241 	int i;
    242 
    243 	for (i=0; i<NHASHSIZE; i++)
    244 		nhash[i] = 0;
    245 	for (p=numtabp; p < &numtabp[ncnt]; p++)
    246 		p->link = 0;
    247 	for (p=numtabp; p < &numtabp[ncnt]; p++) {
    248 		if (p->r == 0)
    249 			continue;
    250 		i = NHASH(p->r);
    251 		p->link = nhash[i];
    252 		nhash[i] = p;
    253 	}
    254 }
    255 
    256 void nunhash(Numtab *rp)
    257 {
    258 	Numtab *p;
    259 	Numtab **lp;
    260 
    261 	if (rp->r == 0)
    262 		return;
    263 	lp = &nhash[NHASH(rp->r)];
    264 	p = *lp;
    265 	while (p) {
    266 		if (p == rp) {
    267 			*lp = p->link;
    268 			p->link = 0;
    269 			return;
    270 		}
    271 		lp = &p->link;
    272 		p = p->link;
    273 	}
    274 }
    275 
    276 int findr(int i)
    277 {
    278 	Numtab *p;
    279 	int h = NHASH(i);
    280 
    281 	if (i == 0)
    282 		return(-1);
    283 a0:
    284 	for (p = nhash[h]; p; p = p->link)
    285 		if (i == p->r)
    286 			return(p - numtabp);
    287 	for (p = numtabp; p < &numtabp[ncnt]; p++) {
    288 		if (p->r == 0) {
    289 			p->r = i;
    290 			p->link = nhash[h];
    291 			nhash[h] = p;
    292 			regcnt++;
    293 			return(p - numtabp);
    294 		}
    295 	}
    296 	grownumtab();
    297 	goto a0;
    298 }
    299 
    300 int usedr(int i)	/* returns -1 if nr i has never been used */
    301 {
    302 	Numtab *p;
    303 
    304 	if (i == 0)
    305 		return(-1);
    306 	for (p = nhash[NHASH(i)]; p; p = p->link)
    307 		if (i == p->r)
    308 			return(p - numtabp);
    309 	return -1;
    310 }
    311 
    312 
    313 int fnumb(int i, int (*f)(Tchar))
    314 {
    315 	int j;
    316 
    317 	j = 0;
    318 	if (i < 0) {
    319 		j = (*f)('-' | nrbits);
    320 		i = -i;
    321 	}
    322 	switch (nform) {
    323 	default:
    324 	case '1':
    325 	case 0:
    326 		return decml(i, f) + j;
    327 	case 'i':
    328 	case 'I':
    329 		return roman(i, f) + j;
    330 	case 'a':
    331 	case 'A':
    332 		return abc(i, f) + j;
    333 	}
    334 }
    335 
    336 
    337 int decml(int i, int (*f)(Tchar))
    338 {
    339 	int j, k;
    340 
    341 	k = 0;
    342 	nform--;
    343 	if ((j = i / 10) || (nform > 0))
    344 		k = decml(j, f);
    345 	return(k + (*f)((i % 10 + '0') | nrbits));
    346 }
    347 
    348 
    349 int roman(int i, int (*f)(Tchar))
    350 {
    351 
    352 	if (!i)
    353 		return((*f)('0' | nrbits));
    354 	if (nform == 'i')
    355 		return(roman0(i, f, "ixcmz", "vldw"));
    356 	else
    357 		return(roman0(i, f, "IXCMZ", "VLDW"));
    358 }
    359 
    360 
    361 int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)
    362 {
    363 	int q, rem, k;
    364 
    365 	if (!i)
    366 		return(0);
    367 	k = roman0(i / 10, f, onesp + 1, fivesp + 1);
    368 	q = (i = i % 10) / 5;
    369 	rem = i % 5;
    370 	if (rem == 4) {
    371 		k += (*f)(*onesp | nrbits);
    372 		if (q)
    373 			i = *(onesp + 1);
    374 		else
    375 			i = *fivesp;
    376 		return(k += (*f)(i | nrbits));
    377 	}
    378 	if (q)
    379 		k += (*f)(*fivesp | nrbits);
    380 	while (--rem >= 0)
    381 		k += (*f)(*onesp | nrbits);
    382 	return(k);
    383 }
    384 
    385 
    386 int abc(int i, int (*f)(Tchar))
    387 {
    388 	if (!i)
    389 		return((*f)('0' | nrbits));
    390 	else
    391 		return(abc0(i - 1, f));
    392 }
    393 
    394 
    395 int abc0(int i, int (*f)(Tchar))
    396 {
    397 	int j, k;
    398 
    399 	k = 0;
    400 	if (j = i / 26)
    401 		k = abc0(j - 1, f);
    402 	return(k + (*f)((i % 26 + nform) | nrbits));
    403 }
    404 
    405 long atoi0(void)
    406 {
    407 	int c, k, cnt;
    408 	Tchar ii;
    409 	long i, acc;
    410 
    411 	acc = 0;
    412 	nonumb = 0;
    413 	cnt = -1;
    414 a0:
    415 	cnt++;
    416 	ii = getch();
    417 	c = cbits(ii);
    418 	switch (c) {
    419 	default:
    420 		ch = ii;
    421 		if (cnt)
    422 			break;
    423 	case '+':
    424 		i = ckph();
    425 		if (nonumb)
    426 			break;
    427 		acc += i;
    428 		goto a0;
    429 	case '-':
    430 		i = ckph();
    431 		if (nonumb)
    432 			break;
    433 		acc -= i;
    434 		goto a0;
    435 	case '*':
    436 		i = ckph();
    437 		if (nonumb)
    438 			break;
    439 		acc *= i;
    440 		goto a0;
    441 	case '/':
    442 		i = ckph();
    443 		if (nonumb)
    444 			break;
    445 		if (i == 0) {
    446 			flusho();
    447 			ERROR "divide by zero." WARN;
    448 			acc = 0;
    449 		} else
    450 			acc /= i;
    451 		goto a0;
    452 	case '%':
    453 		i = ckph();
    454 		if (nonumb)
    455 			break;
    456 		acc %= i;
    457 		goto a0;
    458 	case '&':	/*and*/
    459 		i = ckph();
    460 		if (nonumb)
    461 			break;
    462 		if ((acc > 0) && (i > 0))
    463 			acc = 1;
    464 		else
    465 			acc = 0;
    466 		goto a0;
    467 	case ':':	/*or*/
    468 		i = ckph();
    469 		if (nonumb)
    470 			break;
    471 		if ((acc > 0) || (i > 0))
    472 			acc = 1;
    473 		else
    474 			acc = 0;
    475 		goto a0;
    476 	case '=':
    477 		if (cbits(ii = getch()) != '=')
    478 			ch = ii;
    479 		i = ckph();
    480 		if (nonumb) {
    481 			acc = 0;
    482 			break;
    483 		}
    484 		if (i == acc)
    485 			acc = 1;
    486 		else
    487 			acc = 0;
    488 		goto a0;
    489 	case '>':
    490 		k = 0;
    491 		if (cbits(ii = getch()) == '=')
    492 			k++;
    493 		else
    494 			ch = ii;
    495 		i = ckph();
    496 		if (nonumb) {
    497 			acc = 0;
    498 			break;
    499 		}
    500 		if (acc > (i - k))
    501 			acc = 1;
    502 		else
    503 			acc = 0;
    504 		goto a0;
    505 	case '<':
    506 		k = 0;
    507 		if (cbits(ii = getch()) == '=')
    508 			k++;
    509 		else
    510 			ch = ii;
    511 		i = ckph();
    512 		if (nonumb) {
    513 			acc = 0;
    514 			break;
    515 		}
    516 		if (acc < (i + k))
    517 			acc = 1;
    518 		else
    519 			acc = 0;
    520 		goto a0;
    521 	case ')':
    522 		break;
    523 	case '(':
    524 		acc = atoi0();
    525 		goto a0;
    526 	}
    527 	return(acc);
    528 }
    529 
    530 
    531 long ckph(void)
    532 {
    533 	Tchar i;
    534 	long j;
    535 
    536 	if (cbits(i = getch()) == '(')
    537 		j = atoi0();
    538 	else {
    539 		j = atoi1(i);
    540 	}
    541 	return(j);
    542 }
    543 
    544 
    545 /*
    546  * print error about illegal numeric argument;
    547  */
    548 void prnumerr(void)
    549 {
    550 	char err_buf[40];
    551 	static char warn[] = "Numeric argument expected";
    552 	int savcd = numtabp[CD].val;
    553 
    554 	if (numerr.type == RQERR)
    555 		sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),
    556 						unpair(numerr.req), warn);
    557 	else
    558 		sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
    559 									warn);
    560 	if (frame != stk)	/* uncertainty correction */
    561 		numtabp[CD].val--;
    562 	ERROR "%s", err_buf WARN;
    563 	numtabp[CD].val = savcd;
    564 }
    565 
    566 
    567 long atoi1(Tchar ii)
    568 {
    569 	int i, j, digits;
    570 	double acc;	/* this is the only double in troff! */
    571 	int neg, abs, field, decpnt;
    572 	extern int ifnum;
    573 
    574 
    575 	neg = abs = field = decpnt = digits = 0;
    576 	acc = 0;
    577 	for (;;) {
    578 		i = cbits(ii);
    579 		switch (i) {
    580 		default:
    581 			break;
    582 		case '+':
    583 			ii = getch();
    584 			continue;
    585 		case '-':
    586 			neg = 1;
    587 			ii = getch();
    588 			continue;
    589 		case '|':
    590 			abs = 1 + neg;
    591 			neg = 0;
    592 			ii = getch();
    593 			continue;
    594 		}
    595 		break;
    596 	}
    597 a1:
    598 	while (i >= '0' && i <= '9') {
    599 		field++;
    600 		digits++;
    601 		acc = 10 * acc + i - '0';
    602 		ii = getch();
    603 		i = cbits(ii);
    604 	}
    605 	if (i == '.' && !decpnt++) {
    606 		field++;
    607 		digits = 0;
    608 		ii = getch();
    609 		i = cbits(ii);
    610 		goto a1;
    611 	}
    612 	if (!field) {
    613 		ch = ii;
    614 		goto a2;
    615 	}
    616 	switch (i) {
    617 	case 'u':
    618 		i = j = 1;	/* should this be related to HOR?? */
    619 		break;
    620 	case 'v':	/*VSs - vert spacing*/
    621 		j = lss;
    622 		i = 1;
    623 		break;
    624 	case 'm':	/*Ems*/
    625 		j = EM;
    626 		i = 1;
    627 		break;
    628 	case 'n':	/*Ens*/
    629 		j = EM;
    630 		if (TROFF)
    631 			i = 2;
    632 		else
    633 			i = 1;	/*Same as Ems in NROFF*/
    634 		break;
    635 	case 'p':	/*Points*/
    636 		j = INCH;
    637 		i = 72;
    638 		break;
    639 	case 'i':	/*Inches*/
    640 		j = INCH;
    641 		i = 1;
    642 		break;
    643 	case 'c':	/*Centimeters*/
    644 		/* if INCH is too big, this will overflow */
    645 		j = INCH * 50;
    646 		i = 127;
    647 		break;
    648 	case 'P':	/*Picas*/
    649 		j = INCH;
    650 		i = 6;
    651 		break;
    652 	default:
    653 		j = dfact;
    654 		ch = ii;
    655 		i = dfactd;
    656 	}
    657 	if (neg)
    658 		acc = -acc;
    659 	if (!noscale) {
    660 		acc = (acc * j) / i;
    661 	}
    662 	if (field != digits && digits > 0)
    663 		while (digits--)
    664 			acc /= 10;
    665 	if (abs) {
    666 		if (dip != d)
    667 			j = dip->dnl;
    668 		else
    669 			j = numtabp[NL].val;
    670 		if (!vflag) {
    671 			j = numtabp[HP].val;
    672 		}
    673 		if (abs == 2)
    674 			j = -j;
    675 		acc -= j;
    676 	}
    677 a2:
    678 	nonumb = (!field || field == decpnt);
    679 	if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) {
    680 		if (cbits(ii) != RIGHT ) /* Too painful to do right */
    681 			prnumerr();
    682 	}
    683 	return(acc);
    684 }
    685 
    686 
    687 void caserr(void)
    688 {
    689 	int i, j;
    690 	Numtab *p;
    691 
    692 	lgf++;
    693 	while (!skip() && (i = getrq()) ) {
    694 		j = usedr(i);
    695 		if (j < 0)
    696 			continue;
    697 		p = &numtabp[j];
    698 		nunhash(p);
    699 		p->r = p->val = p->inc = p->fmt = 0;
    700 		regcnt--;
    701 	}
    702 }
    703 
    704 /*
    705  * .nr request; if tracing, don't check optional
    706  * 2nd argument because tbl generates .in 1.5n
    707  */
    708 void casenr(void)
    709 {
    710 	int i, j;
    711 	int savtr = trace;
    712 
    713 	lgf++;
    714 	skip();
    715 	if ((i = findr(getrq())) == -1)
    716 		goto rtn;
    717 	skip();
    718 	j = inumb(&numtabp[i].val);
    719 	if (nonumb)
    720 		goto rtn;
    721 	numtabp[i].val = j;
    722 	skip();
    723 	trace = 0;
    724 	j = atoi0();		/* BUG??? */
    725 	trace = savtr;
    726 	if (nonumb)
    727 		goto rtn;
    728 	numtabp[i].inc = j;
    729 rtn:
    730 	return;
    731 }
    732 
    733 void caseaf(void)
    734 {
    735 	int i, k;
    736 	Tchar j;
    737 
    738 	lgf++;
    739 	if (skip() || !(i = getrq()) || skip())
    740 		return;
    741 	k = 0;
    742 	j = getch();
    743 	if (!isalpha(cbits(j))) {
    744 		ch = j;
    745 		while ((j = cbits(getch())) >= '0' &&  j <= '9')
    746 			k++;
    747 	}
    748 	if (!k)
    749 		k = j;
    750 	numtabp[findr(i)].fmt = k;	/* was k & BYTEMASK */
    751 }
    752 
    753 void setaf(void)	/* return format of number register */
    754 {
    755 	int i, j;
    756 
    757 	i = usedr(getsn());
    758 	if (i == -1)
    759 		return;
    760 	if (numtabp[i].fmt > 20)	/* it was probably a, A, i or I */
    761 		*pbp++ = numtabp[i].fmt;
    762 	else
    763 		for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
    764 			*pbp++ = '0';
    765 }
    766 
    767 
    768 int vnumb(int *i)
    769 {
    770 	vflag++;
    771 	dfact = lss;
    772 	res = VERT;
    773 	return(inumb(i));
    774 }
    775 
    776 
    777 int hnumb(int *i)
    778 {
    779 	dfact = EM;
    780 	res = HOR;
    781 	return(inumb(i));
    782 }
    783 
    784 
    785 int inumb(int *n)
    786 {
    787 	int i, j, f;
    788 	Tchar ii;
    789 
    790 	f = 0;
    791 	if (n) {
    792 		if ((j = cbits(ii = getch())) == '+')
    793 			f = 1;
    794 		else if (j == '-')
    795 			f = -1;
    796 		else
    797 			ch = ii;
    798 	}
    799 	i = atoi0();
    800 	if (n && f)
    801 		i = *n + f * i;
    802 	i = quant(i, res);
    803 	vflag = 0;
    804 	res = dfactd = dfact = 1;
    805 	if (nonumb)
    806 		i = 0;
    807 	return(i);
    808 }
    809 
    810 
    811 int quant(int n, int m)
    812 {
    813 	int i, neg;
    814 
    815 	neg = 0;
    816 	if (n < 0) {
    817 		neg++;
    818 		n = -n;
    819 	}
    820 	/* better as i = ((n + m/2)/m)*m */
    821 	i = n / m;
    822 	if (n - m * i > m / 2)
    823 		i += 1;
    824 	i *= m;
    825 	if (neg)
    826 		i = -i;
    827 	return(i);
    828 }