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_prcbeg; /* regular expr for procedure begin */ 121 char *l_strbeg; /* delimiter for string constant */ 122 char *l_strend; /* delimiter for string constant */ 123 boolean l_toplex; /* procedures only defined at top lex level */ 124 char *language = "c"; /* the language indicator */ 125 126 #define ps(x) printf("%s", x) 127 128 void 129 main(argc, argv) 130 int argc; 131 char *argv[]; 132 { 133 char *fname = ""; 134 struct stat stbuf; 135 char buf[BUFSIZ]; 136 char *defs; 137 int needbp = 0; 138 139 argc--, argv++; 140 do { 141 char *cp; 142 int i; 143 144 if (argc > 0) { 145 if (!strcmp(argv[0], "-h")) { 146 if (argc == 1) { 147 printf("'ds =H\n"); 148 argc = 0; 149 goto rest; 150 } 151 printf("'ds =H %s\n", argv[1]); 152 argc--, argv++; 153 argc--, argv++; 154 if (argc > 0) 155 continue; 156 goto rest; 157 } 158 159 /* act as a filter like eqn */ 160 if (!strcmp(argv[0], "-f")) { 161 filter++; 162 argv[0] = argv[argc-1]; 163 argv[argc-1] = "-"; 164 continue; 165 } 166 167 /* take input from the standard place */ 168 if (!strcmp(argv[0], "-")) { 169 argc = 0; 170 goto rest; 171 } 172 173 /* build an index */ 174 if (!strcmp(argv[0], "-x")) { 175 idx++; 176 argv[0] = "-n"; 177 } 178 179 /* indicate no keywords */ 180 if (!strcmp(argv[0], "-n")) { 181 nokeyw++; 182 argc--, argv++; 183 continue; 184 } 185 186 /* specify the font size */ 187 if (!strncmp(argv[0], "-s", 2)) { 188 i = 0; 189 cp = argv[0] + 2; 190 while (*cp) 191 i = i * 10 + (*cp++ - '0'); 192 printf("'ps %d\n'vs %d\n", i, i+1); 193 argc--, argv++; 194 continue; 195 } 196 197 /* specify the language */ 198 if (!strncmp(argv[0], "-l", 2)) { 199 language = argv[0]+2; 200 argc--, argv++; 201 continue; 202 } 203 204 /* specify the language description file */ 205 if (!strncmp(argv[0], "-d", 2)) { 206 defsfile[0] = argv[1]; 207 argc--, argv++; 208 argc--, argv++; 209 continue; 210 } 211 212 /* open the file for input */ 213 if (freopen(argv[0], "r", stdin) == NULL) { 214 perror(argv[0]); 215 exit(1); 216 } 217 if (idx) 218 printf("'ta 4i 4.25i 5.5iR\n'in .5i\n"); 219 fname = argv[0]; 220 argc--, argv++; 221 } 222 rest: 223 224 /* 225 * get the language definition from the defs file 226 */ 227 i = cgetent(&defs, defsfile, language); 228 if (i == -1) { 229 fprintf (stderr, "no entry for language %s\n", language); 230 exit (0); 231 } else if (i == -2) { fprintf(stderr, 232 "cannot find vgrindefs file %s\n", defsfile[0]); 233 exit (0); 234 } else if (i == -3) { fprintf(stderr, 235 "potential reference loop detected in vgrindefs file %s\n", 236 defsfile[0]); 237 exit(0); 238 } 239 if (cgetustr(defs, "kw", &cp) == -1) 240 nokeyw = TRUE; 241 else { 242 char **cpp; 243 244 cpp = l_keywds; 245 while (*cp) { 246 while (*cp == ' ' || *cp =='\t') 247 *cp++ = NULL; 248 if (*cp) 249 *cpp++ = cp; 250 while (*cp != ' ' && *cp != '\t' && *cp) 251 cp++; 252 } 253 *cpp = NIL; 254 } 255 cgetustr(defs, "pb", &cp); 256 l_prcbeg = convexp(cp); 257 cgetustr(defs, "cb", &cp); 258 l_combeg = convexp(cp); 259 cgetustr(defs, "ce", &cp); 260 l_comend = convexp(cp); 261 cgetustr(defs, "ab", &cp); 262 l_acmbeg = convexp(cp); 263 cgetustr(defs, "ae", &cp); 264 l_acmend = convexp(cp); 265 cgetustr(defs, "sb", &cp); 266 l_strbeg = convexp(cp); 267 cgetustr(defs, "se", &cp); 268 l_strend = convexp(cp); 269 cgetustr(defs, "bb", &cp); 270 l_blkbeg = convexp(cp); 271 cgetustr(defs, "be", &cp); 272 l_blkend = convexp(cp); 273 cgetustr(defs, "lb", &cp); 274 l_chrbeg = convexp(cp); 275 cgetustr(defs, "le", &cp); 276 l_chrend = convexp(cp); 277 l_escape = '\\'; 278 l_onecase = (cgetcap(defs, "oc", ':') != NULL); 279 l_toplex = (cgetcap(defs, "tl", ':') != NULL); 280 281 /* initialize the program */ 282 283 incomm = FALSE; 284 instr = FALSE; 285 inchr = FALSE; 286 _escaped = FALSE; 287 blklevel = 0; 288 for (psptr=0; psptr<PSMAX; psptr++) { 289 pstack[psptr][0] = NULL; 290 plstack[psptr] = 0; 291 } 292 psptr = -1; 293 ps("'-F\n"); 294 if (!filter) { 295 printf(".ds =F %s\n", fname); 296 ps("'wh 0 vH\n"); 297 ps("'wh -1i vF\n"); 298 } 299 if (needbp) { 300 needbp = 0; 301 printf(".()\n"); 302 printf(".bp\n"); 303 } 304 if (!filter) { 305 fstat(fileno(stdin), &stbuf); 306 cp = ctime(&stbuf.st_mtime); 307 cp[16] = '\0'; 308 cp[24] = '\0'; 309 printf(".ds =M %s %s\n", cp+4, cp+20); 310 } 311 312 /* 313 * MAIN LOOP!!! 314 */ 315 while (fgets(buf, sizeof buf, stdin) != NULL) { 316 if (buf[0] == '\f') { 317 printf(".bp\n"); 318 } 319 if (buf[0] == '.') { 320 printf("%s", buf); 321 if (!strncmp (buf+1, "vS", 2)) 322 pass = TRUE; 323 if (!strncmp (buf+1, "vE", 2)) 324 pass = FALSE; 325 continue; 326 } 327 prccont = FALSE; 328 if (!filter || pass) 329 putScp(buf); 330 else 331 printf("%s", buf); 332 if (prccont && (psptr >= 0)) { 333 ps("'FC "); 334 ps(pstack[psptr]); 335 ps("\n"); 336 } 337 #ifdef DEBUG 338 printf ("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr); 339 #endif 340 margin = 0; 341 } 342 needbp = 1; 343 } while (argc > 0); 344 exit(0); 345 } 346 347 #define isidchr(c) (isalnum(c) || (c) == '_') 348 349 static void 350 putScp(os) 351 char *os; 352 { 353 register char *s = os; /* pointer to unmatched string */ 354 char dummy[BUFSIZ]; /* dummy to be used by expmatch */ 355 char *comptr; /* end of a comment delimiter */ 356 char *acmptr; /* end of a comment delimiter */ 357 char *strptr; /* end of a string delimiter */ 358 char *chrptr; /* end of a character const delimiter */ 359 char *blksptr; /* end of a lexical block start */ 360 char *blkeptr; /* end of a lexical block end */ 361 362 _start = os; /* remember the start for expmatch */ 363 _escaped = FALSE; 364 if (nokeyw || incomm || instr) 365 goto skip; 366 if (isproc(s)) { 367 ps("'FN "); 368 ps(pname); 369 ps("\n"); 370 if (psptr < PSMAX) { 371 ++psptr; 372 strncpy (pstack[psptr], pname, PNAMELEN); 373 pstack[psptr][PNAMELEN] = NULL; 374 plstack[psptr] = blklevel; 375 } 376 } 377 skip: 378 do { 379 /* check for string, comment, blockstart, etc */ 380 if (!incomm && !instr && !inchr) { 381 382 blkeptr = expmatch (s, l_blkend, dummy); 383 blksptr = expmatch (s, l_blkbeg, dummy); 384 comptr = expmatch (s, l_combeg, dummy); 385 acmptr = expmatch (s, l_acmbeg, dummy); 386 strptr = expmatch (s, l_strbeg, dummy); 387 chrptr = expmatch (s, l_chrbeg, dummy); 388 389 /* start of a comment? */ 390 if (comptr != NIL) 391 if ((comptr < strptr || strptr == NIL) 392 && (comptr < acmptr || acmptr == NIL) 393 && (comptr < chrptr || chrptr == NIL) 394 && (comptr < blksptr || blksptr == NIL) 395 && (comptr < blkeptr || blkeptr == NIL)) { 396 putKcp (s, comptr-1, FALSE); 397 s = comptr; 398 incomm = TRUE; 399 comtype = STANDARD; 400 if (s != os) 401 ps ("\\c"); 402 ps ("\\c\n'+C\n"); 403 continue; 404 } 405 406 /* start of a comment? */ 407 if (acmptr != NIL) 408 if ((acmptr < strptr || strptr == NIL) 409 && (acmptr < chrptr || chrptr == NIL) 410 && (acmptr < blksptr || blksptr == NIL) 411 && (acmptr < blkeptr || blkeptr == NIL)) { 412 putKcp (s, acmptr-1, FALSE); 413 s = acmptr; 414 incomm = TRUE; 415 comtype = ALTERNATE; 416 if (s != os) 417 ps ("\\c"); 418 ps ("\\c\n'+C\n"); 419 continue; 420 } 421 422 /* start of a string? */ 423 if (strptr != NIL) 424 if ((strptr < chrptr || chrptr == NIL) 425 && (strptr < blksptr || blksptr == NIL) 426 && (strptr < blkeptr || blkeptr == NIL)) { 427 putKcp (s, strptr-1, FALSE); 428 s = strptr; 429 instr = TRUE; 430 continue; 431 } 432 433 /* start of a character string? */ 434 if (chrptr != NIL) 435 if ((chrptr < blksptr || blksptr == NIL) 436 && (chrptr < blkeptr || blkeptr == NIL)) { 437 putKcp (s, chrptr-1, FALSE); 438 s = chrptr; 439 inchr = TRUE; 440 continue; 441 } 442 443 /* end of a lexical block */ 444 if (blkeptr != NIL) { 445 if (blkeptr < blksptr || blksptr == NIL) { 446 putKcp (s, blkeptr - 1, FALSE); 447 s = blkeptr; 448 blklevel--; 449 if (psptr >= 0 && plstack[psptr] >= blklevel) { 450 451 /* end of current procedure */ 452 if (s != os) 453 ps ("\\c"); 454 ps ("\\c\n'-F\n"); 455 blklevel = plstack[psptr]; 456 457 /* see if we should print the last proc name */ 458 if (--psptr >= 0) 459 prccont = TRUE; 460 else 461 psptr = -1; 462 } 463 continue; 464 } 465 } 466 467 /* start of a lexical block */ 468 if (blksptr != NIL) { 469 putKcp (s, blksptr - 1, FALSE); 470 s = blksptr; 471 blklevel++; 472 continue; 473 } 474 475 /* check for end of comment */ 476 } else if (incomm) { 477 comptr = expmatch (s, l_comend, dummy); 478 acmptr = expmatch (s, l_acmend, dummy); 479 if (((comtype == STANDARD) && (comptr != NIL)) || 480 ((comtype == ALTERNATE) && (acmptr != NIL))) { 481 if (comtype == STANDARD) { 482 putKcp (s, comptr-1, TRUE); 483 s = comptr; 484 } else { 485 putKcp (s, acmptr-1, TRUE); 486 s = acmptr; 487 } 488 incomm = FALSE; 489 ps("\\c\n'-C\n"); 490 continue; 491 } else { 492 putKcp (s, s + strlen(s) -1, TRUE); 493 s = s + strlen(s); 494 continue; 495 } 496 497 /* check for end of string */ 498 } else if (instr) { 499 if ((strptr = expmatch (s, l_strend, dummy)) != NIL) { 500 putKcp (s, strptr-1, TRUE); 501 s = strptr; 502 instr = FALSE; 503 continue; 504 } else { 505 putKcp (s, s+strlen(s)-1, TRUE); 506 s = s + strlen(s); 507 continue; 508 } 509 510 /* check for end of character string */ 511 } else if (inchr) { 512 if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) { 513 putKcp (s, chrptr-1, TRUE); 514 s = chrptr; 515 inchr = FALSE; 516 continue; 517 } else { 518 putKcp (s, s+strlen(s)-1, TRUE); 519 s = s + strlen(s); 520 continue; 521 } 522 } 523 524 /* print out the line */ 525 putKcp (s, s + strlen(s) -1, FALSE); 526 s = s + strlen(s); 527 } while (*s); 528 } 529 530 static void 531 putKcp (start, end, force) 532 char *start; /* start of string to write */ 533 char *end; /* end of string to write */ 534 boolean force; /* true if we should force nokeyw */ 535 { 536 int i; 537 int xfld = 0; 538 539 while (start <= end) { 540 if (idx) { 541 if (*start == ' ' || *start == '\t') { 542 if (xfld == 0) 543 printf("\001"); 544 printf("\t"); 545 xfld = 1; 546 while (*start == ' ' || *start == '\t') 547 start++; 548 continue; 549 } 550 } 551 552 /* take care of nice tab stops */ 553 if (*start == '\t') { 554 while (*start == '\t') 555 start++; 556 i = tabs(_start, start) - margin / 8; 557 printf("\\h'|%dn'", i * 10 + 1 - margin % 8); 558 continue; 559 } 560 561 if (!nokeyw && !force) 562 if ((*start == '#' || isidchr(*start)) 563 && (start == _start || !isidchr(start[-1]))) { 564 i = iskw(start); 565 if (i > 0) { 566 ps("\\*(+K"); 567 do 568 putcp(*start++); 569 while (--i > 0); 570 ps("\\*(-K"); 571 continue; 572 } 573 } 574 575 putcp (*start++); 576 } 577 } 578 579 580 static int 581 tabs(s, os) 582 char *s, *os; 583 { 584 585 return (width(s, os) / 8); 586 } 587 588 static int 589 width(s, os) 590 register char *s, *os; 591 { 592 register int i = 0; 593 594 while (s < os) { 595 if (*s == '\t') { 596 i = (i + 8) &~ 7; 597 s++; 598 continue; 599 } 600 if (*s < ' ') 601 i += 2; 602 else 603 i++; 604 s++; 605 } 606 return (i); 607 } 608 609 static void 610 putcp(c) 611 register int c; 612 { 613 614 switch(c) { 615 616 case 0: 617 break; 618 619 case '\f': 620 break; 621 622 case '{': 623 ps("\\*(+K{\\*(-K"); 624 break; 625 626 case '}': 627 ps("\\*(+K}\\*(-K"); 628 break; 629 630 case '\\': 631 ps("\\e"); 632 break; 633 634 case '_': 635 ps("\\*_"); 636 break; 637 638 case '-': 639 ps("\\*-"); 640 break; 641 642 case '`': 643 ps("\\`"); 644 break; 645 646 case '\'': 647 ps("\\'"); 648 break; 649 650 case '.': 651 ps("\\&."); 652 break; 653 654 case '*': 655 ps("\\fI*\\fP"); 656 break; 657 658 case '/': 659 ps("\\fI\\h'\\w' 'u-\\w'/'u'/\\fP"); 660 break; 661 662 default: 663 if (c < 040) 664 putchar('^'), c |= '@'; 665 case '\t': 666 case '\n': 667 putchar(c); 668 } 669 } 670 671 /* 672 * look for a process beginning on this line 673 */ 674 static boolean 675 isproc(s) 676 char *s; 677 { 678 pname[0] = NULL; 679 if (!l_toplex || blklevel == 0) 680 if (expmatch (s, l_prcbeg, pname) != NIL) { 681 return (TRUE); 682 } 683 return (FALSE); 684 } 685 686 687 /* iskw - check to see if the next word is a keyword 688 */ 689 690 static int 691 iskw(s) 692 register char *s; 693 { 694 register char **ss = l_keywds; 695 register int i = 1; 696 register char *cp = s; 697 698 while (++cp, isidchr(*cp)) 699 i++; 700 while (cp = *ss++) 701 if (!STRNCMP(s,cp,i) && !isidchr(cp[i])) 702 return (i); 703 return (0); 704 } 705 706