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