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: }