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 }