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