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