vfontedpr.c revision 1590
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 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)vfontedpr.c	8.1 (Berkeley) 6/6/93";
42#endif /* not lint */
43
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <time.h>
47#include <ctype.h>
48#include <stdlib.h>
49#include <string.h>
50#include <stdio.h>
51#include "pathnames.h"
52#include "extern.h"
53
54#define FALSE 0
55#define TRUE !(FALSE)
56#define NIL 0
57#define STANDARD 0
58#define ALTERNATE 1
59
60/*
61 * Vfontedpr.
62 *
63 * Dave Presotto 1/12/81 (adapted from an earlier version by Bill Joy)
64 *
65 */
66
67#define STRLEN 10		/* length of strings introducing things */
68#define PNAMELEN 40		/* length of a function/procedure name */
69#define PSMAX 20		/* size of procedure name stacking */
70
71static int       iskw __P((char *));
72static boolean   isproc __P((char *));
73static void      putKcp __P((char *, char *, boolean));
74static void      putScp __P((char *));
75static void      putcp __P((int));
76static int       tabs __P((char *, char *));
77static int       width __P((char *, char *));
78
79/*
80 *	The state variables
81 */
82
83static boolean  filter = FALSE;	/* act as a filter (like eqn) */
84static boolean	inchr;		/* in a string constant */
85static boolean	incomm;		/* in a comment of the primary type */
86static boolean	idx = FALSE;	/* form an index */
87static boolean	instr;		/* in a string constant */
88static boolean	nokeyw = FALSE;	/* no keywords being flagged */
89static boolean  pass = FALSE;	/*
90				 * when acting as a filter, pass indicates
91				 * whether we are currently processing
92				 * input.
93				 */
94
95static int	blklevel;	/* current nesting level */
96static int	comtype;	/* type of comment */
97static char    *defsfile[2] = { _PATH_VGRINDEFS, 0 };
98				/* name of language definitions file */
99static int	margin;
100static int	plstack[PSMAX];	/* the procedure nesting level stack */
101static char	pname[BUFSIZ+1];
102static boolean  prccont;	/* continue last procedure */
103static int	psptr;		/* the stack index of the current procedure */
104static char	pstack[PSMAX][PNAMELEN+1];	/* the procedure name stack */
105
106/*
107 *	The language specific globals
108 */
109
110char	*l_acmbeg;		/* string introducing a comment */
111char	*l_acmend;		/* string ending a comment */
112char	*l_blkbeg;		/* string begining of a block */
113char	*l_blkend;		/* string ending a block */
114char    *l_chrbeg;		/* delimiter for character constant */
115char    *l_chrend;		/* delimiter for character constant */
116char	*l_combeg;		/* string introducing a comment */
117char	*l_comend;		/* string ending a comment */
118char	 l_escape;		/* character used to  escape characters */
119char	*l_keywds[BUFSIZ/2];	/* keyword table address */
120char	*l_prcbeg;		/* regular expr for procedure begin */
121char    *l_strbeg;		/* delimiter for string constant */
122char    *l_strend;		/* delimiter for string constant */
123boolean	 l_toplex;		/* procedures only defined at top lex level */
124char	*language = "c";	/* the language indicator */
125
126#define	ps(x)	printf("%s", x)
127
128void
129main(argc, argv)
130    int argc;
131    char *argv[];
132{
133    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++;
162		argv[0] = argv[argc-1];
163		argv[argc-1] = "-";
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++;
176		argv[0] = "-n";
177	    }
178
179	    /* indicate no keywords */
180	    if (!strcmp(argv[0], "-n")) {
181		nokeyw++;
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		perror(argv[0]);
215		exit(1);
216	    }
217	    if (idx)
218		printf("'ta 4i 4.25i 5.5iR\n'in .5i\n");
219	    fname = argv[0];
220	    argc--, argv++;
221	}
222    rest:
223
224	/*
225	 *  get the  language definition from the defs file
226	 */
227	i = cgetent(&defs, defsfile, language);
228	if (i == -1) {
229	    fprintf (stderr, "no entry for language %s\n", language);
230	    exit (0);
231	} else  if (i == -2) { fprintf(stderr,
232	    "cannot find vgrindefs file %s\n", defsfile[0]);
233	    exit (0);
234	} else if (i == -3) { fprintf(stderr,
235	    "potential reference loop detected in vgrindefs file %s\n",
236            defsfile[0]);
237	    exit(0);
238	}
239	if (cgetustr(defs, "kw", &cp) == -1)
240	    nokeyw = TRUE;
241	else  {
242	    char **cpp;
243
244	    cpp = l_keywds;
245	    while (*cp) {
246		while (*cp == ' ' || *cp =='\t')
247		    *cp++ = NULL;
248		if (*cp)
249		    *cpp++ = cp;
250		while (*cp != ' ' && *cp  != '\t' && *cp)
251		    cp++;
252	    }
253	    *cpp = NIL;
254	}
255	cgetustr(defs, "pb", &cp);
256	l_prcbeg = convexp(cp);
257	cgetustr(defs, "cb", &cp);
258	l_combeg = convexp(cp);
259	cgetustr(defs, "ce", &cp);
260	l_comend = convexp(cp);
261	cgetustr(defs, "ab", &cp);
262	l_acmbeg = convexp(cp);
263	cgetustr(defs, "ae", &cp);
264	l_acmend = convexp(cp);
265	cgetustr(defs, "sb", &cp);
266	l_strbeg = convexp(cp);
267	cgetustr(defs, "se", &cp);
268	l_strend = convexp(cp);
269	cgetustr(defs, "bb", &cp);
270	l_blkbeg = convexp(cp);
271	cgetustr(defs, "be", &cp);
272	l_blkend = convexp(cp);
273	cgetustr(defs, "lb", &cp);
274	l_chrbeg = convexp(cp);
275	cgetustr(defs, "le", &cp);
276	l_chrend = 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] = NULL;
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(os)
351    char *os;
352{
353    register char *s = os;		/* pointer to unmatched string */
354    char dummy[BUFSIZ];			/* dummy to be used by expmatch */
355    char *comptr;			/* end of a comment delimiter */
356    char *acmptr;			/* end of a comment delimiter */
357    char *strptr;			/* end of a string delimiter */
358    char *chrptr;			/* end of a character const delimiter */
359    char *blksptr;			/* end of a lexical block start */
360    char *blkeptr;			/* end of a lexical block end */
361
362    _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] = NULL;
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
389	    /* start of a comment? */
390	    if (comptr != NIL)
391		if ((comptr < strptr || strptr == NIL)
392		  && (comptr < acmptr || acmptr == NIL)
393		  && (comptr < chrptr || chrptr == NIL)
394		  && (comptr < blksptr || blksptr == NIL)
395		  && (comptr < blkeptr || blkeptr == NIL)) {
396		    putKcp (s, comptr-1, FALSE);
397		    s = comptr;
398		    incomm = TRUE;
399		    comtype = STANDARD;
400		    if (s != os)
401			ps ("\\c");
402		    ps ("\\c\n'+C\n");
403		    continue;
404		}
405
406	    /* start of a comment? */
407	    if (acmptr != NIL)
408		if ((acmptr < strptr || strptr == NIL)
409		  && (acmptr < chrptr || chrptr == NIL)
410		  && (acmptr < blksptr || blksptr == NIL)
411		  && (acmptr < blkeptr || blkeptr == NIL)) {
412		    putKcp (s, acmptr-1, FALSE);
413		    s = acmptr;
414		    incomm = TRUE;
415		    comtype = ALTERNATE;
416		    if (s != os)
417			ps ("\\c");
418		    ps ("\\c\n'+C\n");
419		    continue;
420		}
421
422	    /* start of a string? */
423	    if (strptr != NIL)
424		if ((strptr < chrptr || chrptr == NIL)
425		  && (strptr < blksptr || blksptr == NIL)
426		  && (strptr < blkeptr || blkeptr == NIL)) {
427		    putKcp (s, strptr-1, FALSE);
428		    s = strptr;
429		    instr = TRUE;
430		    continue;
431		}
432
433	    /* start of a character string? */
434	    if (chrptr != NIL)
435		if ((chrptr < blksptr || blksptr == NIL)
436		  && (chrptr < blkeptr || blkeptr == NIL)) {
437		    putKcp (s, chrptr-1, FALSE);
438		    s = chrptr;
439		    inchr = TRUE;
440		    continue;
441		}
442
443	    /* end of a lexical block */
444	    if (blkeptr != NIL) {
445		if (blkeptr < blksptr || blksptr == NIL) {
446		    putKcp (s, blkeptr - 1, FALSE);
447		    s = blkeptr;
448		    blklevel--;
449		    if (psptr >= 0 && plstack[psptr] >= blklevel) {
450
451			/* end of current procedure */
452			if (s != os)
453			    ps ("\\c");
454			ps ("\\c\n'-F\n");
455			blklevel = plstack[psptr];
456
457			/* see if we should print the last proc name */
458			if (--psptr >= 0)
459			    prccont = TRUE;
460			else
461			    psptr = -1;
462		    }
463		    continue;
464		}
465	    }
466
467	    /* start of a lexical block */
468	    if (blksptr != NIL) {
469		putKcp (s, blksptr - 1, FALSE);
470		s = blksptr;
471		blklevel++;
472		continue;
473	    }
474
475	/* check for end of comment */
476	} else if (incomm) {
477	    comptr = expmatch (s, l_comend, dummy);
478	    acmptr = expmatch (s, l_acmend, dummy);
479	    if (((comtype == STANDARD) && (comptr != NIL)) ||
480	        ((comtype == ALTERNATE) && (acmptr != NIL))) {
481		if (comtype == STANDARD) {
482		    putKcp (s, comptr-1, TRUE);
483		    s = comptr;
484		} else {
485		    putKcp (s, acmptr-1, TRUE);
486		    s = acmptr;
487		}
488		incomm = FALSE;
489		ps("\\c\n'-C\n");
490		continue;
491	    } else {
492		putKcp (s, s + strlen(s) -1, TRUE);
493		s = s + strlen(s);
494		continue;
495	    }
496
497	/* check for end of string */
498	} else if (instr) {
499	    if ((strptr = expmatch (s, l_strend, dummy)) != NIL) {
500		putKcp (s, strptr-1, TRUE);
501		s = strptr;
502		instr = FALSE;
503		continue;
504	    } else {
505		putKcp (s, s+strlen(s)-1, TRUE);
506		s = s + strlen(s);
507		continue;
508	    }
509
510	/* check for end of character string */
511	} else if (inchr) {
512	    if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) {
513		putKcp (s, chrptr-1, TRUE);
514		s = chrptr;
515		inchr = FALSE;
516		continue;
517	    } else {
518		putKcp (s, s+strlen(s)-1, TRUE);
519		s = s + strlen(s);
520		continue;
521	    }
522	}
523
524	/* print out the line */
525	putKcp (s, s + strlen(s) -1, FALSE);
526	s = s + strlen(s);
527    } while (*s);
528}
529
530static void
531putKcp (start, end, force)
532    char	*start;		/* start of string to write */
533    char	*end;		/* end of string to write */
534    boolean	force;		/* true if we should force nokeyw */
535{
536    int i;
537    int xfld = 0;
538
539    while (start <= end) {
540	if (idx) {
541	    if (*start == ' ' || *start == '\t') {
542		if (xfld == 0)
543		    printf("");
544		printf("\t");
545		xfld = 1;
546		while (*start == ' ' || *start == '\t')
547		    start++;
548		continue;
549	    }
550	}
551
552	/* take care of nice tab stops */
553	if (*start == '\t') {
554	    while (*start == '\t')
555		start++;
556	    i = tabs(_start, start) - margin / 8;
557	    printf("\\h'|%dn'", i * 10 + 1 - margin % 8);
558	    continue;
559	}
560
561	if (!nokeyw && !force)
562	    if ((*start == '#' || isidchr(*start))
563	    && (start == _start || !isidchr(start[-1]))) {
564		i = iskw(start);
565		if (i > 0) {
566		    ps("\\*(+K");
567		    do
568			putcp(*start++);
569		    while (--i > 0);
570		    ps("\\*(-K");
571		    continue;
572		}
573	    }
574
575	putcp (*start++);
576    }
577}
578
579
580static int
581tabs(s, os)
582    char *s, *os;
583{
584
585    return (width(s, os) / 8);
586}
587
588static int
589width(s, os)
590	register char *s, *os;
591{
592	register int i = 0;
593
594	while (s < os) {
595		if (*s == '\t') {
596			i = (i + 8) &~ 7;
597			s++;
598			continue;
599		}
600		if (*s < ' ')
601			i += 2;
602		else
603			i++;
604		s++;
605	}
606	return (i);
607}
608
609static void
610putcp(c)
611	register int c;
612{
613
614	switch(c) {
615
616	case 0:
617		break;
618
619	case '\f':
620		break;
621
622	case '{':
623		ps("\\*(+K{\\*(-K");
624		break;
625
626	case '}':
627		ps("\\*(+K}\\*(-K");
628		break;
629
630	case '\\':
631		ps("\\e");
632		break;
633
634	case '_':
635		ps("\\*_");
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("\\fI*\\fP");
656		break;
657
658	case '/':
659		ps("\\fI\\h'\\w' 'u-\\w'/'u'/\\fP");
660		break;
661
662	default:
663		if (c < 040)
664			putchar('^'), c |= '@';
665	case '\t':
666	case '\n':
667		putchar(c);
668	}
669}
670
671/*
672 *	look for a process beginning on this line
673 */
674static boolean
675isproc(s)
676    char *s;
677{
678    pname[0] = NULL;
679    if (!l_toplex || blklevel == 0)
680	if (expmatch (s, l_prcbeg, pname) != NIL) {
681	    return (TRUE);
682	}
683    return (FALSE);
684}
685
686
687/*  iskw -	check to see if the next word is a keyword
688 */
689
690static int
691iskw(s)
692	register char *s;
693{
694	register char **ss = l_keywds;
695	register int i = 1;
696	register char *cp = s;
697
698	while (++cp, isidchr(*cp))
699		i++;
700	while (cp = *ss++)
701		if (!STRNCMP(s,cp,i) && !isidchr(cp[i]))
702			return (i);
703	return (0);
704}
705
706