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