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