1 /* 2 * nreq.c - cawf(1) processing of nroff requests 3 */ 4 5 /* 6 * Copyright (c) 1991 Purdue University Research Foundation, 7 * West Lafayette, Indiana 47907. All rights reserved. 8 * 9 * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue 10 * University Computing Center. Not derived from licensed software; 11 * derived from awf(1) by Henry Spencer of the University of Toronto. 12 * 13 * Permission is granted to anyone to use this software for any 14 * purpose on any computer system, and to alter it and redistribute 15 * it freely, subject to the following restrictions: 16 * 17 * 1. The author is not responsible for any consequences of use of 18 * this software, even if they arise from flaws in it. 19 * 20 * 2. The origin of this software must not be misrepresented, either 21 * by explicit claim or by omission. Credits must appear in the 22 * documentation. 23 * 24 * 3. Altered versions must be plainly marked as such, and must not 25 * be misrepresented as being the original software. Credits must 26 * appear in the documentation. 27 * 28 * 4. This notice may not be removed or altered. 29 */ 30 31 #include "cawf.h" 32 #include <ctype.h> 33 34 35 /* 36 * Prototypes for request processing functions. 37 */ 38 39 static void nr_UL(unsigned char *line, int brk); 40 static void nr_Ub(unsigned char *line, int brk); 41 static void nr_Uc(unsigned char *line, int brk); 42 static void nr_Uf(unsigned char *line, int brk); 43 static void nr_Ur(unsigned char *line, int brk); 44 static void nr_ad(unsigned char *line, int brk); 45 static void nr_bp(unsigned char *line, int brk); 46 static void nr_br(unsigned char *line, int brk); 47 static void nr_ce(unsigned char *line, int brk); 48 static void nr_di(unsigned char *line, int brk); 49 static void nr_ds(unsigned char *line, int brk); 50 static void nr_fi(unsigned char *line, int brk); 51 static void nr_fl(unsigned char *line, int brk); 52 static void nr_ft(unsigned char *line, int brk); 53 static void nr_it(unsigned char *line, int brk); 54 static void nr_na(unsigned char *line, int brk); 55 static void nr_nf(unsigned char *line, int brk); 56 static void nr_ns(unsigned char *line, int brk); 57 static void nr_rm(unsigned char *line, int brk); 58 static void nr_rn(unsigned char *line, int brk); 59 static void nr_rr(unsigned char *line, int brk); 60 static void nr_rs(unsigned char *line, int brk); 61 static void nr_tm(unsigned char *line, int brk); 62 static void nr_tr(unsigned char *line, int brk); 63 64 static void nr_nil(unsigned char *line, int brk); 65 66 67 /* 68 * NrReqt[] - nroff request processing table 69 * 70 * CAUTION: place new entries in their proper alphabetical order, since 71 * this table is processed with a binary search. 72 */ 73 74 static struct nr_req { 75 char *nm; /* nroff request */ 76 void (*fun)(); /* processing function */ 77 } NrReqt[] = { 78 { "\\\"", nr_nil }, /* backslash-quote */ 79 { "^#", nr_UL }, 80 { "^=", nr_UL }, 81 { "^b", nr_Ub }, 82 { "^c", nr_Uc }, 83 { "^d", nr_nil }, 84 { "^e", nr_nil }, 85 { "^f", nr_Uf }, 86 { "^r", nr_Ur }, 87 { "^x", nr_nil }, 88 { "ad", nr_ad }, 89 { "bp", nr_bp }, 90 { "br", nr_br }, 91 { "ce", nr_ce }, 92 { "di", nr_di }, 93 { "ds", nr_ds }, 94 { "fi", nr_fi }, 95 { "fl", nr_fl }, 96 { "ft", nr_ft }, 97 { "hy", nr_nil }, 98 { "i0", nr_nil }, 99 { "it", nr_it }, 100 { "lg", nr_nil }, 101 { "li", nr_nil }, 102 { "na", nr_na }, 103 { "nf", nr_nf }, 104 { "ns", nr_ns }, 105 { "ps", nr_nil }, 106 { "rm", nr_rm }, 107 { "rn", nr_rn }, 108 { "rr", nr_rr }, 109 { "rs", nr_rs }, 110 { "tm", nr_tm }, 111 { "tr", nr_tr }, 112 { "vs", nr_nil }, 113 }; 114 /* 115 * Nreq(line, brk) - process miscellaneous nroff requests from line 116 * buffer with request status of (brk) 117 */ 118 119 void Nreq(unsigned char *line, int brk) { 120 unsigned char c[3]; /* command buffer */ 121 int cmp, hi, low, mid; /* binary search indixes */ 122 123 c[0] = c[1] = c[2] = '\0'; 124 if ((c[0] = line[1]) != '\0') 125 c[1] = line[2]; 126 127 low = mid = 0; 128 hi = sizeof(NrReqt) / sizeof(struct nr_req); 129 while (low <= hi) { 130 mid = (low + hi) / 2; 131 if ((cmp = strcmp((char *)c, NrReqt[mid].nm)) < 0) 132 hi = mid - 1; 133 else if (cmp > 0) 134 low = mid + 1; 135 else { 136 (void) (*NrReqt[mid].fun)(line, brk); 137 return; 138 } 139 } 140 /* 141 * Unknown request starting with a '.' or '\''.. 142 */ 143 Error(WARN, LINE, " unknown request", NULL); 144 } 145 146 147 /* 148 * Adjust - "^[.']ad" 149 */ 150 151 static void nr_ad(unsigned char *line, int brk) { 152 Pass3(NOBREAK, (unsigned char *)"both", NULL, 0); 153 } 154 155 156 /* 157 * Begin new page - "^[.']bp" 158 */ 159 160 static void nr_bp(unsigned char *line, int brk) { 161 Pass3(brk, (unsigned char *)"need", NULL, 999); 162 } 163 164 165 /* 166 * Break - "^[.']br" 167 */ 168 169 static void nr_br(unsigned char *line, int brk) { 170 Pass3(brk, (unsigned char *)"flush", NULL, 0); 171 } 172 173 174 /* 175 * Center - "^[.']ce" 176 */ 177 178 static void nr_ce(unsigned char *line, int brk) { 179 unsigned char *s; /* string poiner */ 180 181 if ((s = Field(2, line, 0)) != NULL) 182 Centering = atoi((char *)s); 183 else 184 Centering = 1; 185 } 186 187 188 /* 189 * Diversion on and off - "^[.']di" 190 */ 191 192 static void nr_di(unsigned char *line, int brk) { 193 Pass3(DOBREAK, (unsigned char *)"flush", NULL, 0); 194 Divert ^= 1; 195 } 196 197 198 /* 199 * Define string - "^[.']ds" 200 */ 201 202 static void nr_ds(unsigned char *line, int brk) { 203 unsigned char buf[MAXLINE]; /* temporary buffer */ 204 unsigned char nm[4], nm1[4]; /* name buffers */ 205 unsigned char *s1, *s2, *s3, /* temporary string pointers */ 206 *s4; 207 208 if (Asmname(&line[3], nm) == 0) { 209 Error(WARN, LINE, " no name", NULL); 210 return; 211 } 212 s1 = Field(3, line, 0); 213 s2 = Findstr(nm, s1, 1); 214 while (*s2 == '\\' && *(s2 + 1) == '*') { 215 s2++; 216 s3 = Asmcode(&s2, nm1); 217 s2 = Findstr(nm1, NULL, 0); 218 } 219 if (Hdft) { 220 221 /* 222 * Look for names LH, LF, CH, CF, RH, RF. 223 */ 224 if ((nm[0]=='L' || nm[0]=='C' || nm[0]=='R') 225 && (nm[1]=='F' || nm[1]=='H')) { 226 (void) sprintf((char *)buf, "%s", (char *)nm); 227 Pass3(NOBREAK, buf, s2, 0); 228 } 229 } 230 } 231 232 233 234 /* 235 * Fill - "^[.']fi" 236 */ 237 238 static void nr_fi(unsigned char *line, int brk) { 239 Fill = 1; 240 Pass3(brk, (unsigned char *)"flush", NULL, 0); 241 } 242 243 244 /* 245 * Flush - "^[.']fl" 246 */ 247 248 static void nr_fl(unsigned char *line, int brk) { 249 Pass3(brk, (unsigned char *)"flush", NULL, 0); 250 } 251 252 253 /* 254 * Font - "^[.']ft <font_name>" 255 */ 256 257 static void nr_ft(unsigned char *line, int brk) { 258 int i; /* temporary index */ 259 260 if (line[3] == '\0' || line[4] == '\0') 261 line[4] = 'P'; 262 if (line[4] == 'P') { 263 Font[0] = Prevfont; 264 return; 265 } 266 for (i = 0; Fcode[i].nm; i++) { 267 if (Fcode[i].nm == line[4]) 268 break; 269 } 270 if (Fcode[i].status == '\0') { 271 Error(WARN, LINE, " bad font code", NULL); 272 return; 273 } 274 Prevfont = Font[0]; 275 Font[0] = line[4]; 276 } 277 278 279 /* 280 * Input trap - "^[.']it [1 <request>]" 281 */ 282 283 static void nr_it(unsigned char *line, int brk) { 284 unsigned char buf[MAXLINE]; /* temporary buffer */ 285 int i; /* temporary index */ 286 unsigned char *s1, *s2; /* temporary string pointers */ 287 288 if ((s1 = Field(2, line, 0)) == NULL) { 289 Free(&Aftnxt); 290 return; 291 } 292 if ((i = atoi((char *)s1)) != 1) { 293 Error(WARN, LINE, " first .it arg must be 1", NULL); 294 return; 295 } 296 if ((s2 = Field(3, line, 0)) == NULL) 297 Free(&Aftnxt); 298 else { 299 (void) sprintf((char *)buf, "%s,%s", 300 (Aftnxt == NULL) ? "" : (char *)Aftnxt, 301 (char *)s2); 302 Free(&Aftnxt); 303 Aftnxt = Newstr(buf); 304 } 305 } 306 307 308 /* 309 * Comment - "^[.']\\" - do nothing 310 * 311 * Debug - "^[.']\^d" - do nothing 312 * 313 * Finalization - "[.']\^e" - do nothing 314 * 315 * Error file - "^[.']\^x <name>" - do nothing 316 * 317 * "^[.']i0", "^[.']lg" and "^[.']li" - do nothing 318 * 319 * Point size - "^[.']ps" - do nothing 320 * 321 * Vertical spacing - "^[.']vs" - do nothing 322 * 323 */ 324 325 static void nr_nil(unsigned char *line, int brk) { 326 } 327 328 329 /* 330 * No adjust "^[.']na" 331 */ 332 333 static void nr_na(unsigned char *line, int brk) { 334 Pass3(NOBREAK, (unsigned char *)"left", NULL, 0); 335 } 336 337 338 /* 339 * No fill - "^[.']nf" 340 */ 341 342 static void nr_nf(unsigned char *line, int brk) { 343 Fill = 0; 344 Pass3(brk, (unsigned char *)"flush", NULL, 0); 345 } 346 347 348 /* 349 * No space - "^[.']ns" 350 */ 351 352 static void nr_ns(unsigned char *line, int brk) { 353 Pass3(NOBREAK, (unsigned char *)"nospace", NULL, 0); 354 } 355 356 357 /* 358 * Remove macro or string - "^[.']rm" 359 */ 360 361 static void nr_rm(unsigned char *line, int brk) { 362 int i; /* temporary index */ 363 unsigned char nm[4]; /* name buffer */ 364 365 if (Asmname(&line[3], nm) == 0) { 366 Error(WARN, LINE, " no name", NULL); 367 return; 368 } 369 if ((i = Findmacro(nm, 0)) >= 0) { 370 Delmacro(i); 371 return; 372 } 373 (void) Findstr(nm, NULL, 0); 374 if (Sx >= 0) { 375 Delstr(Sx); 376 return; 377 } 378 Error(WARN, LINE, " no macro/string", NULL); 379 } 380 381 382 /* 383 * Rename macro or string - "^[.']rn" 384 */ 385 386 static void nr_rn(unsigned char *line, int brk) { 387 int i, j; /* temporary indexes */ 388 unsigned char nm[4], nm1[4]; /* name buffers */ 389 unsigned char *s1; /* temporary string pointer */ 390 391 if ((s1 = Field(2, line, 0)) == NULL || Asmname(s1, nm) == 0) { 392 Error(WARN, LINE, " no name", NULL); 393 return; 394 } 395 if ((s1 = Field(3, line, 0)) == NULL || Asmname(s1, nm1) == 0) { 396 Error(WARN, LINE, " no new name", NULL); 397 return; 398 } 399 if ((i = Findmacro(nm, 0)) >= 0) { 400 if ((j = Findmacro(nm1, 0)) >= 0) 401 Delmacro(j); 402 j = Findmacro(nm1, 1); 403 Macrotab[j].bx = Macrotab[i].bx; 404 Macrotab[i].bx = -1; 405 Macrotab[j].ct = Macrotab[i].ct; 406 Macrotab[i].ct = 0; 407 Delmacro(i); 408 return; 409 } 410 (void) Findstr(nm, NULL, 0); 411 if ((i = Sx) >= 0) { 412 (void) Findstr(nm1, Str[i].str, 1); 413 Delstr(i); 414 return; 415 } 416 if (Findmacro(nm1, 0) < 0) 417 (void) Findmacro(nm1, 1); 418 } 419 420 421 /* 422 * Remove register - "^[.']rr" 423 */ 424 425 static void nr_rr(unsigned char *line, int brk) { 426 int i; /* temporary index */ 427 unsigned char nm[4]; /* name buffer */ 428 429 if (Asmname(&line[3], nm) == 0) { 430 Error(WARN, LINE, " no name", NULL); 431 return; 432 } 433 if ((i = Findnum(nm, 0, 0)) < 0) { 434 Error(WARN, LINE, " no register", NULL); 435 return; 436 } 437 Delnum(i); 438 } 439 440 441 /* 442 * Resume space - "^[.']rs" 443 */ 444 445 static void nr_rs(unsigned char *line, int brk) { 446 Pass3(NOBREAK, (unsigned char *)"yesspace", NULL, 0); 447 } 448 449 450 /* 451 * Message - "^[.']tm" 452 */ 453 454 static void nr_tm(unsigned char *line, int brk) { 455 Pass3(MESSAGE, Inname, (line[3] == ' ') ? &line[4] : &line[3], NR); 456 } 457 458 459 /* 460 * Translate - "^[.']tr abcd..." 461 */ 462 463 static void nr_tr(unsigned char *line, int brk) { 464 unsigned char buf[MAXLINE]; /* temporary buffer */ 465 int i, j; /* temporary indexes */ 466 unsigned char nm[4], nm1[4]; /* name buffers */ 467 unsigned char *s1, *s2; /* temporary string pointers */ 468 int trin, trout; /* types: 0 = char; 1 = named char */ 469 unsigned char xbuf[MAXLINE]; /* temporary buffer */ 470 471 if (line[3] != ' ') { 472 Error(WARN, LINE, " unknown translation", NULL); 473 return; 474 } 475 for (s1 = &line[4]; *s1;) { 476 nm[1] = nm[2] = '\0'; 477 s2 = s1 + 1; 478 /* 479 * Assemble the input value. 480 */ 481 if (*s1 == '\\' && (*s2 == '*' || *s2 == '(')) { 482 if (*s2 == '(') { 483 /* 484 * Input is named character -- "\(xx". 485 */ 486 trin = 1; 487 s1 = s2 + 1; 488 if ((nm[0] = *s1) != '\0') { 489 s1++; 490 if ((nm[1] = *s1) != '\0') 491 s1++; 492 } 493 } else { 494 /* 495 * Input is interpolated string -- "\*x" or "\*(xx". 496 */ 497 s1 = Asmcode(&s2, nm); 498 if (*s1) 499 s1++; 500 s2 = Findstr(nm, NULL, 0); 501 if (*s2 != '\0') { 502 if ((strlen((char *)s2) + strlen((char *)s1) + 1) 503 >= MAXLINE) 504 Error(WARN, LINE, " string too long: ", (char *)nm); 505 else { 506 (void) sprintf((char *)buf, "%s%s", 507 (char *)s2, (char *)s1); 508 (void) strcpy((char *)xbuf, (char *)buf); 509 s1 = xbuf; 510 } 511 } 512 continue; 513 } 514 } else { 515 516 /* 517 * Input is a simple character. 518 */ 519 trin = 0; 520 if ((nm[0] = *s1) != '\0') 521 s1++; 522 } 523 /* 524 * Assemble the output value. 525 */ 526 527 assemble_output: 528 nm1[1] = nm1[2] = '\0'; 529 if (*s1 == '\0') { 530 531 /* 532 * Supply a space if there is no output character. 533 */ 534 trout = 0; 535 nm1[0] = ' '; 536 } else { 537 s2 = s1 + 1; 538 if (*s1 == '\\' && (*s2 == '(' || *s2 == '*')) { 539 if (*s2 == '(') { 540 /* 541 * The output is a named character -- "\(xx". 542 */ 543 trout = 1; 544 s1 = s2 + 1; 545 if ((nm1[0] = *s1) != '\0') { 546 s1++; 547 if ((nm1[1] = *s1) != '\0') 548 s1++; 549 } 550 } else { 551 /* 552 * The output is an interpolated string -- * "\*x" or "\*(xx". 553 */ 554 s1 = Asmcode(&s2, nm1); 555 if (*s1) 556 s1++; 557 s2 = Findstr(nm1, NULL, 0); 558 if (*s2 != '\0') { 559 /* 560 * Interpolate a string value. 561 */ 562 if ((strlen((char *)s2) + strlen((char *)s1) + 1) 563 >= MAXLINE) 564 Error(WARN, LINE, " string too long: ", 565 (char *)nm); 566 else { 567 (void) sprintf((char *)buf, "%s%s", (char *)s2, 568 (char *)s1); 569 (void) strcpy((char *)xbuf, (char *)buf); 570 s1 = xbuf; 571 } 572 } 573 goto assemble_output; 574 } 575 } else { 576 trout = 0; 577 if ((nm1[0] = *s1) != '0') 578 s1++; 579 else 580 nm1[0] = ' '; 581 } 582 } 583 /* 584 * Do the translation. 585 */ 586 switch (trin) { 587 588 case 0: /* simple char */ 589 switch (trout) { 590 591 case 0: /* to simple char */ 592 Trtbl[(int)nm[0]] = nm1[0]; 593 break; 594 case 1: /* to named char */ 595 if ((i = Findchar(nm1, 0, NULL, 0)) < 0 596 || strlen((char *)Schar[i].str) != 1) 597 Error(WARN, LINE, " bad named character: ", 598 (char *)nm1); 599 else 600 Trtbl[(int)nm[0]] = *(Schar[i].str); 601 break; 602 } 603 break; 604 case 1: /* named char */ 605 if ((i = Findchar(nm, 0, NULL, 0)) < 0) 606 Error(WARN, LINE, " unknown named character: ", (char *)nm); 607 else { 608 switch (trout) { 609 610 case 0: /* to simple char */ 611 Free(&Schar[i].str); 612 Schar[i].str = Newstr(nm1); 613 Schar[i].len = 1; 614 break; 615 case 1: /* to named char */ 616 if ((j = Findchar(nm1, 0, NULL, 0)) < 0) 617 Error(WARN, LINE, " unknown named character: ", 618 (char *)nm1); 619 else 620 (void) Findchar(nm, Schar[j].len, Schar[j].str, 1); 621 break; 622 } 623 } 624 break; 625 } 626 } 627 } 628 629 630 /* 631 * Initialization - "^[.']\^b (fh|HF|NH) [01]" 632 * 633 * fh = first page header status 634 * HF = header/footer status 635 * NH = initialize number headers 636 */ 637 638 static void nr_Ub(unsigned char *line, int brk) { 639 int i; /* temporary index */ 640 unsigned char *s1, *s2; /* temporary string pointers */ 641 642 if ((s1 = Field(2, line, 0)) == NULL) 643 return; 644 if ((s2 = Field(3, line, 0)) == NULL) 645 i = 0; 646 else 647 i = atoi((char *)s2); 648 if (s1[0] == 'f' && s1[1] == 'h') 649 Pass3(NOBREAK, (unsigned char *)"fph", NULL, i); 650 else if (s1[0] == 'H' && s1[1] == 'F') 651 Hdft = i; 652 else if (s1[0] == 'N' && s1[1] == 'H') { 653 for (i = 0; i < MAXNHNR; i++) 654 Nhnr[i] = 0; 655 } else 656 Error(WARN, LINE, " unknown initialization", NULL); 657 } 658 659 660 /* 661 * Character definitions - "^[.']\^c" 662 */ 663 664 static void nr_Uc(unsigned char *line, int brk) { 665 unsigned char buf[MAXLINE]; /* temporary buffer */ 666 int i; /* temporary index */ 667 unsigned char *s1, *s2, *s3, /* temporary string pointers */ 668 *s4, *s5; 669 670 s2 = Field(2, line, 0); 671 i = atoi((char *)Field(3, line, 0)); 672 s4 = Field(4, line, 0); 673 if (i < 0 || i > MAXLINE/2 || *s2 == '\0') { 674 Error(WARN, LINE, " bad character definition", NULL); 675 return; 676 } 677 if (s4 == NULL) 678 s4 = (unsigned char *)""; 679 else if (*s4 == '"') 680 s4++; 681 s1 = buf; 682 while ((s5 = (unsigned char *)strchr((char *)s4, '\\')) != NULL) { 683 while (s5 > s4) 684 *s1++ = *s4++; 685 s4 = ++s5; 686 if (*s5 == '\\') 687 *s1++ = '\\'; 688 else if (*s5 == 'b') 689 *s1++ = '\b'; 690 if (*s4) 691 s4++; 692 } 693 while ((*s1++ = *s4++)) 694 ; 695 if (*s2 == 'h' && *(s2+1) == 'y') 696 (void) Findhy(buf, i, 1); 697 else 698 (void) Findchar(s2, i, buf, 1); 699 } 700 701 702 /* 703 * Font is OK - "[.']\^f <font_name_character>" 704 */ 705 706 static void nr_Uf(unsigned char *line, int brk) { 707 int i; /* temporary index */ 708 709 if (line[3] != '\0' && line[4] != '\0') { 710 for (i = 0; Fcode[i].nm; i++) { 711 if (line[4] == Fcode[i].nm) { 712 Fcode[i].status = '1'; 713 return; 714 } 715 } 716 } 717 Error(WARN, LINE, " unknown font", NULL); 718 } 719 720 721 /* 722 * Resolutions - "[.']\^r cpi horizontal vertical" 723 */ 724 725 static void nr_Ur(unsigned char *line, int brk) { 726 unsigned char buf[MAXLINE]; /* temporary buffer */ 727 int i, j; /* temporary indexes */ 728 double tval; /* temporary value */ 729 730 if ((i = atoi((char *)Field(3, line, 0))) <= 0 731 || (j = atoi((char *)Field(4, line, 0))) <= 0) { 732 Error(WARN, LINE, " bad cpi resolutions", NULL); 733 return; 734 } 735 tval = (double) (240.0 / (double) i); 736 if (Findscale((int)'m', tval, 1) < 0) 737 Error(FATAL, LINE, " missing Scal['m']", NULL); 738 Scalen = tval; 739 if (Scalen <= 0.0) { 740 (void) sprintf((char *)buf, " bad Scale['n'] (%f)", Scalen); 741 Error(FATAL, LINE, (char *)buf, NULL); 742 } 743 if (Findscale((int)'n', tval, 1) < 0) 744 Error(FATAL, LINE, " missing Scale['n']", NULL); 745 Scalev = (double) (240.0 / (double) j); 746 if (Scalev <= 0.0) { 747 (void) sprintf((char *)buf, " bad Scale['v'] (%f)", Scalen); 748 Error(FATAL, LINE, (char *)buf, NULL); 749 } 750 if (Findscale((int)'v', Scalev, 1) < 0) 751 Error(FATAL, LINE, " missing Scale['v']", NULL); 752 } 753 754 755 /* 756 * Set line number and file name - "^[.']\^# <number> <file>" 757 * 758 * Lock line number and file name - "^[.']\^= <number> <file>" 759 */ 760 761 static void nr_UL(unsigned char *line, int brk) { 762 unsigned char *s1; /* temporary string pointer */ 763 764 if ((s1 = Field(2, line, 0)) != NULL) 765 P2il = atoi((char *)s1) - 1; 766 else 767 P2il = 0; 768 Lockil = (line[2] == '#') ? 0 : 1; 769 Free(&P2name); 770 if (Field(3, line, 1) != NULL) { 771 P2name = F; 772 F = NULL; 773 } else 774 P2name = NULL; 775 } 776