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