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