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