1 /* 2 * Copyright (c) 1980 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)vfontedpr.c 5.5 (Berkeley) 06/01/90"; 16 #endif /* not lint */ 17 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <ctype.h> 21 #include <stdio.h> 22 #include "pathnames.h" 23 24 #define boolean int 25 #define TRUE 1 26 #define FALSE 0 27 #define NIL 0 28 #define STANDARD 0 29 #define ALTERNATE 1 30 31 /* 32 * Vfontedpr. 33 * 34 * Dave Presotto 1/12/81 (adapted from an earlier version by Bill Joy) 35 * 36 */ 37 38 #define STRLEN 10 /* length of strings introducing things */ 39 #define PNAMELEN 40 /* length of a function/procedure name */ 40 #define PSMAX 20 /* size of procedure name stacking */ 41 42 /* regular expression routines */ 43 44 char *expmatch(); /* match a string to an expression */ 45 char *STRNCMP(); /* a different kindof strncmp */ 46 char *convexp(); /* convert expression to internal form */ 47 char *tgetstr(); 48 49 boolean isproc(); 50 51 52 char *ctime(); 53 54 /* 55 * The state variables 56 */ 57 58 boolean incomm; /* in a comment of the primary type */ 59 boolean instr; /* in a string constant */ 60 boolean inchr; /* in a string constant */ 61 boolean nokeyw = FALSE; /* no keywords being flagged */ 62 boolean index = FALSE; /* form an index */ 63 boolean filter = FALSE; /* act as a filter (like eqn) */ 64 boolean pass = FALSE; /* when acting as a filter, pass indicates 65 * whether we are currently processing 66 * input. 67 */ 68 boolean prccont; /* continue last procedure */ 69 int comtype; /* type of comment */ 70 int margin; 71 int psptr; /* the stack index of the current procedure */ 72 char pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */ 73 int plstack[PSMAX]; /* the procedure nesting level stack */ 74 int blklevel; /* current nesting level */ 75 char *defsfile = _PATH_VGRINDEFS; /* name of language definitions file */ 76 char pname[BUFSIZ+1]; 77 78 /* 79 * The language specific globals 80 */ 81 82 char *language = "c"; /* the language indicator */ 83 char *l_keywds[BUFSIZ/2]; /* keyword table address */ 84 char *l_prcbeg; /* regular expr for procedure begin */ 85 char *l_combeg; /* string introducing a comment */ 86 char *l_comend; /* string ending a comment */ 87 char *l_acmbeg; /* string introducing a comment */ 88 char *l_acmend; /* string ending a comment */ 89 char *l_blkbeg; /* string begining of a block */ 90 char *l_blkend; /* string ending a block */ 91 char *l_strbeg; /* delimiter for string constant */ 92 char *l_strend; /* delimiter for string constant */ 93 char *l_chrbeg; /* delimiter for character constant */ 94 char *l_chrend; /* delimiter for character constant */ 95 char l_escape; /* character used to escape characters */ 96 boolean l_toplex; /* procedures only defined at top lex level */ 97 98 /* 99 * global variables also used by expmatch 100 */ 101 boolean _escaped; /* if last character was an escape */ 102 char *_start; /* start of the current string */ 103 boolean l_onecase; /* upper and lower case are equivalent */ 104 105 #define ps(x) printf("%s", x) 106 107 main(argc, argv) 108 int argc; 109 char *argv[]; 110 { 111 int lineno; 112 char *fname = ""; 113 char *ptr; 114 struct stat stbuf; 115 char buf[BUFSIZ]; 116 char strings[2 * BUFSIZ]; 117 char defs[2 * BUFSIZ]; 118 int needbp = 0; 119 120 argc--, argv++; 121 do { 122 char *cp; 123 int i; 124 125 if (argc > 0) { 126 if (!strcmp(argv[0], "-h")) { 127 if (argc == 1) { 128 printf("'ds =H\n"); 129 argc = 0; 130 goto rest; 131 } 132 printf("'ds =H %s\n", argv[1]); 133 argc--, argv++; 134 argc--, argv++; 135 if (argc > 0) 136 continue; 137 goto rest; 138 } 139 140 /* act as a filter like eqn */ 141 if (!strcmp(argv[0], "-f")) { 142 filter++; 143 argv[0] = argv[argc-1]; 144 argv[argc-1] = "-"; 145 continue; 146 } 147 148 /* take input from the standard place */ 149 if (!strcmp(argv[0], "-")) { 150 argc = 0; 151 goto rest; 152 } 153 154 /* build an index */ 155 if (!strcmp(argv[0], "-x")) { 156 index++; 157 argv[0] = "-n"; 158 } 159 160 /* indicate no keywords */ 161 if (!strcmp(argv[0], "-n")) { 162 nokeyw++; 163 argc--, argv++; 164 continue; 165 } 166 167 /* specify the font size */ 168 if (!strncmp(argv[0], "-s", 2)) { 169 i = 0; 170 cp = argv[0] + 2; 171 while (*cp) 172 i = i * 10 + (*cp++ - '0'); 173 printf("'ps %d\n'vs %d\n", i, i+1); 174 argc--, argv++; 175 continue; 176 } 177 178 /* specify the language */ 179 if (!strncmp(argv[0], "-l", 2)) { 180 language = argv[0]+2; 181 argc--, argv++; 182 continue; 183 } 184 185 /* specify the language description file */ 186 if (!strncmp(argv[0], "-d", 2)) { 187 defsfile = argv[1]; 188 argc--, argv++; 189 argc--, argv++; 190 continue; 191 } 192 193 /* open the file for input */ 194 if (freopen(argv[0], "r", stdin) == NULL) { 195 perror(argv[0]); 196 exit(1); 197 } 198 if (index) 199 printf("'ta 4i 4.25i 5.5iR\n'in .5i\n"); 200 fname = argv[0]; 201 argc--, argv++; 202 } 203 rest: 204 205 /* 206 * get the language definition from the defs file 207 */ 208 i = tgetent (defs, language, defsfile); 209 if (i == 0) { 210 fprintf (stderr, "no entry for language %s\n", language); 211 exit (0); 212 } else if (i < 0) { 213 fprintf (stderr, "cannot find vgrindefs file %s\n", defsfile); 214 exit (0); 215 } 216 cp = strings; 217 if (tgetstr ("kw", &cp) == NIL) 218 nokeyw = TRUE; 219 else { 220 char **cpp; 221 222 cpp = l_keywds; 223 cp = strings; 224 while (*cp) { 225 while (*cp == ' ' || *cp =='\t') 226 *cp++ = NULL; 227 if (*cp) 228 *cpp++ = cp; 229 while (*cp != ' ' && *cp != '\t' && *cp) 230 cp++; 231 } 232 *cpp = NIL; 233 } 234 cp = buf; 235 l_prcbeg = convexp (tgetstr ("pb", &cp)); 236 cp = buf; 237 l_combeg = convexp (tgetstr ("cb", &cp)); 238 cp = buf; 239 l_comend = convexp (tgetstr ("ce", &cp)); 240 cp = buf; 241 l_acmbeg = convexp (tgetstr ("ab", &cp)); 242 cp = buf; 243 l_acmend = convexp (tgetstr ("ae", &cp)); 244 cp = buf; 245 l_strbeg = convexp (tgetstr ("sb", &cp)); 246 cp = buf; 247 l_strend = convexp (tgetstr ("se", &cp)); 248 cp = buf; 249 l_blkbeg = convexp (tgetstr ("bb", &cp)); 250 cp = buf; 251 l_blkend = convexp (tgetstr ("be", &cp)); 252 cp = buf; 253 l_chrbeg = convexp (tgetstr ("lb", &cp)); 254 cp = buf; 255 l_chrend = convexp (tgetstr ("le", &cp)); 256 l_escape = '\\'; 257 l_onecase = tgetflag ("oc"); 258 l_toplex = tgetflag ("tl"); 259 260 /* initialize the program */ 261 262 incomm = FALSE; 263 instr = FALSE; 264 inchr = FALSE; 265 _escaped = FALSE; 266 blklevel = 0; 267 for (psptr=0; psptr<PSMAX; psptr++) { 268 pstack[psptr][0] = NULL; 269 plstack[psptr] = 0; 270 } 271 psptr = -1; 272 ps("'-F\n"); 273 if (!filter) { 274 printf(".ds =F %s\n", fname); 275 ps("'wh 0 vH\n"); 276 ps("'wh -1i vF\n"); 277 } 278 if (needbp) { 279 needbp = 0; 280 printf(".()\n"); 281 printf(".bp\n"); 282 } 283 if (!filter) { 284 fstat(fileno(stdin), &stbuf); 285 cp = ctime(&stbuf.st_mtime); 286 cp[16] = '\0'; 287 cp[24] = '\0'; 288 printf(".ds =M %s %s\n", cp+4, cp+20); 289 } 290 291 /* 292 * MAIN LOOP!!! 293 */ 294 while (fgets(buf, sizeof buf, stdin) != NULL) { 295 if (buf[0] == '\f') { 296 printf(".bp\n"); 297 } 298 if (buf[0] == '.') { 299 printf("%s", buf); 300 if (!strncmp (buf+1, "vS", 2)) 301 pass = TRUE; 302 if (!strncmp (buf+1, "vE", 2)) 303 pass = FALSE; 304 continue; 305 } 306 prccont = FALSE; 307 if (!filter || pass) 308 putScp(buf); 309 else 310 printf("%s", buf); 311 if (prccont && (psptr >= 0)) { 312 ps("'FC "); 313 ps(pstack[psptr]); 314 ps("\n"); 315 } 316 #ifdef DEBUG 317 printf ("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr); 318 #endif 319 margin = 0; 320 } 321 needbp = 1; 322 } while (argc > 0); 323 exit(0); 324 } 325 326 #define isidchr(c) (isalnum(c) || (c) == '_') 327 328 putScp(os) 329 char *os; 330 { 331 register char *s = os; /* pointer to unmatched string */ 332 char dummy[BUFSIZ]; /* dummy to be used by expmatch */ 333 char *comptr; /* end of a comment delimiter */ 334 char *acmptr; /* end of a comment delimiter */ 335 char *strptr; /* end of a string delimiter */ 336 char *chrptr; /* end of a character const delimiter */ 337 char *blksptr; /* end of a lexical block start */ 338 char *blkeptr; /* end of a lexical block end */ 339 340 _start = os; /* remember the start for expmatch */ 341 _escaped = FALSE; 342 if (nokeyw || incomm || instr) 343 goto skip; 344 if (isproc(s)) { 345 ps("'FN "); 346 ps(pname); 347 ps("\n"); 348 if (psptr < PSMAX) { 349 ++psptr; 350 strncpy (pstack[psptr], pname, PNAMELEN); 351 pstack[psptr][PNAMELEN] = NULL; 352 plstack[psptr] = blklevel; 353 } 354 } 355 skip: 356 do { 357 /* check for string, comment, blockstart, etc */ 358 if (!incomm && !instr && !inchr) { 359 360 blkeptr = expmatch (s, l_blkend, dummy); 361 blksptr = expmatch (s, l_blkbeg, dummy); 362 comptr = expmatch (s, l_combeg, dummy); 363 acmptr = expmatch (s, l_acmbeg, dummy); 364 strptr = expmatch (s, l_strbeg, dummy); 365 chrptr = expmatch (s, l_chrbeg, dummy); 366 367 /* start of a comment? */ 368 if (comptr != NIL) 369 if ((comptr < strptr || strptr == NIL) 370 && (comptr < acmptr || acmptr == NIL) 371 && (comptr < chrptr || chrptr == NIL) 372 && (comptr < blksptr || blksptr == NIL) 373 && (comptr < blkeptr || blkeptr == NIL)) { 374 putKcp (s, comptr-1, FALSE); 375 s = comptr; 376 incomm = TRUE; 377 comtype = STANDARD; 378 if (s != os) 379 ps ("\\c"); 380 ps ("\\c\n'+C\n"); 381 continue; 382 } 383 384 /* start of a comment? */ 385 if (acmptr != NIL) 386 if ((acmptr < strptr || strptr == NIL) 387 && (acmptr < chrptr || chrptr == NIL) 388 && (acmptr < blksptr || blksptr == NIL) 389 && (acmptr < blkeptr || blkeptr == NIL)) { 390 putKcp (s, acmptr-1, FALSE); 391 s = acmptr; 392 incomm = TRUE; 393 comtype = ALTERNATE; 394 if (s != os) 395 ps ("\\c"); 396 ps ("\\c\n'+C\n"); 397 continue; 398 } 399 400 /* start of a string? */ 401 if (strptr != NIL) 402 if ((strptr < chrptr || chrptr == NIL) 403 && (strptr < blksptr || blksptr == NIL) 404 && (strptr < blkeptr || blkeptr == NIL)) { 405 putKcp (s, strptr-1, FALSE); 406 s = strptr; 407 instr = TRUE; 408 continue; 409 } 410 411 /* start of a character string? */ 412 if (chrptr != NIL) 413 if ((chrptr < blksptr || blksptr == NIL) 414 && (chrptr < blkeptr || blkeptr == NIL)) { 415 putKcp (s, chrptr-1, FALSE); 416 s = chrptr; 417 inchr = TRUE; 418 continue; 419 } 420 421 /* end of a lexical block */ 422 if (blkeptr != NIL) { 423 if (blkeptr < blksptr || blksptr == NIL) { 424 putKcp (s, blkeptr - 1, FALSE); 425 s = blkeptr; 426 blklevel--; 427 if (psptr >= 0 && plstack[psptr] >= blklevel) { 428 429 /* end of current procedure */ 430 if (s != os) 431 ps ("\\c"); 432 ps ("\\c\n'-F\n"); 433 blklevel = plstack[psptr]; 434 435 /* see if we should print the last proc name */ 436 if (--psptr >= 0) 437 prccont = TRUE; 438 else 439 psptr = -1; 440 } 441 continue; 442 } 443 } 444 445 /* start of a lexical block */ 446 if (blksptr != NIL) { 447 putKcp (s, blksptr - 1, FALSE); 448 s = blksptr; 449 blklevel++; 450 continue; 451 } 452 453 /* check for end of comment */ 454 } else if (incomm) { 455 comptr = expmatch (s, l_comend, dummy); 456 acmptr = expmatch (s, l_acmend, dummy); 457 if (((comtype == STANDARD) && (comptr != NIL)) || 458 ((comtype == ALTERNATE) && (acmptr != NIL))) { 459 if (comtype == STANDARD) { 460 putKcp (s, comptr-1, TRUE); 461 s = comptr; 462 } else { 463 putKcp (s, acmptr-1, TRUE); 464 s = acmptr; 465 } 466 incomm = FALSE; 467 ps("\\c\n'-C\n"); 468 continue; 469 } else { 470 putKcp (s, s + strlen(s) -1, TRUE); 471 s = s + strlen(s); 472 continue; 473 } 474 475 /* check for end of string */ 476 } else if (instr) { 477 if ((strptr = expmatch (s, l_strend, dummy)) != NIL) { 478 putKcp (s, strptr-1, TRUE); 479 s = strptr; 480 instr = FALSE; 481 continue; 482 } else { 483 putKcp (s, s+strlen(s)-1, TRUE); 484 s = s + strlen(s); 485 continue; 486 } 487 488 /* check for end of character string */ 489 } else if (inchr) { 490 if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) { 491 putKcp (s, chrptr-1, TRUE); 492 s = chrptr; 493 inchr = FALSE; 494 continue; 495 } else { 496 putKcp (s, s+strlen(s)-1, TRUE); 497 s = s + strlen(s); 498 continue; 499 } 500 } 501 502 /* print out the line */ 503 putKcp (s, s + strlen(s) -1, FALSE); 504 s = s + strlen(s); 505 } while (*s); 506 } 507 508 putKcp (start, end, force) 509 char *start; /* start of string to write */ 510 char *end; /* end of string to write */ 511 boolean force; /* true if we should force nokeyw */ 512 { 513 int i; 514 int xfld = 0; 515 516 while (start <= end) { 517 if (index) { 518 if (*start == ' ' || *start == '\t') { 519 if (xfld == 0) 520 printf(""); 521 printf("\t"); 522 xfld = 1; 523 while (*start == ' ' || *start == '\t') 524 start++; 525 continue; 526 } 527 } 528 529 /* take care of nice tab stops */ 530 if (*start == '\t') { 531 while (*start == '\t') 532 start++; 533 i = tabs(_start, start) - margin / 8; 534 printf("\\h'|%dn'", i * 10 + 1 - margin % 8); 535 continue; 536 } 537 538 if (!nokeyw && !force) 539 if ((*start == '#' || isidchr(*start)) 540 && (start == _start || !isidchr(start[-1]))) { 541 i = iskw(start); 542 if (i > 0) { 543 ps("\\*(+K"); 544 do 545 putcp(*start++); 546 while (--i > 0); 547 ps("\\*(-K"); 548 continue; 549 } 550 } 551 552 putcp (*start++); 553 } 554 } 555 556 557 tabs(s, os) 558 char *s, *os; 559 { 560 561 return (width(s, os) / 8); 562 } 563 564 width(s, os) 565 register char *s, *os; 566 { 567 register int i = 0; 568 569 while (s < os) { 570 if (*s == '\t') { 571 i = (i + 8) &~ 7; 572 s++; 573 continue; 574 } 575 if (*s < ' ') 576 i += 2; 577 else 578 i++; 579 s++; 580 } 581 return (i); 582 } 583 584 putcp(c) 585 register int c; 586 { 587 588 switch(c) { 589 590 case 0: 591 break; 592 593 case '\f': 594 break; 595 596 case '{': 597 ps("\\*(+K{\\*(-K"); 598 break; 599 600 case '}': 601 ps("\\*(+K}\\*(-K"); 602 break; 603 604 case '\\': 605 ps("\\e"); 606 break; 607 608 case '_': 609 ps("\\*_"); 610 break; 611 612 case '-': 613 ps("\\*-"); 614 break; 615 616 case '`': 617 ps("\\`"); 618 break; 619 620 case '\'': 621 ps("\\'"); 622 break; 623 624 case '.': 625 ps("\\&."); 626 break; 627 628 case '*': 629 ps("\\fI*\\fP"); 630 break; 631 632 case '/': 633 ps("\\fI\\h'\\w' 'u-\\w'/'u'/\\fP"); 634 break; 635 636 default: 637 if (c < 040) 638 putchar('^'), c |= '@'; 639 case '\t': 640 case '\n': 641 putchar(c); 642 } 643 } 644 645 /* 646 * look for a process beginning on this line 647 */ 648 boolean 649 isproc(s) 650 char *s; 651 { 652 pname[0] = NULL; 653 if (!l_toplex || blklevel == 0) 654 if (expmatch (s, l_prcbeg, pname) != NIL) { 655 return (TRUE); 656 } 657 return (FALSE); 658 } 659 660 661 /* iskw - check to see if the next word is a keyword 662 */ 663 664 iskw(s) 665 register char *s; 666 { 667 register char **ss = l_keywds; 668 register int i = 1; 669 register char *cp = s; 670 671 while (++cp, isidchr(*cp)) 672 i++; 673 while (cp = *ss++) 674 if (!STRNCMP(s,cp,i) && !isidchr(cp[i])) 675 return (i); 676 return (0); 677 } 678