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