xref: /illumos-gate/usr/src/cmd/vgrind/vfontedpr.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #pragma ident	"%Z%%M%	%I%	%E% SMI"
8 
9 #include <ctype.h>
10 #include <stdio.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <locale.h>
14 #include <euc.h>
15 #include <stdlib.h>
16 
17 #define boolean int
18 #define TRUE 1
19 #define FALSE 0
20 #define NIL 0
21 #define STANDARD 0
22 #define ALTERNATE 1
23 
24 /*
25  * Vfontedpr.
26  *
27  * Dave Presotto 1/12/81 (adapted from an earlier version by Bill Joy)
28  *
29  */
30 
31 #define STRLEN 10		/* length of strings introducing things */
32 #define PNAMELEN 40		/* length of a function/procedure name */
33 #define PSMAX 20		/* size of procedure name stacking */
34 
35 /* regular expression routines */
36 
37 char	*expmatch();		/* match a string to an expression */
38 char	*STRNCMP();		/* a different kind of strncmp */
39 char	*convexp();		/* convert expression to internal form */
40 
41 char	*tgetstr();		/* extract a string-valued capability */
42 boolean	isproc();
43 char	*ctime();
44 char	*strchr();
45 
46 /*
47  *	The state variables
48  */
49 
50 boolean	incomm;			/* in a comment of the primary type */
51 boolean	instr;			/* in a string constant */
52 boolean	inchr;			/* in a string constant */
53 boolean	nokeyw = FALSE;		/* no keywords being flagged */
54 boolean	doindex = FALSE;	/* form an index */
55 boolean twocol = FALSE;		/* in two-column mode */
56 boolean	filter = FALSE;		/* act as a filter (like eqn) */
57 boolean	pass = FALSE;		/* when acting as a filter, pass indicates
58 				 * whether we are currently processing
59 				 * input.
60 				 */
61 boolean	prccont;		/* continue last procedure */
62 int	comtype;		/* type of comment */
63 int	margin;
64 int	psptr;			/* the stack index of the current procedure */
65 char	pstack[PSMAX][PNAMELEN+1];	/* the procedure name stack */
66 int	plstack[PSMAX];		/* the procedure nesting level stack */
67 int	blklevel;		/* current nesting level */
68 int	prclevel;		/* nesting level at which procedure definitions
69 				   may be found, -1 if none currently valid
70 				   (meaningful only if l_prclevel is true) */
71 char	*defsfile = "/usr/lib/vgrindefs";	/* name of language definitions file */
72 char	pname[BUFSIZ+1];
73 
74 /*
75  *	The language specific globals
76  */
77 
78 char	*language = "c";	/* the language indicator */
79 char	*l_keywds[BUFSIZ/2];	/* keyword table address */
80 char	*l_prcbeg;		/* regular expr for procedure begin */
81 char	*l_combeg;		/* string introducing a comment */
82 char	*l_comend;		/* string ending a comment */
83 char	*l_acmbeg;		/* string introducing a comment */
84 char	*l_acmend;		/* string ending a comment */
85 char	*l_blkbeg;		/* string begining of a block */
86 char	*l_blkend;		/* string ending a block */
87 char	*l_strbeg;		/* delimiter for string constant */
88 char	*l_strend;		/* delimiter for string constant */
89 char	*l_chrbeg;		/* delimiter for character constant */
90 char	*l_chrend;		/* delimiter for character constant */
91 char	*l_prcenable;		/* re indicating that procedure definitions
92 				   can be found in the next lexical level --
93 				   kludge for lisp-like languages that use
94 				   something like
95 					   (defun (proc ...)
96 					  	(proc ...)
97 					   )
98 				   to define procedures */
99 char	l_escape;		/* character used to  escape characters */
100 boolean	l_toplex;		/* procedures only defined at top lex level */
101 boolean l_prclevel;		/* procedure definitions valid only within
102 				   the nesting level indicated by the px
103 				   (l_prcenable) capability */
104 
105 /*
106  *  for the benefit of die-hards who aren't convinced that tabs
107  *  occur every eight columns
108  */
109 short tabsize = 8;
110 
111 /*
112  *  global variables also used by expmatch
113  */
114 boolean	_escaped;		/* if last character was an escape */
115 char	*Start;			/* start of the current string */
116 boolean	l_onecase;		/* upper and lower case are equivalent */
117 char	*l_idchars;		/* characters legal in identifiers in addition
118 				   to letters and digits (default "_") */
119 
120 /*
121  * The code below emits troff macros and directives that consume part of the
122  * troff macro and register space.  See tmac.vgrind for an enumeration of
123  * these macros and registers.
124  */
125 
126 main(argc, argv)
127     int argc;
128     char *argv[];
129 {
130     FILE *in;
131     char *fname;
132     struct stat stbuf;
133     char buf[BUFSIZ];
134     char idbuf[256];	/* enough for all 8 bit chars */
135     char strings[2 * BUFSIZ];
136     char defs[2 * BUFSIZ];
137     int needbp = 0;
138     int i;
139     char *cp;
140 
141 	(void) setlocale(LC_ALL, "");
142 #if !defined(TEXT_DOMAIN)
143 #define	TEXT_DOMAIN	"SYS_TEST"
144 #endif
145 	(void) textdomain(TEXT_DOMAIN);
146 
147     /*
148      * Dump the name by which we were invoked.
149      */
150     argc--, argv++;
151 
152     /*
153      * Process arguments.  For the sake of compatibility with older versions
154      * of the program, the syntax accepted below is very idiosyncratic.  Some
155      * options require space between the option and its argument; others
156      * disallow it.  No options may be bundled together.
157      *
158      * Actually, there is one incompatibility.  Files and options formerly
159      * could be arbitrarily intermixed, but this is no longer allowed.  (This
160      * possiblity was never documented.)
161      */
162     while (argc > 0 && *argv[0] == '-') {
163 	switch (*(cp = argv[0] + 1)) {
164 
165 	case '\0':				/* - */
166 	    /* Take input from stdin. */
167 	    /*
168 	     * This option implies the end of the flag arguments.  Leave the
169 	     * "-" in place for the file processing code to see.
170 	     */
171 	    goto flagsdone;
172 
173 	case '2':				/* -2 */
174 	    /* Enter two column mode. */
175 	    twocol = 1;
176 	    printf("'nr =2 1\n");
177 	    break;
178 
179 	case 'd':				/* -d <defs-file> */
180 	    /* Specify the language description file. */
181 	    defsfile = argv[1];
182 	    argc--, argv++;
183 	    break;
184 
185 	case 'f':				/* -f */
186 	    /* Act as a filter like eqn. */
187 	    filter = 1;
188 	    /*
189 	     * Slide remaining arguments down one position and postpend "-",
190 	     * to force reading from stdin.
191 	     */
192 	    for (i = 0; i < argc - 1; i++)
193 		argv[i] = argv[i + 1];
194 	    argv[argc - 1] = "-";
195 	    continue;
196 
197 	case 'h':				/* -h [header] */
198 	    /* Specify header string. */
199 	    if (argc == 1) {
200 		printf("'ds =H\n");
201 		break;
202 	    }
203 	    printf("'ds =H %s\n", argv[1]);
204 	    argc--, argv++;
205 	    break;
206 
207 	case 'l':				/* -l<language> */
208 	    /* Specify the language. */
209 	    language = cp + 1;
210 	    break;
211 
212 	case 'n':				/* -n */
213 	    /* Indicate no keywords. */
214 	    nokeyw = 1;
215 	    break;
216 
217 	case 's':				/* -s<size> */
218 	    /* Specify the font size. */
219 	    i = 0;
220 	    cp++;
221 	    while (*cp)
222 		i = i * 10 + (*cp++ - '0');
223 	    printf("'nr vP %d\n", i);
224 	    break;
225 
226 	case 't':				/* -t */
227 	    /* Specify a nondefault tab size. */
228 	    tabsize = 4;
229 	    break;
230 
231 	case 'x':				/* -x */
232 	    /* Build an index. */
233 	    doindex = 1;
234 	    /* This option implies "-n" as well; turn it on. */
235 	    argv[0] = "-n";
236 	    continue;
237 	}
238 
239 	/* Advance to next argument. */
240 	argc--, argv++;
241     }
242 
243 flagsdone:
244 
245     /*
246      * Get the language definition from the defs file.
247      */
248     i = tgetent (defs, language, defsfile);
249     if (i == 0) {
250 	fprintf (stderr, gettext("no entry for language %s\n"), language);
251 	exit (0);
252     } else  if (i < 0) {
253 	fprintf (stderr,  gettext("cannot find vgrindefs file %s\n"), defsfile);
254 	exit (0);
255     }
256     cp = strings;
257     if (tgetstr ("kw", &cp) == NIL)
258 	nokeyw = TRUE;
259     else  {
260 	char **cpp;
261 
262 	cpp = l_keywds;
263 	cp = strings;
264 	while (*cp) {
265 	    while (*cp == ' ' || *cp =='\t')
266 		*cp++ = NULL;
267 	    if (*cp)
268 		*cpp++ = cp;
269 	    while (*cp != ' ' && *cp  != '\t' && *cp)
270 		cp++;
271 	}
272 	*cpp = NIL;
273     }
274     cp = buf;
275     l_prcbeg = convexp (tgetstr ("pb", &cp));
276     cp = buf;
277     l_combeg = convexp (tgetstr ("cb", &cp));
278     cp = buf;
279     l_comend = convexp (tgetstr ("ce", &cp));
280     cp = buf;
281     l_acmbeg = convexp (tgetstr ("ab", &cp));
282     cp = buf;
283     l_acmend = convexp (tgetstr ("ae", &cp));
284     cp = buf;
285     l_strbeg = convexp (tgetstr ("sb", &cp));
286     cp = buf;
287     l_strend = convexp (tgetstr ("se", &cp));
288     cp = buf;
289     l_blkbeg = convexp (tgetstr ("bb", &cp));
290     cp = buf;
291     l_blkend = convexp (tgetstr ("be", &cp));
292     cp = buf;
293     l_chrbeg = convexp (tgetstr ("lb", &cp));
294     cp = buf;
295     l_chrend = convexp (tgetstr ("le", &cp));
296     cp = buf;
297     l_prcenable = convexp (tgetstr ("px", &cp));
298     cp = idbuf;
299     l_idchars = tgetstr ("id", &cp);
300     /* Set default, for compatibility with old version */
301     if (l_idchars == NIL)
302 	l_idchars = "_";
303     l_escape = '\\';
304     l_onecase = tgetflag ("oc");
305     l_toplex = tgetflag ("tl");
306     l_prclevel = tgetflag ("pl");
307 
308     /*
309      * Emit a call to the initialization macro.  If not in filter mode, emit a
310      * call to the vS macro, so that tmac.vgrind can uniformly assume that all
311      * program input is bracketed with vS-vE pairs.
312      */
313     printf("'vI\n");
314     if (!filter)
315 	printf("'vS\n");
316 
317     if (doindex) {
318 	/*
319 	 * XXX:	Hard-wired spacing information.  This should probably turn
320 	 *	into the emission of a macro invocation, so that tmac.vgrind
321 	 *	can make up its own mind about what spacing is appropriate.
322 	 */
323 	if (twocol)
324 	    printf("'ta 2.5i 2.75i 4.0iR\n'in .25i\n");
325 	else
326 	    printf("'ta 4i 4.25i 5.5iR\n'in .5i\n");
327     }
328 
329     while (argc > 0) {
330 	if (strcmp(argv[0], "-") == 0) {
331 	    /* Embed an instance of the original stdin. */
332 	    in = fdopen(fileno(stdin), "r");
333 	    fname = "";
334 	} else {
335 	    /* Open the file for input. */
336 	    if ((in = fopen(argv[0], "r")) == NULL) {
337 		perror(argv[0]);
338 		exit(1);
339 	    }
340 	    fname = argv[0];
341 	}
342 	argc--, argv++;
343 
344 	/*
345 	 * Reinitialize for the current file.
346 	 */
347 	incomm = FALSE;
348 	instr = FALSE;
349 	inchr = FALSE;
350 	_escaped = FALSE;
351 	blklevel = 0;
352 	prclevel = -1;
353 	for (psptr=0; psptr<PSMAX; psptr++) {
354 	    pstack[psptr][0] = NULL;
355 	    plstack[psptr] = 0;
356 	}
357 	psptr = -1;
358 	printf("'-F\n");
359 	if (!filter) {
360 	    char *cp;
361 
362 	    printf(".ds =F %s\n", fname);
363 	    if (needbp) {
364 		needbp = 0;
365 		printf(".()\n");
366 		printf(".bp\n");
367 	    }
368 	    fstat(fileno(in), &stbuf);
369 	    cp = ctime(&stbuf.st_mtime);
370 	    cp[16] = '\0';
371 	    cp[24] = '\0';
372 	    printf(".ds =M %s %s\n", cp+4, cp+20);
373 	    printf("'wh 0 vH\n");
374 	    printf("'wh -1i vF\n");
375 	}
376 	if (needbp && filter) {
377 	    needbp = 0;
378 	    printf(".()\n");
379 	    printf(".bp\n");
380 	}
381 
382 	/*
383 	 *	MAIN LOOP!!!
384 	 */
385 	while (fgets(buf, sizeof buf, in) != NULL) {
386 	    if (buf[0] == '\f') {
387 		printf(".bp\n");
388 	    }
389 	    if (buf[0] == '.') {
390 		printf("%s", buf);
391 		if (!strncmp (buf+1, "vS", 2))
392 		    pass = TRUE;
393 		if (!strncmp (buf+1, "vE", 2))
394 		    pass = FALSE;
395 		continue;
396 	    }
397 	    prccont = FALSE;
398 	    if (!filter || pass)
399 		putScp(buf);
400 	    else
401 		printf("%s", buf);
402 	    if (prccont && (psptr >= 0))
403 		printf("'FC %s\n", pstack[psptr]);
404 #ifdef DEBUG
405 	    printf ("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr);
406 #endif
407 	    margin = 0;
408 	}
409 
410 	needbp = 1;
411 	(void) fclose(in);
412     }
413 
414     /* Close off the vS-vE pair. */
415     if (!filter)
416 	printf("'vE\n");
417 
418     exit(0);
419     /* NOTREACHED */
420 }
421 
422 #define isidchr(c) (isalnum(c) || ((c) != NIL && strchr(l_idchars, (c)) != NIL))
423 
424 putScp(os)
425     char *os;
426 {
427     register char *s = os;		/* pointer to unmatched string */
428     char dummy[BUFSIZ];			/* dummy to be used by expmatch */
429     char *comptr;			/* end of a comment delimiter */
430     char *acmptr;			/* end of a comment delimiter */
431     char *strptr;			/* end of a string delimiter */
432     char *chrptr;			/* end of a character const delimiter */
433     char *blksptr;			/* end of a lexical block start */
434     char *blkeptr;			/* end of a lexical block end */
435 
436     Start = os;			/* remember the start for expmatch */
437     _escaped = FALSE;
438     if (nokeyw || incomm || instr)
439 	goto skip;
440     if (isproc(s)) {
441 	printf("'FN %s\n", pname);
442 	if (psptr < PSMAX-1) {
443 	    ++psptr;
444 	    strncpy (pstack[psptr], pname, PNAMELEN);
445 	    pstack[psptr][PNAMELEN] = NULL;
446 	    plstack[psptr] = blklevel;
447 	}
448     }
449     /*
450      * if l_prclevel is set, check to see whether this lexical level
451      * is one immediately below which procedure definitions are allowed.
452      */
453     if (l_prclevel && !incomm && !instr && !inchr) {
454 	if (expmatch (s, l_prcenable, dummy) != NIL)
455 	    prclevel = blklevel + 1;
456     }
457 skip:
458     do {
459 	/* check for string, comment, blockstart, etc */
460 	if (!incomm && !instr && !inchr) {
461 
462 	    blkeptr = expmatch (s, l_blkend, dummy);
463 	    blksptr = expmatch (s, l_blkbeg, dummy);
464 	    comptr = expmatch (s, l_combeg, dummy);
465 	    acmptr = expmatch (s, l_acmbeg, dummy);
466 	    strptr = expmatch (s, l_strbeg, dummy);
467 	    chrptr = expmatch (s, l_chrbeg, dummy);
468 
469 	    /* start of a comment? */
470 	    if (comptr != NIL)
471 		if ((comptr < strptr || strptr == NIL)
472 		  && (comptr < acmptr || acmptr == NIL)
473 		  && (comptr < chrptr || chrptr == NIL)
474 		  && (comptr < blksptr || blksptr == NIL)
475 		  && (comptr < blkeptr || blkeptr == NIL)) {
476 		    putKcp (s, comptr-1, FALSE);
477 		    s = comptr;
478 		    incomm = TRUE;
479 		    comtype = STANDARD;
480 		    if (s != os)
481 			printf ("\\c");
482 		    printf ("\\c\n'+C\n");
483 		    continue;
484 		}
485 
486 	    /* start of a comment? */
487 	    if (acmptr != NIL)
488 		if ((acmptr < strptr || strptr == NIL)
489 		  && (acmptr < chrptr || chrptr == NIL)
490 		  && (acmptr < blksptr || blksptr == NIL)
491 		  && (acmptr < blkeptr || blkeptr == NIL)) {
492 		    putKcp (s, acmptr-1, FALSE);
493 		    s = acmptr;
494 		    incomm = TRUE;
495 		    comtype = ALTERNATE;
496 		    if (s != os)
497 			printf ("\\c");
498 		    printf ("\\c\n'+C\n");
499 		    continue;
500 		}
501 
502 	    /* start of a string? */
503 	    if (strptr != NIL)
504 		if ((strptr < chrptr || chrptr == NIL)
505 		  && (strptr < blksptr || blksptr == NIL)
506 		  && (strptr < blkeptr || blkeptr == NIL)) {
507 		    putKcp (s, strptr-1, FALSE);
508 		    s = strptr;
509 		    instr = TRUE;
510 		    continue;
511 		}
512 
513 	    /* start of a character string? */
514 	    if (chrptr != NIL)
515 		if ((chrptr < blksptr || blksptr == NIL)
516 		  && (chrptr < blkeptr || blkeptr == NIL)) {
517 		    putKcp (s, chrptr-1, FALSE);
518 		    s = chrptr;
519 		    inchr = TRUE;
520 		    continue;
521 		}
522 
523 	    /* end of a lexical block */
524 	    if (blkeptr != NIL) {
525 		if (blkeptr < blksptr || blksptr == NIL) {
526 		    /* reset prclevel if necessary */
527 		    if (l_prclevel && prclevel == blklevel)
528 			prclevel = -1;
529 		    putKcp (s, blkeptr - 1, FALSE);
530 		    s = blkeptr;
531 		    blklevel--;
532 		    if (psptr >= 0 && plstack[psptr] >= blklevel) {
533 
534 			/* end of current procedure */
535 			if (s != os)
536 			    printf ("\\c");
537 			printf ("\\c\n'-F\n");
538 			blklevel = plstack[psptr];
539 
540 			/* see if we should print the last proc name */
541 			if (--psptr >= 0)
542 			    prccont = TRUE;
543 			else
544 			    psptr = -1;
545 		    }
546 		    continue;
547 		}
548 	    }
549 
550 	    /* start of a lexical block */
551 	    if (blksptr != NIL) {
552 		putKcp (s, blksptr - 1, FALSE);
553 		s = blksptr;
554 		blklevel++;
555 		continue;
556 	    }
557 
558 	/* check for end of comment */
559 	} else if (incomm) {
560 	    comptr = expmatch (s, l_comend, dummy);
561 	    acmptr = expmatch (s, l_acmend, dummy);
562 	    if (((comtype == STANDARD) && (comptr != NIL)) ||
563 	        ((comtype == ALTERNATE) && (acmptr != NIL))) {
564 		if (comtype == STANDARD) {
565 		    putKcp (s, comptr-1, TRUE);
566 		    s = comptr;
567 		} else {
568 		    putKcp (s, acmptr-1, TRUE);
569 		    s = acmptr;
570 		}
571 		incomm = FALSE;
572 		printf("\\c\n'-C\n");
573 		continue;
574 	    } else {
575 		putKcp (s, s + strlen(s) -1, TRUE);
576 		s = s + strlen(s);
577 		continue;
578 	    }
579 
580 	/* check for end of string */
581 	} else if (instr) {
582 	    if ((strptr = expmatch (s, l_strend, dummy)) != NIL) {
583 		putKcp (s, strptr-1, TRUE);
584 		s = strptr;
585 		instr = FALSE;
586 		continue;
587 	    } else {
588 		putKcp (s, s+strlen(s)-1, TRUE);
589 		s = s + strlen(s);
590 		continue;
591 	    }
592 
593 	/* check for end of character string */
594 	} else if (inchr) {
595 	    if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) {
596 		putKcp (s, chrptr-1, TRUE);
597 		s = chrptr;
598 		inchr = FALSE;
599 		continue;
600 	    } else {
601 		putKcp (s, s+strlen(s)-1, TRUE);
602 		s = s + strlen(s);
603 		continue;
604 	    }
605 	}
606 
607 	/* print out the line */
608 	putKcp (s, s + strlen(s) -1, FALSE);
609 	s = s + strlen(s);
610     } while (*s);
611 }
612 
613 putKcp (start, end, force)
614     char	*start;		/* start of string to write */
615     char	*end;		/* end of string to write */
616     boolean	force;		/* true if we should force nokeyw */
617 {
618     int i;
619     int xfld = 0;
620 
621     while (start <= end) {
622 	if (doindex) {
623 	    if (*start == ' ' || *start == '\t') {
624 		if (xfld == 0)
625 		    printf("");
626 		printf("\t");
627 		xfld = 1;
628 		while (*start == ' ' || *start == '\t')
629 		    start++;
630 		continue;
631 	    }
632 	}
633 
634 	/* take care of nice tab stops */
635 	if (*start == '\t') {
636 	    while (*start == '\t')
637 		start++;
638 	    i = tabs(Start, start) - margin / tabsize;
639 	    printf ("\\h'|%dn'",
640 		    i * (tabsize == 4 ? 5 : 10) + 1 - margin % tabsize);
641 	    continue;
642 	}
643 
644 	if (!nokeyw && !force)
645 	    if (  (*start == '#'   ||  isidchr(*start))
646 	       && (start == Start || !isidchr(start[-1]))
647 	       ) {
648 		i = iskw(start);
649 		if (i > 0) {
650 		    printf("\\*(+K");
651 		    do
652 			putcp(*start++);
653 		    while (--i > 0);
654 		    printf("\\*(-K");
655 		    continue;
656 		}
657 	    }
658 
659 	putcp (*start++);
660     }
661 }
662 
663 
664 tabs(s, os)
665     char *s, *os;
666 {
667 
668     return (width(s, os) / tabsize);
669 }
670 
671 width(s, os)
672 	register char *s, *os;
673 {
674 	register int i = 0;
675 	unsigned char c;
676 	int n;
677 
678 	while (s < os) {
679 		if (*s == '\t') {
680 			i = (i + tabsize) &~ (tabsize-1);
681 			s++;
682 			continue;
683 		}
684 		c = *(unsigned char *)s;
685 		if (c < ' ')
686 			i += 2, s++;
687 		else if (c >= 0200) {
688 			if ((n = mblen(s, MB_CUR_MAX)) > 0) {
689 				i += csetcol(csetno(c));
690 				s += n;
691 			} else
692 				s++;
693 		} else
694 			i++, s++;
695 	}
696 	return (i);
697 }
698 
699 putcp(c)
700 	register int c;
701 {
702 
703 	switch(c) {
704 
705 	case 0:
706 		break;
707 
708 	case '\f':
709 		break;
710 
711 	case '{':
712 		printf("\\*(+K{\\*(-K");
713 		break;
714 
715 	case '}':
716 		printf("\\*(+K}\\*(-K");
717 		break;
718 
719 	case '\\':
720 		printf("\\e");
721 		break;
722 
723 	case '_':
724 		printf("\\*_");
725 		break;
726 
727 	case '-':
728 		printf("\\*-");
729 		break;
730 
731 		/*
732 		 * The following two cases deal with the accent characters.
733 		 * If they're part of a comment, we assume that they're part
734 		 * of running text and hand them to troff as regular quote
735 		 * characters.  Otherwise, we assume they're being used as
736 		 * special characters (e.g., string delimiters) and arrange
737 		 * for troff to render them as accents.  This is an imperfect
738 		 * heuristic that produces slightly better appearance than the
739 		 * former behavior of unconditionally rendering the characters
740 		 * as accents.  (See bug 1040343.)
741 		 */
742 
743 	case '`':
744 		if (incomm)
745 			printf("`");
746 		else
747 			printf("\\`");
748 		break;
749 
750 	case '\'':
751 		if (incomm)
752 			printf("'");
753 		else
754 			printf("\\'");
755 		break;
756 
757 	case '.':
758 		printf("\\&.");
759 		break;
760 
761 		/*
762 		 * The following two cases contain special hacking
763 		 * to make C-style comments line up.  The tests aren't
764 		 * really adequate; they lead to grotesqueries such
765 		 * as italicized multiplication and division operators.
766 		 * However, the obvious test (!incomm) doesn't work,
767 		 * because incomm isn't set until after we've put out
768 		 * the comment-begin characters.  The real problem is
769 		 * that expmatch() doesn't give us enough information.
770 		 */
771 
772 	case '*':
773 		if (instr || inchr)
774 			printf("*");
775 		else
776 			printf("\\f2*\\fP");
777 		break;
778 
779 	case '/':
780 		if (instr || inchr)
781 			printf("/");
782 		else
783 			printf("\\f2\\h'\\w' 'u-\\w'/'u'/\\fP");
784 		break;
785 
786 	default:
787 		if (c < 040)
788 			putchar('^'), c |= '@';
789 	case '\t':
790 	case '\n':
791 		putchar(c);
792 	}
793 }
794 
795 /*
796  *	look for a process beginning on this line
797  */
798 boolean
799 isproc(s)
800     char *s;
801 {
802     pname[0] = NULL;
803     if (l_prclevel ? (prclevel == blklevel) : (!l_toplex || blklevel == 0))
804 	if (expmatch (s, l_prcbeg, pname) != NIL) {
805 	    return (TRUE);
806 	}
807     return (FALSE);
808 }
809 
810 
811 /*
812  * iskw - check to see if the next word is a keyword
813  *	Return its length if it is or 0 if it isn't.
814  */
815 
816 iskw(s)
817 	register char *s;
818 {
819 	register char **ss = l_keywds;
820 	register int i = 1;
821 	register char *cp = s;
822 
823 	/* Get token length. */
824 	while (++cp, isidchr(*cp))
825 		i++;
826 
827 	while (cp = *ss++) {
828 		if (!STRNCMP(s,cp,i) && !isidchr(cp[i]))
829 			return (i);
830 	}
831 	return (0);
832 }
833