1 /* $NetBSD: vfontedpr.c,v 1.7 1998/12/19 23:41:53 christos 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 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) 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 __RCSID("$NetBSD: vfontedpr.c,v 1.7 1998/12/19 23:41:53 christos 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 int main __P((int, char **)); 132 133 #define ps(x) printf("%s", x) 134 135 int 136 main(argc, argv) 137 int argc; 138 char *argv[]; 139 { 140 char *fname = ""; 141 struct stat stbuf; 142 char buf[BUFSIZ]; 143 char *defs; 144 int needbp = 0; 145 146 argc--, argv++; 147 do { 148 char *cp; 149 int i; 150 151 if (argc > 0) { 152 if (!strcmp(argv[0], "-h")) { 153 if (argc == 1) { 154 printf("'ds =H\n"); 155 argc = 0; 156 goto rest; 157 } 158 printf("'ds =H %s\n", argv[1]); 159 argc--, argv++; 160 argc--, argv++; 161 if (argc > 0) 162 continue; 163 goto rest; 164 } 165 166 /* act as a filter like eqn */ 167 if (!strcmp(argv[0], "-f")) { 168 filter++; 169 argv[0] = argv[argc-1]; 170 argv[argc-1] = "-"; 171 continue; 172 } 173 174 /* take input from the standard place */ 175 if (!strcmp(argv[0], "-")) { 176 argc = 0; 177 goto rest; 178 } 179 180 /* build an index */ 181 if (!strcmp(argv[0], "-x")) { 182 idx++; 183 argv[0] = "-n"; 184 } 185 186 /* indicate no keywords */ 187 if (!strcmp(argv[0], "-n")) { 188 nokeyw++; 189 argc--, argv++; 190 continue; 191 } 192 193 /* specify the font size */ 194 if (!strncmp(argv[0], "-s", 2)) { 195 i = 0; 196 cp = argv[0] + 2; 197 while (*cp) 198 i = i * 10 + (*cp++ - '0'); 199 printf("'ps %d\n'vs %d\n", i, i+1); 200 argc--, argv++; 201 continue; 202 } 203 204 /* specify the language */ 205 if (!strncmp(argv[0], "-l", 2)) { 206 language = argv[0]+2; 207 argc--, argv++; 208 continue; 209 } 210 211 /* specify the language description file */ 212 if (!strncmp(argv[0], "-d", 2)) { 213 defsfile[0] = argv[1]; 214 argc--, argv++; 215 argc--, argv++; 216 continue; 217 } 218 219 /* open the file for input */ 220 if (freopen(argv[0], "r", stdin) == NULL) { 221 perror(argv[0]); 222 exit(1); 223 } 224 if (idx) 225 printf("'ta 4i 4.25i 5.5iR\n'in .5i\n"); 226 fname = argv[0]; 227 argc--, argv++; 228 } 229 rest: 230 231 /* 232 * get the language definition from the defs file 233 */ 234 i = cgetent(&defs, defsfile, language); 235 if (i == -1) { 236 fprintf (stderr, "no entry for language %s\n", language); 237 exit (0); 238 } else if (i == -2) { fprintf(stderr, 239 "cannot find vgrindefs file %s\n", defsfile[0]); 240 exit (0); 241 } else if (i == -3) { fprintf(stderr, 242 "potential reference loop detected in vgrindefs file %s\n", 243 defsfile[0]); 244 exit(0); 245 } 246 if (cgetustr(defs, "kw", &cp) == -1) 247 nokeyw = TRUE; 248 else { 249 char **cpp; 250 251 cpp = l_keywds; 252 while (*cp) { 253 while (*cp == ' ' || *cp =='\t') 254 *cp++ = '\0'; 255 if (*cp) 256 *cpp++ = cp; 257 while (*cp != ' ' && *cp != '\t' && *cp) 258 cp++; 259 } 260 *cpp = NIL; 261 } 262 cgetustr(defs, "pb", &cp); 263 l_prcbeg = convexp(cp); 264 cgetustr(defs, "cb", &cp); 265 l_combeg = convexp(cp); 266 cgetustr(defs, "ce", &cp); 267 l_comend = convexp(cp); 268 cgetustr(defs, "ab", &cp); 269 l_acmbeg = convexp(cp); 270 cgetustr(defs, "ae", &cp); 271 l_acmend = convexp(cp); 272 cgetustr(defs, "sb", &cp); 273 l_strbeg = convexp(cp); 274 cgetustr(defs, "se", &cp); 275 l_strend = convexp(cp); 276 cgetustr(defs, "bb", &cp); 277 l_blkbeg = convexp(cp); 278 cgetustr(defs, "be", &cp); 279 l_blkend = convexp(cp); 280 cgetustr(defs, "lb", &cp); 281 l_chrbeg = convexp(cp); 282 cgetustr(defs, "le", &cp); 283 l_chrend = convexp(cp); 284 l_escape = '\\'; 285 l_onecase = (cgetcap(defs, "oc", ':') != NULL); 286 l_toplex = (cgetcap(defs, "tl", ':') != NULL); 287 288 /* initialize the program */ 289 290 incomm = FALSE; 291 instr = FALSE; 292 inchr = FALSE; 293 x_escaped = FALSE; 294 blklevel = 0; 295 for (psptr=0; psptr<PSMAX; psptr++) { 296 pstack[psptr][0] = '\0'; 297 plstack[psptr] = 0; 298 } 299 psptr = -1; 300 ps("'-F\n"); 301 if (!filter) { 302 printf(".ds =F %s\n", fname); 303 ps("'wh 0 vH\n"); 304 ps("'wh -1i vF\n"); 305 } 306 if (needbp) { 307 needbp = 0; 308 printf(".()\n"); 309 printf(".bp\n"); 310 } 311 if (!filter) { 312 fstat(fileno(stdin), &stbuf); 313 cp = ctime(&stbuf.st_mtime); 314 cp[16] = '\0'; 315 cp[24] = '\0'; 316 printf(".ds =M %s %s\n", cp+4, cp+20); 317 } 318 319 /* 320 * MAIN LOOP!!! 321 */ 322 while (fgets(buf, sizeof buf, stdin) != NULL) { 323 if (buf[0] == '\f') { 324 printf(".bp\n"); 325 } 326 if (buf[0] == '.') { 327 printf("%s", buf); 328 if (!strncmp (buf+1, "vS", 2)) 329 pass = TRUE; 330 if (!strncmp (buf+1, "vE", 2)) 331 pass = FALSE; 332 continue; 333 } 334 prccont = FALSE; 335 if (!filter || pass) 336 putScp(buf); 337 else 338 printf("%s", buf); 339 if (prccont && (psptr >= 0)) { 340 ps("'FC "); 341 ps(pstack[psptr]); 342 ps("\n"); 343 } 344 #ifdef DEBUG 345 printf ("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr); 346 #endif 347 margin = 0; 348 } 349 needbp = 1; 350 } while (argc > 0); 351 exit(0); 352 } 353 354 #define isidchr(c) (isalnum((unsigned char)(c)) || (c) == '_') 355 356 static void 357 putScp(os) 358 char *os; 359 { 360 char *s = os; /* pointer to unmatched string */ 361 char dummy[BUFSIZ]; /* dummy to be used by expmatch */ 362 char *comptr; /* end of a comment delimiter */ 363 char *acmptr; /* end of a comment delimiter */ 364 char *strptr; /* end of a string delimiter */ 365 char *chrptr; /* end of a character const delimiter */ 366 char *blksptr; /* end of a lexical block start */ 367 char *blkeptr; /* end of a lexical block end */ 368 369 x_start = os; /* remember the start for expmatch */ 370 x_escaped = FALSE; 371 if (nokeyw || incomm || instr) 372 goto skip; 373 if (isproc(s)) { 374 ps("'FN "); 375 ps(pname); 376 ps("\n"); 377 if (psptr < PSMAX) { 378 ++psptr; 379 strncpy (pstack[psptr], pname, PNAMELEN); 380 pstack[psptr][PNAMELEN] = '\0'; 381 plstack[psptr] = blklevel; 382 } 383 } 384 skip: 385 do { 386 /* check for string, comment, blockstart, etc */ 387 if (!incomm && !instr && !inchr) { 388 389 blkeptr = expmatch (s, l_blkend, dummy); 390 blksptr = expmatch (s, l_blkbeg, dummy); 391 comptr = expmatch (s, l_combeg, dummy); 392 acmptr = expmatch (s, l_acmbeg, dummy); 393 strptr = expmatch (s, l_strbeg, dummy); 394 chrptr = expmatch (s, l_chrbeg, dummy); 395 396 /* start of a comment? */ 397 if (comptr != NIL) 398 if ((comptr < strptr || strptr == NIL) 399 && (comptr < acmptr || acmptr == NIL) 400 && (comptr < chrptr || chrptr == NIL) 401 && (comptr < blksptr || blksptr == NIL) 402 && (comptr < blkeptr || blkeptr == NIL)) { 403 putKcp (s, comptr-1, FALSE); 404 s = comptr; 405 incomm = TRUE; 406 comtype = STANDARD; 407 if (s != os) 408 ps ("\\c"); 409 ps ("\\c\n'+C\n"); 410 continue; 411 } 412 413 /* start of a comment? */ 414 if (acmptr != NIL) 415 if ((acmptr < strptr || strptr == NIL) 416 && (acmptr < chrptr || chrptr == NIL) 417 && (acmptr < blksptr || blksptr == NIL) 418 && (acmptr < blkeptr || blkeptr == NIL)) { 419 putKcp (s, acmptr-1, FALSE); 420 s = acmptr; 421 incomm = TRUE; 422 comtype = ALTERNATE; 423 if (s != os) 424 ps ("\\c"); 425 ps ("\\c\n'+C\n"); 426 continue; 427 } 428 429 /* start of a string? */ 430 if (strptr != NIL) 431 if ((strptr < chrptr || chrptr == NIL) 432 && (strptr < blksptr || blksptr == NIL) 433 && (strptr < blkeptr || blkeptr == NIL)) { 434 putKcp (s, strptr-1, FALSE); 435 s = strptr; 436 instr = TRUE; 437 continue; 438 } 439 440 /* start of a character string? */ 441 if (chrptr != NIL) 442 if ((chrptr < blksptr || blksptr == NIL) 443 && (chrptr < blkeptr || blkeptr == NIL)) { 444 putKcp (s, chrptr-1, FALSE); 445 s = chrptr; 446 inchr = TRUE; 447 continue; 448 } 449 450 /* end of a lexical block */ 451 if (blkeptr != NIL) { 452 if (blkeptr < blksptr || blksptr == NIL) { 453 putKcp (s, blkeptr - 1, FALSE); 454 s = blkeptr; 455 blklevel--; 456 if (psptr >= 0 && plstack[psptr] >= blklevel) { 457 458 /* end of current procedure */ 459 if (s != os) 460 ps ("\\c"); 461 ps ("\\c\n'-F\n"); 462 blklevel = plstack[psptr]; 463 464 /* see if we should print the last proc name */ 465 if (--psptr >= 0) 466 prccont = TRUE; 467 else 468 psptr = -1; 469 } 470 continue; 471 } 472 } 473 474 /* start of a lexical block */ 475 if (blksptr != NIL) { 476 putKcp (s, blksptr - 1, FALSE); 477 s = blksptr; 478 blklevel++; 479 continue; 480 } 481 482 /* check for end of comment */ 483 } else if (incomm) { 484 comptr = expmatch (s, l_comend, dummy); 485 acmptr = expmatch (s, l_acmend, dummy); 486 if (((comtype == STANDARD) && (comptr != NIL)) || 487 ((comtype == ALTERNATE) && (acmptr != NIL))) { 488 if (comtype == STANDARD) { 489 putKcp (s, comptr-1, TRUE); 490 s = comptr; 491 } else { 492 putKcp (s, acmptr-1, TRUE); 493 s = acmptr; 494 } 495 incomm = FALSE; 496 ps("\\c\n'-C\n"); 497 continue; 498 } else { 499 putKcp (s, s + strlen(s) -1, TRUE); 500 s = s + strlen(s); 501 continue; 502 } 503 504 /* check for end of string */ 505 } else if (instr) { 506 if ((strptr = expmatch (s, l_strend, dummy)) != NIL) { 507 putKcp (s, strptr-1, TRUE); 508 s = strptr; 509 instr = FALSE; 510 continue; 511 } else { 512 putKcp (s, s+strlen(s)-1, TRUE); 513 s = s + strlen(s); 514 continue; 515 } 516 517 /* check for end of character string */ 518 } else if (inchr) { 519 if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) { 520 putKcp (s, chrptr-1, TRUE); 521 s = chrptr; 522 inchr = FALSE; 523 continue; 524 } else { 525 putKcp (s, s+strlen(s)-1, TRUE); 526 s = s + strlen(s); 527 continue; 528 } 529 } 530 531 /* print out the line */ 532 putKcp (s, s + strlen(s) -1, FALSE); 533 s = s + strlen(s); 534 } while (*s); 535 } 536 537 static void 538 putKcp (start, end, force) 539 char *start; /* start of string to write */ 540 char *end; /* end of string to write */ 541 boolean force; /* true if we should force nokeyw */ 542 { 543 int i; 544 int xfld = 0; 545 546 while (start <= end) { 547 if (idx) { 548 if (*start == ' ' || *start == '\t') { 549 if (xfld == 0) 550 printf(""); 551 printf("\t"); 552 xfld = 1; 553 while (*start == ' ' || *start == '\t') 554 start++; 555 continue; 556 } 557 } 558 559 /* take care of nice tab stops */ 560 if (*start == '\t') { 561 while (*start == '\t') 562 start++; 563 i = tabs(x_start, start) - margin / 8; 564 printf("\\h'|%dn'", i * 10 + 1 - margin % 8); 565 continue; 566 } 567 568 if (!nokeyw && !force) 569 if ((*start == '#' || isidchr(*start)) 570 && (start == x_start || !isidchr(start[-1]))) { 571 i = iskw(start); 572 if (i > 0) { 573 ps("\\*(+K"); 574 do 575 putcp(*start++); 576 while (--i > 0); 577 ps("\\*(-K"); 578 continue; 579 } 580 } 581 582 putcp (*start++); 583 } 584 } 585 586 587 static int 588 tabs(s, os) 589 char *s, *os; 590 { 591 592 return (width(s, os) / 8); 593 } 594 595 static int 596 width(s, os) 597 char *s, *os; 598 { 599 int i = 0; 600 601 while (s < os) { 602 if (*s == '\t') { 603 i = (i + 8) &~ 7; 604 s++; 605 continue; 606 } 607 if (*s < ' ') 608 i += 2; 609 else 610 i++; 611 s++; 612 } 613 return (i); 614 } 615 616 static void 617 putcp(c) 618 int c; 619 { 620 621 switch(c) { 622 623 case 0: 624 break; 625 626 case '\f': 627 break; 628 629 case '{': 630 ps("\\*(+K{\\*(-K"); 631 break; 632 633 case '}': 634 ps("\\*(+K}\\*(-K"); 635 break; 636 637 case '\\': 638 ps("\\e"); 639 break; 640 641 case '_': 642 ps("\\*_"); 643 break; 644 645 case '-': 646 ps("\\*-"); 647 break; 648 649 case '`': 650 ps("\\`"); 651 break; 652 653 case '\'': 654 ps("\\'"); 655 break; 656 657 case '.': 658 ps("\\&."); 659 break; 660 661 case '*': 662 ps("\\fI*\\fP"); 663 break; 664 665 case '/': 666 ps("\\fI\\h'\\w' 'u-\\w'/'u'/\\fP"); 667 break; 668 669 default: 670 if (c < 040) 671 putchar('^'), c |= '@'; 672 case '\t': 673 case '\n': 674 putchar(c); 675 } 676 } 677 678 /* 679 * look for a process beginning on this line 680 */ 681 static boolean 682 isproc(s) 683 char *s; 684 { 685 pname[0] = '\0'; 686 if (!l_toplex || blklevel == 0) 687 if (expmatch (s, l_prcbeg, pname) != NIL) { 688 return (TRUE); 689 } 690 return (FALSE); 691 } 692 693 694 /* iskw - check to see if the next word is a keyword 695 */ 696 697 static int 698 iskw(s) 699 char *s; 700 { 701 char **ss = l_keywds; 702 int i = 1; 703 char *cp = s; 704 705 /*###705 [cc] warning: subscript has type `char'%%%*/ 706 while (++cp, isidchr(*cp)) 707 i++; 708 while ((cp = *ss++) != NULL) 709 /*###708 [cc] warning: subscript has type `char'%%%*/ 710 if (!STRNCMP(s,cp,i) && !isidchr(cp[i])) 711 return (i); 712 return (0); 713 } 714 715