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