1 /* $NetBSD: vfontedpr.c,v 1.13 2008/07/21 14:19:27 lukem 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\ 35 The Regents of the University of California. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)vfontedpr.c 8.1 (Berkeley) 6/6/93"; 41 #endif 42 __RCSID("$NetBSD: vfontedpr.c,v 1.13 2008/07/21 14:19:27 lukem Exp $"); 43 #endif /* not lint */ 44 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 #include <time.h> 48 #include <ctype.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <stdio.h> 52 #include "pathnames.h" 53 #include "extern.h" 54 55 #define FALSE 0 56 #define TRUE !(FALSE) 57 #define NIL 0 58 #define STANDARD 0 59 #define ALTERNATE 1 60 61 /* 62 * Vfontedpr. 63 * 64 * Dave Presotto 1/12/81 (adapted from an earlier version by Bill Joy) 65 * 66 */ 67 68 #define STRLEN 10 /* length of strings introducing things */ 69 #define PNAMELEN 40 /* length of a function/procedure name */ 70 #define PSMAX 20 /* size of procedure name stacking */ 71 72 static int iskw __P((char *)); 73 static boolean isproc __P((char *)); 74 static void putKcp __P((char *, char *, boolean)); 75 static void putScp __P((char *)); 76 static void putcp __P((int)); 77 static int tabs __P((char *, char *)); 78 static int width __P((char *, char *)); 79 80 /* 81 * The state variables 82 */ 83 84 static boolean filter = FALSE; /* act as a filter (like eqn) */ 85 static boolean inchr; /* in a string constant */ 86 static boolean incomm; /* in a comment of the primary type */ 87 static boolean idx = FALSE; /* form an index */ 88 static boolean instr; /* in a string constant */ 89 static boolean nokeyw = FALSE; /* no keywords being flagged */ 90 static boolean pass = FALSE; /* 91 * when acting as a filter, pass indicates 92 * whether we are currently processing 93 * input. 94 */ 95 96 static int blklevel; /* current nesting level */ 97 static int comtype; /* type of comment */ 98 static const char *defsfile[2] = { _PATH_VGRINDEFS, 0 }; 99 /* name of language definitions file */ 100 static int margin; 101 static int plstack[PSMAX]; /* the procedure nesting level stack */ 102 static char pname[BUFSIZ+1]; 103 static boolean prccont; /* continue last procedure */ 104 static int psptr; /* the stack index of the current procedure */ 105 static char pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */ 106 107 /* 108 * The language specific globals 109 */ 110 111 char *l_acmbeg; /* string introducing a comment */ 112 char *l_acmend; /* string ending a comment */ 113 char *l_blkbeg; /* string begining of a block */ 114 char *l_blkend; /* string ending a block */ 115 char *l_chrbeg; /* delimiter for character constant */ 116 char *l_chrend; /* delimiter for character constant */ 117 char *l_combeg; /* string introducing a comment */ 118 char *l_comend; /* string ending a comment */ 119 char l_escape; /* character used to escape characters */ 120 char *l_keywds[BUFSIZ/2]; /* keyword table address */ 121 char *l_prcbeg; /* regular expr for procedure begin */ 122 char *l_strbeg; /* delimiter for string constant */ 123 char *l_strend; /* delimiter for string constant */ 124 boolean l_toplex; /* procedures only defined at top lex level */ 125 const char *language = "c"; /* the language indicator */ 126 127 int main __P((int, char **)); 128 129 #define ps(x) printf("%s", x) 130 static char minus[] = "-"; 131 static char minusn[] = "-n"; 132 133 int 134 main(argc, argv) 135 int argc; 136 char *argv[]; 137 { 138 const 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] = minus; 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] = minusn; 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 x_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((unsigned char)(c)) || (c) == '_') 353 354 static void 355 putScp(os) 356 char *os; 357 { 358 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 x_start = os; /* remember the start for expmatch */ 368 x_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 strlcpy(pstack[psptr], pname, sizeof(pstack[psptr])); 378 plstack[psptr] = blklevel; 379 } 380 } 381 skip: 382 do { 383 /* check for string, comment, blockstart, etc */ 384 if (!incomm && !instr && !inchr) { 385 386 blkeptr = expmatch(s, l_blkend, dummy); 387 blksptr = expmatch(s, l_blkbeg, dummy); 388 comptr = expmatch(s, l_combeg, dummy); 389 acmptr = expmatch(s, l_acmbeg, dummy); 390 strptr = expmatch(s, l_strbeg, dummy); 391 chrptr = expmatch(s, l_chrbeg, dummy); 392 393 /* start of a comment? */ 394 if (comptr != NIL) 395 if ((comptr < strptr || strptr == NIL) 396 && (comptr < acmptr || acmptr == NIL) 397 && (comptr < chrptr || chrptr == NIL) 398 && (comptr < blksptr || blksptr == NIL) 399 && (comptr < blkeptr || blkeptr == NIL)) { 400 putKcp(s, comptr-1, FALSE); 401 s = comptr; 402 incomm = TRUE; 403 comtype = STANDARD; 404 if (s != os) 405 ps("\\c"); 406 ps("\\c\n'+C\n"); 407 continue; 408 } 409 410 /* start of a comment? */ 411 if (acmptr != NIL) 412 if ((acmptr < strptr || strptr == NIL) 413 && (acmptr < chrptr || chrptr == NIL) 414 && (acmptr < blksptr || blksptr == NIL) 415 && (acmptr < blkeptr || blkeptr == NIL)) { 416 putKcp(s, acmptr-1, FALSE); 417 s = acmptr; 418 incomm = TRUE; 419 comtype = ALTERNATE; 420 if (s != os) 421 ps("\\c"); 422 ps("\\c\n'+C\n"); 423 continue; 424 } 425 426 /* start of a string? */ 427 if (strptr != NIL) 428 if ((strptr < chrptr || chrptr == NIL) 429 && (strptr < blksptr || blksptr == NIL) 430 && (strptr < blkeptr || blkeptr == NIL)) { 431 putKcp(s, strptr-1, FALSE); 432 s = strptr; 433 instr = TRUE; 434 continue; 435 } 436 437 /* start of a character string? */ 438 if (chrptr != NIL) 439 if ((chrptr < blksptr || blksptr == NIL) 440 && (chrptr < blkeptr || blkeptr == NIL)) { 441 putKcp(s, chrptr-1, FALSE); 442 s = chrptr; 443 inchr = TRUE; 444 continue; 445 } 446 447 /* end of a lexical block */ 448 if (blkeptr != NIL) { 449 if (blkeptr < blksptr || blksptr == NIL) { 450 putKcp(s, blkeptr - 1, FALSE); 451 s = blkeptr; 452 blklevel--; 453 if (psptr >= 0 && plstack[psptr] >= blklevel) { 454 455 /* end of current procedure */ 456 if (s != os) 457 ps("\\c"); 458 ps("\\c\n'-F\n"); 459 blklevel = plstack[psptr]; 460 461 /* see if we should print the last proc name */ 462 if (--psptr >= 0) 463 prccont = TRUE; 464 else 465 psptr = -1; 466 } 467 continue; 468 } 469 } 470 471 /* start of a lexical block */ 472 if (blksptr != NIL) { 473 putKcp(s, blksptr - 1, FALSE); 474 s = blksptr; 475 blklevel++; 476 continue; 477 } 478 479 /* check for end of comment */ 480 } else if (incomm) { 481 comptr = expmatch(s, l_comend, dummy); 482 acmptr = expmatch(s, l_acmend, dummy); 483 if (((comtype == STANDARD) && (comptr != NIL)) || 484 ((comtype == ALTERNATE) && (acmptr != NIL))) { 485 if (comtype == STANDARD) { 486 putKcp(s, comptr-1, TRUE); 487 s = comptr; 488 } else { 489 putKcp(s, acmptr-1, TRUE); 490 s = acmptr; 491 } 492 incomm = FALSE; 493 ps("\\c\n'-C\n"); 494 continue; 495 } else { 496 putKcp(s, s + strlen(s) -1, TRUE); 497 s = s + strlen(s); 498 continue; 499 } 500 501 /* check for end of string */ 502 } else if (instr) { 503 if ((strptr = expmatch(s, l_strend, dummy)) != NIL) { 504 putKcp(s, strptr-1, TRUE); 505 s = strptr; 506 instr = FALSE; 507 continue; 508 } else { 509 putKcp(s, s+strlen(s)-1, TRUE); 510 s = s + strlen(s); 511 continue; 512 } 513 514 /* check for end of character string */ 515 } else if (inchr) { 516 if ((chrptr = expmatch(s, l_chrend, dummy)) != NIL) { 517 putKcp(s, chrptr-1, TRUE); 518 s = chrptr; 519 inchr = FALSE; 520 continue; 521 } else { 522 putKcp(s, s+strlen(s)-1, TRUE); 523 s = s + strlen(s); 524 continue; 525 } 526 } 527 528 /* print out the line */ 529 putKcp(s, s + strlen(s) -1, FALSE); 530 s = s + strlen(s); 531 } while (*s); 532 } 533 534 static void 535 putKcp(start, end, force) 536 char *start; /* start of string to write */ 537 char *end; /* end of string to write */ 538 boolean force; /* true if we should force nokeyw */ 539 { 540 int i; 541 int xfld = 0; 542 543 while (start <= end) { 544 if (idx) { 545 if (*start == ' ' || *start == '\t') { 546 if (xfld == 0) 547 printf(""); 548 printf("\t"); 549 xfld = 1; 550 while (*start == ' ' || *start == '\t') 551 start++; 552 continue; 553 } 554 } 555 556 /* take care of nice tab stops */ 557 if (*start == '\t') { 558 while (*start == '\t') 559 start++; 560 i = tabs(x_start, start) - margin / 8; 561 printf("\\h'|%dn'", i * 10 + 1 - margin % 8); 562 continue; 563 } 564 565 if (!nokeyw && !force) 566 if ((*start == '#' || isidchr(*start)) 567 && (start == x_start || !isidchr(start[-1]))) { 568 i = iskw(start); 569 if (i > 0) { 570 ps("\\*(+K"); 571 do 572 putcp(*start++); 573 while (--i > 0); 574 ps("\\*(-K"); 575 continue; 576 } 577 } 578 579 putcp(*start++); 580 } 581 } 582 583 584 static int 585 tabs(s, os) 586 char *s, *os; 587 { 588 589 return (width(s, os) / 8); 590 } 591 592 static int 593 width(s, os) 594 char *s, *os; 595 { 596 int i = 0; 597 598 while (s < os) { 599 if (*s == '\t') { 600 i = (i + 8) &~ 7; 601 s++; 602 continue; 603 } 604 if (*s < ' ') 605 i += 2; 606 else 607 i++; 608 s++; 609 } 610 return (i); 611 } 612 613 static void 614 putcp(c) 615 int c; 616 { 617 618 switch(c) { 619 620 case 0: 621 break; 622 623 case '\f': 624 break; 625 626 case '{': 627 ps("\\*(+K{\\*(-K"); 628 break; 629 630 case '}': 631 ps("\\*(+K}\\*(-K"); 632 break; 633 634 case '\\': 635 ps("\\e"); 636 break; 637 638 case '_': 639 ps("\\*_"); 640 break; 641 642 case '-': 643 ps("\\*-"); 644 break; 645 646 case '`': 647 ps("\\`"); 648 break; 649 650 case '\'': 651 ps("\\'"); 652 break; 653 654 case '.': 655 ps("\\&."); 656 break; 657 658 case '*': 659 ps("\\fI*\\fP"); 660 break; 661 662 case '/': 663 ps("\\fI\\h'\\w' 'u-\\w'/'u'/\\fP"); 664 break; 665 666 default: 667 if (c < 040) 668 putchar('^'), c |= '@'; 669 case '\t': 670 case '\n': 671 putchar(c); 672 } 673 } 674 675 /* 676 * look for a process beginning on this line 677 */ 678 static boolean 679 isproc(s) 680 char *s; 681 { 682 pname[0] = '\0'; 683 if (!l_toplex || blklevel == 0) 684 if (expmatch(s, l_prcbeg, pname) != NIL) { 685 return (TRUE); 686 } 687 return (FALSE); 688 } 689 690 691 /* iskw - check to see if the next word is a keyword 692 */ 693 694 static int 695 iskw(s) 696 char *s; 697 { 698 char **ss = l_keywds; 699 int i = 1; 700 char *cp = s; 701 702 while (++cp, isidchr((unsigned char)*cp)) 703 i++; 704 while ((cp = *ss++) != NULL) 705 if (!STRNCMP(s,cp,i) && !isidchr((unsigned char)cp[i])) 706 return (i); 707 return (0); 708 } 709 710