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