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
44 static 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 
74 static int       iskw(char *);
75 static bool      isproc(char *);
76 static void      putKcp(char *, char *, bool);
77 static void      putScp(char *);
78 static void      putcp(int);
79 static int       tabs(char *, char *);
80 static int       width(char *, char *);
81 
82 /*
83  *        The state variables
84  */
85 
86 static bool         filter = false;     /* act as a filter (like eqn) */
87 static bool         inchr;              /* in a string constant */
88 static bool         incomm;             /* in a comment of the primary type */
89 static bool         idx = false;        /* form an index */
90 static bool         instr;              /* in a string constant */
91 static bool         nokeyw = false;     /* no keywords being flagged */
92 static bool         pass = false;       /*
93                                          * when acting as a filter, pass indicates
94                                          * whether we are currently processing
95                                          * input.
96                                          */
97 
98 static int          blklevel; /* current nesting level */
99 static int          comtype;  /* type of comment */
100 static const char *defsfile[2] = { _PATH_VGRINDEFS, 0 };
101                                         /* name of language definitions file */
102 static int          margin;
103 static int          plstack[PSMAX];     /* the procedure nesting level stack */
104 static char         pname[BUFSIZ+1];
105 static bool  prccont;         /* continue last procedure */
106 static int          psptr;              /* the stack index of the current procedure */
107 static char         pstack[PSMAX][PNAMELEN+1];    /* the procedure name stack */
108 
109 /*
110  *        The language specific globals
111  */
112 
113 char      *l_acmbeg;                    /* string introducing a comment */
114 char      *l_acmend;                    /* string ending a comment */
115 char      *l_blkbeg;                    /* string beginning of a block */
116 char      *l_blkend;                    /* string ending a block */
117 char    *l_chrbeg;            /* delimiter for character constant */
118 char    *l_chrend;            /* delimiter for character constant */
119 char      *l_combeg;                    /* string introducing a comment */
120 char      *l_comend;                    /* string ending a comment */
121 char       l_escape;                    /* character used to  escape characters */
122 char      *l_keywds[BUFSIZ/2];          /* keyword table address */
123 char      *l_prcbeg;                    /* regular expr for procedure begin */
124 char    *l_strbeg;            /* delimiter for string constant */
125 char    *l_strend;            /* delimiter for string constant */
126 bool       l_toplex;                    /* procedures only defined at top lex level */
127 const char *language = "c";   /* the language indicator */
128 
129 #define   ps(x)     printf("%s", x)
130 static char minus[] = "-";
131 static char minusn[] = "-n";
132 
133 int
main(int argc,char * argv[])134 main(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 
352 static void
putScp(char * os)353 putScp(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     }
378 skip:
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 
531 static void
putKcp(char * start,char * end,bool force)532 putKcp(
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 
581 static int
tabs(char * s,char * os)582 tabs(char *s, char *os)
583 {
584 
585     return width(s, os) / 8;
586 }
587 
588 static int
width(char * s,char * os)589 width(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 
608 static void
putcp(int c)609 putcp(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  */
673 static bool
isproc(char * s)674 isproc(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 
688 static int
iskw(char * s)689 iskw(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