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