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