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.2 (Berkeley) 07/17/86"; 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 ps("'wh 0 vH\n"); 268 ps("'wh -1i vF\n"); 269 } 270 if (needbp) { 271 needbp = 0; 272 printf(".()\n"); 273 printf(".bp\n"); 274 } 275 if (!filter) { 276 fstat(fileno(stdin), &stbuf); 277 cp = ctime(&stbuf.st_mtime); 278 cp[16] = '\0'; 279 cp[24] = '\0'; 280 printf(".ds =M %s %s\n", cp+4, cp+20); 281 } 282 283 /* 284 * MAIN LOOP!!! 285 */ 286 while (fgets(buf, sizeof buf, stdin) != NULL) { 287 if (buf[0] == '\f') { 288 printf(".bp\n"); 289 } 290 if (buf[0] == '.') { 291 printf("%s", buf); 292 if (!strncmp (buf+1, "vS", 2)) 293 pass = TRUE; 294 if (!strncmp (buf+1, "vE", 2)) 295 pass = FALSE; 296 continue; 297 } 298 prccont = FALSE; 299 if (!filter || pass) 300 putScp(buf); 301 else 302 printf("%s", buf); 303 if (prccont && (psptr >= 0)) { 304 ps("'FC "); 305 ps(pstack[psptr]); 306 ps("\n"); 307 } 308 #ifdef DEBUG 309 printf ("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr); 310 #endif 311 margin = 0; 312 } 313 needbp = 1; 314 } while (argc > 0); 315 exit(0); 316 } 317 318 #define isidchr(c) (isalnum(c) || (c) == '_') 319 320 putScp(os) 321 char *os; 322 { 323 register char *s = os; /* pointer to unmatched string */ 324 char dummy[BUFSIZ]; /* dummy to be used by expmatch */ 325 char *comptr; /* end of a comment delimiter */ 326 char *acmptr; /* end of a comment delimiter */ 327 char *strptr; /* end of a string delimiter */ 328 char *chrptr; /* end of a character const delimiter */ 329 char *blksptr; /* end of a lexical block start */ 330 char *blkeptr; /* end of a lexical block end */ 331 332 _start = os; /* remember the start for expmatch */ 333 _escaped = FALSE; 334 if (nokeyw || incomm || instr) 335 goto skip; 336 if (isproc(s)) { 337 ps("'FN "); 338 ps(pname); 339 ps("\n"); 340 if (psptr < PSMAX) { 341 ++psptr; 342 strncpy (pstack[psptr], pname, PNAMELEN); 343 pstack[psptr][PNAMELEN] = NULL; 344 plstack[psptr] = blklevel; 345 } 346 } 347 skip: 348 do { 349 /* check for string, comment, blockstart, etc */ 350 if (!incomm && !instr && !inchr) { 351 352 blkeptr = expmatch (s, l_blkend, dummy); 353 blksptr = expmatch (s, l_blkbeg, dummy); 354 comptr = expmatch (s, l_combeg, dummy); 355 acmptr = expmatch (s, l_acmbeg, dummy); 356 strptr = expmatch (s, l_strbeg, dummy); 357 chrptr = expmatch (s, l_chrbeg, dummy); 358 359 /* start of a comment? */ 360 if (comptr != NIL) 361 if ((comptr < strptr || strptr == NIL) 362 && (comptr < acmptr || acmptr == NIL) 363 && (comptr < chrptr || chrptr == NIL) 364 && (comptr < blksptr || blksptr == NIL) 365 && (comptr < blkeptr || blkeptr == NIL)) { 366 putKcp (s, comptr-1, FALSE); 367 s = comptr; 368 incomm = TRUE; 369 comtype = STANDARD; 370 if (s != os) 371 ps ("\\c"); 372 ps ("\\c\n'+C\n"); 373 continue; 374 } 375 376 /* start of a comment? */ 377 if (acmptr != NIL) 378 if ((acmptr < strptr || strptr == NIL) 379 && (acmptr < chrptr || chrptr == NIL) 380 && (acmptr < blksptr || blksptr == NIL) 381 && (acmptr < blkeptr || blkeptr == NIL)) { 382 putKcp (s, acmptr-1, FALSE); 383 s = acmptr; 384 incomm = TRUE; 385 comtype = ALTERNATE; 386 if (s != os) 387 ps ("\\c"); 388 ps ("\\c\n'+C\n"); 389 continue; 390 } 391 392 /* start of a string? */ 393 if (strptr != NIL) 394 if ((strptr < chrptr || chrptr == NIL) 395 && (strptr < blksptr || blksptr == NIL) 396 && (strptr < blkeptr || blkeptr == NIL)) { 397 putKcp (s, strptr-1, FALSE); 398 s = strptr; 399 instr = TRUE; 400 continue; 401 } 402 403 /* start of a character string? */ 404 if (chrptr != NIL) 405 if ((chrptr < blksptr || blksptr == NIL) 406 && (chrptr < blkeptr || blkeptr == NIL)) { 407 putKcp (s, chrptr-1, FALSE); 408 s = chrptr; 409 inchr = TRUE; 410 continue; 411 } 412 413 /* end of a lexical block */ 414 if (blkeptr != NIL) { 415 if (blkeptr < blksptr || blksptr == NIL) { 416 putKcp (s, blkeptr - 1, FALSE); 417 s = blkeptr; 418 blklevel--; 419 if (psptr >= 0 && plstack[psptr] >= blklevel) { 420 421 /* end of current procedure */ 422 if (s != os) 423 ps ("\\c"); 424 ps ("\\c\n'-F\n"); 425 blklevel = plstack[psptr]; 426 427 /* see if we should print the last proc name */ 428 if (--psptr >= 0) 429 prccont = TRUE; 430 else 431 psptr = -1; 432 } 433 continue; 434 } 435 } 436 437 /* start of a lexical block */ 438 if (blksptr != NIL) { 439 putKcp (s, blksptr - 1, FALSE); 440 s = blksptr; 441 blklevel++; 442 continue; 443 } 444 445 /* check for end of comment */ 446 } else if (incomm) { 447 comptr = expmatch (s, l_comend, dummy); 448 acmptr = expmatch (s, l_acmend, dummy); 449 if (((comtype == STANDARD) && (comptr != NIL)) || 450 ((comtype == ALTERNATE) && (acmptr != NIL))) { 451 if (comtype == STANDARD) { 452 putKcp (s, comptr-1, TRUE); 453 s = comptr; 454 } else { 455 putKcp (s, acmptr-1, TRUE); 456 s = acmptr; 457 } 458 incomm = FALSE; 459 ps("\\c\n'-C\n"); 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 string */ 468 } else if (instr) { 469 if ((strptr = expmatch (s, l_strend, dummy)) != NIL) { 470 putKcp (s, strptr-1, TRUE); 471 s = strptr; 472 instr = FALSE; 473 continue; 474 } else { 475 putKcp (s, s+strlen(s)-1, TRUE); 476 s = s + strlen(s); 477 continue; 478 } 479 480 /* check for end of character string */ 481 } else if (inchr) { 482 if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) { 483 putKcp (s, chrptr-1, TRUE); 484 s = chrptr; 485 inchr = FALSE; 486 continue; 487 } else { 488 putKcp (s, s+strlen(s)-1, TRUE); 489 s = s + strlen(s); 490 continue; 491 } 492 } 493 494 /* print out the line */ 495 putKcp (s, s + strlen(s) -1, FALSE); 496 s = s + strlen(s); 497 } while (*s); 498 } 499 500 putKcp (start, end, force) 501 char *start; /* start of string to write */ 502 char *end; /* end of string to write */ 503 boolean force; /* true if we should force nokeyw */ 504 { 505 int i; 506 int xfld = 0; 507 508 while (start <= end) { 509 if (index) { 510 if (*start == ' ' || *start == '\t') { 511 if (xfld == 0) 512 printf(""); 513 printf("\t"); 514 xfld = 1; 515 while (*start == ' ' || *start == '\t') 516 start++; 517 continue; 518 } 519 } 520 521 /* take care of nice tab stops */ 522 if (*start == '\t') { 523 while (*start == '\t') 524 start++; 525 i = tabs(_start, start) - margin / 8; 526 printf("\\h'|%dn'", i * 10 + 1 - margin % 8); 527 continue; 528 } 529 530 if (!nokeyw && !force) 531 if ((*start == '#' || isidchr(*start)) 532 && (start == _start || !isidchr(start[-1]))) { 533 i = iskw(start); 534 if (i > 0) { 535 ps("\\*(+K"); 536 do 537 putcp(*start++); 538 while (--i > 0); 539 ps("\\*(-K"); 540 continue; 541 } 542 } 543 544 putcp (*start++); 545 } 546 } 547 548 549 tabs(s, os) 550 char *s, *os; 551 { 552 553 return (width(s, os) / 8); 554 } 555 556 width(s, os) 557 register char *s, *os; 558 { 559 register int i = 0; 560 561 while (s < os) { 562 if (*s == '\t') { 563 i = (i + 8) &~ 7; 564 s++; 565 continue; 566 } 567 if (*s < ' ') 568 i += 2; 569 else 570 i++; 571 s++; 572 } 573 return (i); 574 } 575 576 putcp(c) 577 register int c; 578 { 579 580 switch(c) { 581 582 case 0: 583 break; 584 585 case '\f': 586 break; 587 588 case '{': 589 ps("\\*(+K{\\*(-K"); 590 break; 591 592 case '}': 593 ps("\\*(+K}\\*(-K"); 594 break; 595 596 case '\\': 597 ps("\\e"); 598 break; 599 600 case '_': 601 ps("\\*_"); 602 break; 603 604 case '-': 605 ps("\\*-"); 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("\\fI*\\fP"); 622 break; 623 624 case '/': 625 ps("\\fI\\h'\\w' 'u-\\w'/'u'/\\fP"); 626 break; 627 628 default: 629 if (c < 040) 630 putchar('^'), c |= '@'; 631 case '\t': 632 case '\n': 633 putchar(c); 634 } 635 } 636 637 /* 638 * look for a process beginning on this line 639 */ 640 boolean 641 isproc(s) 642 char *s; 643 { 644 pname[0] = NULL; 645 if (!l_toplex || blklevel == 0) 646 if (expmatch (s, l_prcbeg, pname) != NIL) { 647 return (TRUE); 648 } 649 return (FALSE); 650 } 651 652 653 /* iskw - check to see if the next word is a keyword 654 */ 655 656 iskw(s) 657 register char *s; 658 { 659 register char **ss = l_keywds; 660 register int i = 1; 661 register char *cp = s; 662 663 while (++cp, isidchr(*cp)) 664 i++; 665 while (cp = *ss++) 666 if (!STRNCMP(s,cp,i) && !isidchr(cp[i])) 667 return (i); 668 return (0); 669 } 670