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