1 /* $NetBSD: vfontedpr.c,v 1.8 2003/06/10 21:27:16 hubertf 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.8 2003/06/10 21:27:16 hubertf 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 char *s=buf; 339 while (*s) { 340 if ( *s == '\\' ) 341 /* escape backslashes */ 342 putchar('\\'); 343 putchar(*s); 344 s++; 345 } 346 } 347 if (prccont && (psptr >= 0)) { 348 ps("'FC "); 349 ps(pstack[psptr]); 350 ps("\n"); 351 } 352 #ifdef DEBUG 353 printf ("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr); 354 #endif 355 margin = 0; 356 } 357 needbp = 1; 358 } while (argc > 0); 359 exit(0); 360 } 361 362 #define isidchr(c) (isalnum((unsigned char)(c)) || (c) == '_') 363 364 static void 365 putScp(os) 366 char *os; 367 { 368 char *s = os; /* pointer to unmatched string */ 369 char dummy[BUFSIZ]; /* dummy to be used by expmatch */ 370 char *comptr; /* end of a comment delimiter */ 371 char *acmptr; /* end of a comment delimiter */ 372 char *strptr; /* end of a string delimiter */ 373 char *chrptr; /* end of a character const delimiter */ 374 char *blksptr; /* end of a lexical block start */ 375 char *blkeptr; /* end of a lexical block end */ 376 377 x_start = os; /* remember the start for expmatch */ 378 x_escaped = FALSE; 379 if (nokeyw || incomm || instr) 380 goto skip; 381 if (isproc(s)) { 382 ps("'FN "); 383 ps(pname); 384 ps("\n"); 385 if (psptr < PSMAX) { 386 ++psptr; 387 strncpy (pstack[psptr], pname, PNAMELEN); 388 pstack[psptr][PNAMELEN] = '\0'; 389 plstack[psptr] = blklevel; 390 } 391 } 392 skip: 393 do { 394 /* check for string, comment, blockstart, etc */ 395 if (!incomm && !instr && !inchr) { 396 397 blkeptr = expmatch (s, l_blkend, dummy); 398 blksptr = expmatch (s, l_blkbeg, dummy); 399 comptr = expmatch (s, l_combeg, dummy); 400 acmptr = expmatch (s, l_acmbeg, dummy); 401 strptr = expmatch (s, l_strbeg, dummy); 402 chrptr = expmatch (s, l_chrbeg, dummy); 403 404 /* start of a comment? */ 405 if (comptr != NIL) 406 if ((comptr < strptr || strptr == NIL) 407 && (comptr < acmptr || acmptr == NIL) 408 && (comptr < chrptr || chrptr == NIL) 409 && (comptr < blksptr || blksptr == NIL) 410 && (comptr < blkeptr || blkeptr == NIL)) { 411 putKcp (s, comptr-1, FALSE); 412 s = comptr; 413 incomm = TRUE; 414 comtype = STANDARD; 415 if (s != os) 416 ps ("\\c"); 417 ps ("\\c\n'+C\n"); 418 continue; 419 } 420 421 /* start of a comment? */ 422 if (acmptr != NIL) 423 if ((acmptr < strptr || strptr == NIL) 424 && (acmptr < chrptr || chrptr == NIL) 425 && (acmptr < blksptr || blksptr == NIL) 426 && (acmptr < blkeptr || blkeptr == NIL)) { 427 putKcp (s, acmptr-1, FALSE); 428 s = acmptr; 429 incomm = TRUE; 430 comtype = ALTERNATE; 431 if (s != os) 432 ps ("\\c"); 433 ps ("\\c\n'+C\n"); 434 continue; 435 } 436 437 /* start of a string? */ 438 if (strptr != NIL) 439 if ((strptr < chrptr || chrptr == NIL) 440 && (strptr < blksptr || blksptr == NIL) 441 && (strptr < blkeptr || blkeptr == NIL)) { 442 putKcp (s, strptr-1, FALSE); 443 s = strptr; 444 instr = TRUE; 445 continue; 446 } 447 448 /* start of a character string? */ 449 if (chrptr != NIL) 450 if ((chrptr < blksptr || blksptr == NIL) 451 && (chrptr < blkeptr || blkeptr == NIL)) { 452 putKcp (s, chrptr-1, FALSE); 453 s = chrptr; 454 inchr = TRUE; 455 continue; 456 } 457 458 /* end of a lexical block */ 459 if (blkeptr != NIL) { 460 if (blkeptr < blksptr || blksptr == NIL) { 461 putKcp (s, blkeptr - 1, FALSE); 462 s = blkeptr; 463 blklevel--; 464 if (psptr >= 0 && plstack[psptr] >= blklevel) { 465 466 /* end of current procedure */ 467 if (s != os) 468 ps ("\\c"); 469 ps ("\\c\n'-F\n"); 470 blklevel = plstack[psptr]; 471 472 /* see if we should print the last proc name */ 473 if (--psptr >= 0) 474 prccont = TRUE; 475 else 476 psptr = -1; 477 } 478 continue; 479 } 480 } 481 482 /* start of a lexical block */ 483 if (blksptr != NIL) { 484 putKcp (s, blksptr - 1, FALSE); 485 s = blksptr; 486 blklevel++; 487 continue; 488 } 489 490 /* check for end of comment */ 491 } else if (incomm) { 492 comptr = expmatch (s, l_comend, dummy); 493 acmptr = expmatch (s, l_acmend, dummy); 494 if (((comtype == STANDARD) && (comptr != NIL)) || 495 ((comtype == ALTERNATE) && (acmptr != NIL))) { 496 if (comtype == STANDARD) { 497 putKcp (s, comptr-1, TRUE); 498 s = comptr; 499 } else { 500 putKcp (s, acmptr-1, TRUE); 501 s = acmptr; 502 } 503 incomm = FALSE; 504 ps("\\c\n'-C\n"); 505 continue; 506 } else { 507 putKcp (s, s + strlen(s) -1, TRUE); 508 s = s + strlen(s); 509 continue; 510 } 511 512 /* check for end of string */ 513 } else if (instr) { 514 if ((strptr = expmatch (s, l_strend, dummy)) != NIL) { 515 putKcp (s, strptr-1, TRUE); 516 s = strptr; 517 instr = FALSE; 518 continue; 519 } else { 520 putKcp (s, s+strlen(s)-1, TRUE); 521 s = s + strlen(s); 522 continue; 523 } 524 525 /* check for end of character string */ 526 } else if (inchr) { 527 if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) { 528 putKcp (s, chrptr-1, TRUE); 529 s = chrptr; 530 inchr = FALSE; 531 continue; 532 } else { 533 putKcp (s, s+strlen(s)-1, TRUE); 534 s = s + strlen(s); 535 continue; 536 } 537 } 538 539 /* print out the line */ 540 putKcp (s, s + strlen(s) -1, FALSE); 541 s = s + strlen(s); 542 } while (*s); 543 } 544 545 static void 546 putKcp (start, end, force) 547 char *start; /* start of string to write */ 548 char *end; /* end of string to write */ 549 boolean force; /* true if we should force nokeyw */ 550 { 551 int i; 552 int xfld = 0; 553 554 while (start <= end) { 555 if (idx) { 556 if (*start == ' ' || *start == '\t') { 557 if (xfld == 0) 558 printf(""); 559 printf("\t"); 560 xfld = 1; 561 while (*start == ' ' || *start == '\t') 562 start++; 563 continue; 564 } 565 } 566 567 /* take care of nice tab stops */ 568 if (*start == '\t') { 569 while (*start == '\t') 570 start++; 571 i = tabs(x_start, start) - margin / 8; 572 printf("\\h'|%dn'", i * 10 + 1 - margin % 8); 573 continue; 574 } 575 576 if (!nokeyw && !force) 577 if ((*start == '#' || isidchr(*start)) 578 && (start == x_start || !isidchr(start[-1]))) { 579 i = iskw(start); 580 if (i > 0) { 581 ps("\\*(+K"); 582 do 583 putcp(*start++); 584 while (--i > 0); 585 ps("\\*(-K"); 586 continue; 587 } 588 } 589 590 putcp (*start++); 591 } 592 } 593 594 595 static int 596 tabs(s, os) 597 char *s, *os; 598 { 599 600 return (width(s, os) / 8); 601 } 602 603 static int 604 width(s, os) 605 char *s, *os; 606 { 607 int i = 0; 608 609 while (s < os) { 610 if (*s == '\t') { 611 i = (i + 8) &~ 7; 612 s++; 613 continue; 614 } 615 if (*s < ' ') 616 i += 2; 617 else 618 i++; 619 s++; 620 } 621 return (i); 622 } 623 624 static void 625 putcp(c) 626 int c; 627 { 628 629 switch(c) { 630 631 case 0: 632 break; 633 634 case '\f': 635 break; 636 637 case '{': 638 ps("\\*(+K{\\*(-K"); 639 break; 640 641 case '}': 642 ps("\\*(+K}\\*(-K"); 643 break; 644 645 case '\\': 646 ps("\\e"); 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("\\'"); 663 break; 664 665 case '.': 666 ps("\\&."); 667 break; 668 669 case '*': 670 ps("\\fI*\\fP"); 671 break; 672 673 case '/': 674 ps("\\fI\\h'\\w' 'u-\\w'/'u'/\\fP"); 675 break; 676 677 default: 678 if (c < 040) 679 putchar('^'), c |= '@'; 680 case '\t': 681 case '\n': 682 putchar(c); 683 } 684 } 685 686 /* 687 * look for a process beginning on this line 688 */ 689 static boolean 690 isproc(s) 691 char *s; 692 { 693 pname[0] = '\0'; 694 if (!l_toplex || blklevel == 0) 695 if (expmatch (s, l_prcbeg, pname) != NIL) { 696 return (TRUE); 697 } 698 return (FALSE); 699 } 700 701 702 /* iskw - check to see if the next word is a keyword 703 */ 704 705 static int 706 iskw(s) 707 char *s; 708 { 709 char **ss = l_keywds; 710 int i = 1; 711 char *cp = s; 712 713 /*###705 [cc] warning: subscript has type `char'%%%*/ 714 while (++cp, isidchr(*cp)) 715 i++; 716 while ((cp = *ss++) != NULL) 717 /*###708 [cc] warning: subscript has type `char'%%%*/ 718 if (!STRNCMP(s,cp,i) && !isidchr(cp[i])) 719 return (i); 720 return (0); 721 } 722 723