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