xref: /openbsd-src/usr.bin/mg/cmode.c (revision ce7279d89b71439c96c854f612f4ac93a461fdc4)
1*ce7279d8Sjsg /* $OpenBSD: cmode.c,v 1.23 2024/05/21 05:00:48 jsg Exp $ */
243e1f234Skjell /*
343e1f234Skjell  * This file is in the public domain.
443e1f234Skjell  *
543e1f234Skjell  * Author: Kjell Wooding <kjell@openbsd.org>
643e1f234Skjell  */
743e1f234Skjell 
843e1f234Skjell /*
943e1f234Skjell  * Implement an non-irritating KNF-compliant mode for editing
1043e1f234Skjell  * C code.
1143e1f234Skjell  */
12cc6738c5Sbcallah 
13cc6738c5Sbcallah #include <sys/queue.h>
1443e1f234Skjell #include <ctype.h>
15cc6738c5Sbcallah #include <signal.h>
16cc6738c5Sbcallah #include <stdio.h>
1743e1f234Skjell 
1843e1f234Skjell #include "def.h"
1943e1f234Skjell #include "funmap.h"
20cc6738c5Sbcallah #include "kbd.h"
2143e1f234Skjell 
2243e1f234Skjell /* Pull in from modes.c */
2343e1f234Skjell extern int changemode(int, int, char *);
2443e1f234Skjell 
2543e1f234Skjell static int cc_strip_trailp = TRUE;	/* Delete Trailing space? */
2643e1f234Skjell static int cc_basic_indent = 8;		/* Basic Indent multiple */
2743e1f234Skjell static int cc_cont_indent = 4;		/* Continued line indent */
2843e1f234Skjell static int cc_colon_indent = -8;	/* Label / case indent */
2943e1f234Skjell 
3043e1f234Skjell static int getmatch(int, int);
3143e1f234Skjell static int getindent(const struct line *, int *);
3292cb5ab0Skjell static int in_whitespace(struct line *, int);
3392cb5ab0Skjell static int findcolpos(const struct buffer *, const struct line *, int);
3492cb5ab0Skjell static struct line *findnonblank(struct line *);
3592cb5ab0Skjell static int isnonblank(const struct line *, int);
3692cb5ab0Skjell 
376238f0cdSlum void cmode_init(void);
3843e1f234Skjell 
3943e1f234Skjell /* Keymaps */
4043e1f234Skjell 
4143e1f234Skjell static PF cmode_brace[] = {
42d3776cdaSkjell 	cc_brace,	/* } */
4343e1f234Skjell };
4443e1f234Skjell 
459d7fdde6Skjell static PF cmode_cCP[] = {
469d7fdde6Skjell 	compile,		/* C-c P */
479d7fdde6Skjell };
489d7fdde6Skjell 
499d7fdde6Skjell 
509d7fdde6Skjell static PF cmode_cc[] = {
519d7fdde6Skjell 	NULL,		/* ^C */
529d7fdde6Skjell 	rescan,		/* ^D */
539d7fdde6Skjell 	rescan,		/* ^E */
549d7fdde6Skjell 	rescan,		/* ^F */
559d7fdde6Skjell 	rescan,		/* ^G */
569d7fdde6Skjell 	rescan,		/* ^H */
5743e1f234Skjell 	cc_tab,		/* ^I */
5843e1f234Skjell 	rescan,		/* ^J */
5943e1f234Skjell 	rescan,		/* ^K */
6043e1f234Skjell 	rescan,		/* ^L */
6143e1f234Skjell 	cc_lfindent,	/* ^M */
6243e1f234Skjell };
6343e1f234Skjell 
6492cb5ab0Skjell static PF cmode_spec[] = {
6543e1f234Skjell 	cc_char,	/* : */
6643e1f234Skjell };
6743e1f234Skjell 
6808e58701Sbcallah static struct KEYMAPE (1) cmode_cmap = {
699d7fdde6Skjell 	1,
7008e58701Sbcallah 	1,
719d7fdde6Skjell 	rescan,
729d7fdde6Skjell 	{
739d7fdde6Skjell 		{ 'P', 'P', cmode_cCP, NULL }
749d7fdde6Skjell 	}
759d7fdde6Skjell };
769d7fdde6Skjell 
7708e58701Sbcallah static struct KEYMAPE (3) cmodemap = {
7843e1f234Skjell 	3,
7908e58701Sbcallah 	3,
8043e1f234Skjell 	rescan,
8143e1f234Skjell 	{
829d7fdde6Skjell 		{ CCHR('C'), CCHR('M'), cmode_cc, (KEYMAP *) &cmode_cmap },
8392cb5ab0Skjell 		{ ':', ':', cmode_spec, NULL },
8443e1f234Skjell 		{ '}', '}', cmode_brace, NULL }
8543e1f234Skjell 	}
8643e1f234Skjell };
8743e1f234Skjell 
8849cb4ed9Sop /* Function, Mode hooks */
8943e1f234Skjell 
9043e1f234Skjell void
cmode_init(void)9143e1f234Skjell cmode_init(void)
9243e1f234Skjell {
93f8588f90Slum 	funmap_add(cmode, "c-mode", 0);
94f8588f90Slum 	funmap_add(cc_char, "c-handle-special-char", 0);
95f8588f90Slum 	funmap_add(cc_brace, "c-handle-special-brace", 0);
96f8588f90Slum 	funmap_add(cc_tab, "c-tab-or-indent", 0);
97f8588f90Slum 	funmap_add(cc_indent, "c-indent", 0);
98f8588f90Slum 	funmap_add(cc_lfindent, "c-indent-and-newline", 0);
99eb0368c5Ssobrado 	maps_add((KEYMAP *)&cmodemap, "c");
10043e1f234Skjell }
10143e1f234Skjell 
10243e1f234Skjell /*
10343e1f234Skjell  * Enable/toggle c-mode
10443e1f234Skjell  */
10543e1f234Skjell int
cmode(int f,int n)10643e1f234Skjell cmode(int f, int n)
10743e1f234Skjell {
108eb0368c5Ssobrado 	return(changemode(f, n, "c"));
10943e1f234Skjell }
11043e1f234Skjell 
11143e1f234Skjell /*
11243e1f234Skjell  * Handle special C character - selfinsert then indent.
11343e1f234Skjell  */
11443e1f234Skjell int
cc_char(int f,int n)11543e1f234Skjell cc_char(int f, int n)
11643e1f234Skjell {
11743e1f234Skjell 	if (n < 0)
11843e1f234Skjell 		return (FALSE);
11943e1f234Skjell 	if (selfinsert(FFRAND, n) == FALSE)
12043e1f234Skjell 		return (FALSE);
12143e1f234Skjell 	return (cc_indent(FFRAND, n));
12243e1f234Skjell }
12343e1f234Skjell 
12443e1f234Skjell /*
125d3776cdaSkjell  * Handle special C character - selfinsert then indent.
126d3776cdaSkjell  */
127d3776cdaSkjell int
cc_brace(int f,int n)128d3776cdaSkjell cc_brace(int f, int n)
129d3776cdaSkjell {
130d3776cdaSkjell 	if (n < 0)
131d3776cdaSkjell 		return (FALSE);
132d3776cdaSkjell 	if (showmatch(FFRAND, 1) == FALSE)
133d3776cdaSkjell 		return (FALSE);
134d3776cdaSkjell 	return (cc_indent(FFRAND, n));
135d3776cdaSkjell }
136d3776cdaSkjell 
137d3776cdaSkjell 
138d3776cdaSkjell /*
13943e1f234Skjell  * If we are in the whitespace at the beginning of the line,
14043e1f234Skjell  * simply act as a regular tab. If we are not, indent
14143e1f234Skjell  * current line according to whitespace rules.
14243e1f234Skjell  */
14343e1f234Skjell int
cc_tab(int f,int n)14443e1f234Skjell cc_tab(int f, int n)
14543e1f234Skjell {
14643e1f234Skjell 	int inwhitep = FALSE;	/* In leading whitespace? */
14743e1f234Skjell 
14892cb5ab0Skjell 	inwhitep = in_whitespace(curwp->w_dotp, llength(curwp->w_dotp));
14943e1f234Skjell 
15043e1f234Skjell 	/* If empty line, or in whitespace */
15143e1f234Skjell 	if (llength(curwp->w_dotp) == 0 || inwhitep)
15243e1f234Skjell 		return (selfinsert(f, n));
15343e1f234Skjell 
15443e1f234Skjell 	return (cc_indent(FFRAND, 1));
15543e1f234Skjell }
15643e1f234Skjell 
15743e1f234Skjell /*
15843e1f234Skjell  * Attempt to indent current line according to KNF rules.
15943e1f234Skjell  */
16043e1f234Skjell int
cc_indent(int f,int n)16143e1f234Skjell cc_indent(int f, int n)
16243e1f234Skjell {
163a70808f5Sguenther 	int pi, mi;			/* Previous indents (mi is ignored) */
164a70808f5Sguenther 	int ci;				/* current indent */
16543e1f234Skjell 	struct line *lp;
1669d7fdde6Skjell 	int ret;
16743e1f234Skjell 
16843e1f234Skjell 	if (n < 0)
16943e1f234Skjell 		return (FALSE);
17043e1f234Skjell 
171a13804d2Skjell 	undo_boundary_enable(FFRAND, 0);
17243e1f234Skjell 	if (cc_strip_trailp)
17343e1f234Skjell 		deltrailwhite(FFRAND, 1);
17443e1f234Skjell 
17592cb5ab0Skjell 	/*
17692cb5ab0Skjell 	 * Search backwards for a non-blank, non-preprocessor,
17792cb5ab0Skjell 	 * non-comment line
17892cb5ab0Skjell 	 */
17992cb5ab0Skjell 
18092cb5ab0Skjell 	lp = findnonblank(curwp->w_dotp);
18143e1f234Skjell 
18243e1f234Skjell 	pi = getindent(lp, &mi);
18343e1f234Skjell 
18443e1f234Skjell 	/* Strip leading space on current line */
18543e1f234Skjell 	delleadwhite(FFRAND, 1);
18643e1f234Skjell 	/* current indent is computed only to current position */
187a70808f5Sguenther 	(void)getindent(curwp->w_dotp, &ci);
18843e1f234Skjell 
18943e1f234Skjell 	if (pi + ci < 0)
1909d7fdde6Skjell 		ret = indent(FFOTHARG, 0);
19143e1f234Skjell 	else
1929d7fdde6Skjell 		ret = indent(FFOTHARG, pi + ci);
1939d7fdde6Skjell 
194a13804d2Skjell 	undo_boundary_enable(FFRAND, 1);
1959d7fdde6Skjell 
1969d7fdde6Skjell 	return (ret);
19743e1f234Skjell }
19843e1f234Skjell 
19943e1f234Skjell /*
20043e1f234Skjell  * Indent-and-newline (technically, newline then indent)
20143e1f234Skjell  */
20243e1f234Skjell int
cc_lfindent(int f,int n)20343e1f234Skjell cc_lfindent(int f, int n)
20443e1f234Skjell {
20543e1f234Skjell 	if (n < 0)
20643e1f234Skjell 		return (FALSE);
207d1c1bfe0Sop 	if (cc_strip_trailp)
208d1c1bfe0Sop 		(void)delwhite(FFRAND, 1);
2093eb81a2eSbcallah 	if (enewline(FFRAND, 1) == FALSE)
21043e1f234Skjell 		return (FALSE);
21143e1f234Skjell 	return (cc_indent(FFRAND, n));
21243e1f234Skjell }
21343e1f234Skjell 
21443e1f234Skjell /*
215d9a51c35Sjmc  * Get the level of indentation after line lp is processed
21692cb5ab0Skjell  * Note getindent has two returns:
21743e1f234Skjell  * curi = value if indenting current line.
21843e1f234Skjell  * return value = value affecting subsequent lines.
21943e1f234Skjell  */
22043e1f234Skjell static int
getindent(const struct line * lp,int * curi)22143e1f234Skjell getindent(const struct line *lp, int *curi)
22243e1f234Skjell {
22343e1f234Skjell 	int lo, co;		/* leading space,  current offset*/
22443e1f234Skjell 	int nicol = 0;		/* position count */
22543e1f234Skjell 	int c = '\0';		/* current char */
22643e1f234Skjell 	int newind = 0;		/* new index value */
22743e1f234Skjell 	int stringp = FALSE;	/* in string? */
22843e1f234Skjell 	int escp = FALSE;	/* Escape char? */
229d9a51c35Sjmc 	int lastc = '\0';	/* Last matched string delimiter */
23043e1f234Skjell 	int nparen = 0;		/* paren count */
23143e1f234Skjell 	int obrace = 0;		/* open brace count */
23243e1f234Skjell 	int cbrace = 0;		/* close brace count */
23392cb5ab0Skjell 	int firstnwsp = FALSE;	/* First nonspace encountered? */
23443e1f234Skjell 	int colonp = FALSE;	/* Did we see a colon? */
23543e1f234Skjell 	int questionp = FALSE;	/* Did we see a question mark? */
23692cb5ab0Skjell 	int slashp = FALSE;	/* Slash? */
23792cb5ab0Skjell 	int astp = FALSE;	/* Asterisk? */
23892cb5ab0Skjell 	int cpos = -1;		/* comment position */
23992cb5ab0Skjell 	int cppp  = FALSE;	/* Preprocessor command? */
24043e1f234Skjell 
24143e1f234Skjell 	*curi = 0;
24243e1f234Skjell 
24343e1f234Skjell 	/* Compute leading space */
24443e1f234Skjell 	for (lo = 0; lo < llength(lp); lo++) {
24543e1f234Skjell 		if (!isspace(c = lgetc(lp, lo)))
24643e1f234Skjell 			break;
247fb3e194eSop 		if (c == '\t')
248fb3e194eSop 			nicol = ntabstop(nicol, curbp->b_tabw);
249fb3e194eSop 		else
25043e1f234Skjell 			nicol++;
25143e1f234Skjell 	}
25243e1f234Skjell 
25343e1f234Skjell 	/* If last line was blank, choose 0 */
25443e1f234Skjell 	if (lo == llength(lp))
25543e1f234Skjell 		nicol = 0;
25643e1f234Skjell 
25743e1f234Skjell 	newind = 0;
25843e1f234Skjell 	/* Compute modifiers */
25943e1f234Skjell 	for (co = lo; co < llength(lp); co++) {
26043e1f234Skjell 		c = lgetc(lp, co);
26143e1f234Skjell 		/* We have a non-whitespace char */
26292cb5ab0Skjell 		if (!firstnwsp && !isspace(c)) {
26392cb5ab0Skjell 			if (c == '#')
26492cb5ab0Skjell 				cppp = TRUE;
26592cb5ab0Skjell 			firstnwsp = TRUE;
26643e1f234Skjell 		}
26743e1f234Skjell 		if (c == '\\')
26843e1f234Skjell 			escp = !escp;
26943e1f234Skjell 		else if (stringp) {
27043e1f234Skjell 			if (!escp && (c == '"' || c == '\'')) {
27143e1f234Skjell 				/* unescaped string char */
27243e1f234Skjell 				if (getmatch(c, lastc))
27343e1f234Skjell 					stringp = FALSE;
27443e1f234Skjell 			}
27543e1f234Skjell 		} else if (c == '"' || c == '\'') {
27643e1f234Skjell 			stringp = TRUE;
27743e1f234Skjell 			lastc = c;
27843e1f234Skjell 		} else if (c == '(') {
27943e1f234Skjell 			nparen++;
28043e1f234Skjell 		} else if (c == ')') {
28143e1f234Skjell 			nparen--;
28243e1f234Skjell 		} else if (c == '{') {
28343e1f234Skjell 			obrace++;
28492cb5ab0Skjell 			firstnwsp = FALSE;
28543e1f234Skjell 		} else if (c == '}') {
28643e1f234Skjell 			cbrace++;
28743e1f234Skjell 		} else if (c == '?') {
28843e1f234Skjell 			questionp = TRUE;
28943e1f234Skjell 		} else if (c == ':') {
29043e1f234Skjell 			/* ignore (foo ? bar : baz) construct */
29143e1f234Skjell 			if (!questionp)
29243e1f234Skjell 				colonp = TRUE;
29392cb5ab0Skjell 		} else if (c == '/') {
29492cb5ab0Skjell 			/* first nonwhitespace? -> indent */
29592cb5ab0Skjell 			if (firstnwsp) {
29692cb5ab0Skjell 				/* If previous char asterisk -> close */
29792cb5ab0Skjell 				if (astp)
29892cb5ab0Skjell 					cpos = -1;
29992cb5ab0Skjell 				else
30092cb5ab0Skjell 					slashp = TRUE;
30192cb5ab0Skjell 			}
30292cb5ab0Skjell 		} else if (c == '*') {
30392cb5ab0Skjell 			/* If previous char slash -> open */
30492cb5ab0Skjell 			if (slashp)
30592cb5ab0Skjell 				cpos = co;
30692cb5ab0Skjell 			else
30792cb5ab0Skjell 				astp = TRUE;
30892cb5ab0Skjell 		} else if (firstnwsp) {
30992cb5ab0Skjell 			firstnwsp = FALSE;
31043e1f234Skjell 		}
31143e1f234Skjell 
31292cb5ab0Skjell 		/* Reset matches that apply to next character only */
31343e1f234Skjell 		if (c != '\\')
31443e1f234Skjell 			escp = FALSE;
31592cb5ab0Skjell 		if (c != '*')
31692cb5ab0Skjell 			astp = FALSE;
31792cb5ab0Skjell 		if (c != '/')
31892cb5ab0Skjell 			slashp = FALSE;
31943e1f234Skjell 	}
32043e1f234Skjell 	/*
32143e1f234Skjell 	 * If not terminated with a semicolon, and brace or paren open.
32243e1f234Skjell 	 * we continue
32343e1f234Skjell 	 */
32443e1f234Skjell 	if (colonp) {
32543e1f234Skjell 		*curi += cc_colon_indent;
32643e1f234Skjell 		newind -= cc_colon_indent;
32743e1f234Skjell 	}
32843e1f234Skjell 
32943e1f234Skjell 	*curi -= (cbrace) * cc_basic_indent;
33043e1f234Skjell 	newind += obrace * cc_basic_indent;
33143e1f234Skjell 
33243e1f234Skjell 	if (nparen < 0)
33343e1f234Skjell 		newind -= cc_cont_indent;
33443e1f234Skjell 	else if (nparen > 0)
33543e1f234Skjell 		newind += cc_cont_indent;
33692cb5ab0Skjell 
33743e1f234Skjell 	*curi += nicol;
33843e1f234Skjell 
33992cb5ab0Skjell 	/* Ignore preprocessor. Otherwise, add current column */
34092cb5ab0Skjell 	if (cppp) {
34192cb5ab0Skjell 		newind = nicol;
34292cb5ab0Skjell 		*curi = 0;
34392cb5ab0Skjell 	} else {
34492cb5ab0Skjell 		newind += nicol;
34592cb5ab0Skjell 	}
34692cb5ab0Skjell 
34792cb5ab0Skjell 	if (cpos != -1)
34892cb5ab0Skjell 		newind = findcolpos(curbp, lp, cpos);
34992cb5ab0Skjell 
35043e1f234Skjell 	return (newind);
35143e1f234Skjell }
35243e1f234Skjell 
35343e1f234Skjell /*
354d9a51c35Sjmc  * Given a delimiter and its purported mate, tell us if they
35543e1f234Skjell  * match.
35643e1f234Skjell  */
35743e1f234Skjell static int
getmatch(int c,int mc)35843e1f234Skjell getmatch(int c, int mc)
35943e1f234Skjell {
36043e1f234Skjell 	int match = FALSE;
36143e1f234Skjell 
36243e1f234Skjell 	switch (c) {
36343e1f234Skjell 	case '"':
36443e1f234Skjell 		match = (mc == '"');
36543e1f234Skjell 		break;
36643e1f234Skjell 	case '\'':
36743e1f234Skjell 		match = (mc == '\'');
36843e1f234Skjell 		break;
36943e1f234Skjell 	case '(':
37043e1f234Skjell 		match = (mc == ')');
37143e1f234Skjell 		break;
37243e1f234Skjell 	case '[':
37343e1f234Skjell 		match = (mc == ']');
37443e1f234Skjell 		break;
37543e1f234Skjell 	case '{':
37643e1f234Skjell 		match = (mc == '}');
37743e1f234Skjell 		break;
37843e1f234Skjell 	}
37943e1f234Skjell 
38043e1f234Skjell 	return (match);
38143e1f234Skjell }
38292cb5ab0Skjell 
38392cb5ab0Skjell static int
in_whitespace(struct line * lp,int len)38492cb5ab0Skjell in_whitespace(struct line *lp, int len)
38592cb5ab0Skjell {
38692cb5ab0Skjell 	int lo;
38792cb5ab0Skjell 	int inwhitep = FALSE;
38892cb5ab0Skjell 
38992cb5ab0Skjell 	for (lo = 0; lo < len; lo++) {
39092cb5ab0Skjell 		if (!isspace(lgetc(lp, lo)))
39192cb5ab0Skjell 			break;
39292cb5ab0Skjell 		if (lo == len - 1)
39392cb5ab0Skjell 			inwhitep = TRUE;
39492cb5ab0Skjell 	}
39592cb5ab0Skjell 
39692cb5ab0Skjell 	return (inwhitep);
39792cb5ab0Skjell }
39892cb5ab0Skjell 
39992cb5ab0Skjell 
40092cb5ab0Skjell /* convert a line/offset pair to a column position (for indenting) */
40192cb5ab0Skjell static int
findcolpos(const struct buffer * bp,const struct line * lp,int lo)40292cb5ab0Skjell findcolpos(const struct buffer *bp, const struct line *lp, int lo)
40392cb5ab0Skjell {
40492cb5ab0Skjell 	int	col, i, c;
40592cb5ab0Skjell 	char tmp[5];
40692cb5ab0Skjell 
40792cb5ab0Skjell 	/* determine column */
40892cb5ab0Skjell 	col = 0;
40992cb5ab0Skjell 
41092cb5ab0Skjell 	for (i = 0; i < lo; ++i) {
41192cb5ab0Skjell 		c = lgetc(lp, i);
41238733382Sop 		if (c == '\t') {
413fb3e194eSop 			col = ntabstop(col, curbp->b_tabw);
41492cb5ab0Skjell 		} else if (ISCTRL(c) != FALSE)
41592cb5ab0Skjell 			col += 2;
41692cb5ab0Skjell 		else if (isprint(c)) {
41792cb5ab0Skjell 			col++;
41892cb5ab0Skjell 		} else {
41992cb5ab0Skjell 			col += snprintf(tmp, sizeof(tmp), "\\%o", c);
42092cb5ab0Skjell 		}
42192cb5ab0Skjell 
42292cb5ab0Skjell 	}
42392cb5ab0Skjell 	return (col);
42492cb5ab0Skjell }
42592cb5ab0Skjell 
42692cb5ab0Skjell /*
42792cb5ab0Skjell  * Find a non-blank line, searching backwards from the supplied line pointer.
42892cb5ab0Skjell  * For C, nonblank is non-preprocessor, non C++, and accounts
42992cb5ab0Skjell  * for complete C-style comments.
43092cb5ab0Skjell  */
43192cb5ab0Skjell static struct line *
findnonblank(struct line * lp)43292cb5ab0Skjell findnonblank(struct line *lp)
43392cb5ab0Skjell {
43492cb5ab0Skjell 	int lo;
43592cb5ab0Skjell 	int nonblankp = FALSE;
43692cb5ab0Skjell 	int commentp = FALSE;
43792cb5ab0Skjell 	int slashp;
43892cb5ab0Skjell 	int astp;
43992cb5ab0Skjell 	int c;
44092cb5ab0Skjell 
44192cb5ab0Skjell 	while (lback(lp) != curbp->b_headp && (commentp || !nonblankp)) {
44292cb5ab0Skjell 		lp = lback(lp);
44392cb5ab0Skjell 		slashp = FALSE;
44492cb5ab0Skjell 		astp = FALSE;
44592cb5ab0Skjell 
44692cb5ab0Skjell 		/* Potential nonblank? */
44792cb5ab0Skjell 		nonblankp = isnonblank(lp, llength(lp));
44892cb5ab0Skjell 
44992cb5ab0Skjell 		/*
45092cb5ab0Skjell 		 * Search from end, removing complete C-style
45192cb5ab0Skjell 		 * comments. If one is found, ignore it and
45292cb5ab0Skjell 		 * test for nonblankness from where it starts.
45392cb5ab0Skjell 		 */
45492cb5ab0Skjell 		for (lo = llength(lp) - 1; lo >= 0; lo--) {
45592cb5ab0Skjell 			if (!isspace(c = lgetc(lp, lo))) {
45692cb5ab0Skjell 				if (commentp) { /* find comment "open" */
45792cb5ab0Skjell 					if (c == '*')
45892cb5ab0Skjell 						astp = TRUE;
45992cb5ab0Skjell 					else if (astp && c == '/') {
46092cb5ab0Skjell 						commentp = FALSE;
46192cb5ab0Skjell 						/* whitespace to here? */
46292cb5ab0Skjell 						nonblankp = isnonblank(lp, lo);
46392cb5ab0Skjell 					}
46492cb5ab0Skjell 				} else { /* find comment "close" */
46592cb5ab0Skjell 					if (c == '/')
46692cb5ab0Skjell 						slashp = TRUE;
46792cb5ab0Skjell 					else if (slashp && c == '*')
46892cb5ab0Skjell 						/* found a comment */
46992cb5ab0Skjell 						commentp = TRUE;
47092cb5ab0Skjell 				}
47192cb5ab0Skjell 			}
47292cb5ab0Skjell 		}
47392cb5ab0Skjell 	}
47492cb5ab0Skjell 
47592cb5ab0Skjell 	/* Rewound to start of file? */
47692cb5ab0Skjell 	if (lback(lp) == curbp->b_headp && !nonblankp)
47792cb5ab0Skjell 		return (curbp->b_headp);
47892cb5ab0Skjell 
47992cb5ab0Skjell 	return (lp);
48092cb5ab0Skjell }
48192cb5ab0Skjell 
48292cb5ab0Skjell /*
48392cb5ab0Skjell  * Given a line, scan forward to 'omax' and determine if we
48492cb5ab0Skjell  * are all C whitespace.
48592cb5ab0Skjell  * Note that preprocessor directives and C++-style comments
48692cb5ab0Skjell  * count as whitespace. C-style comments do not, and must
48792cb5ab0Skjell  * be handled elsewhere.
48892cb5ab0Skjell  */
48992cb5ab0Skjell static int
isnonblank(const struct line * lp,int omax)49092cb5ab0Skjell isnonblank(const struct line *lp, int omax)
49192cb5ab0Skjell {
49292cb5ab0Skjell 	int nonblankp = FALSE;		/* Return value */
49392cb5ab0Skjell 	int slashp = FALSE;		/* Encountered slash */
49492cb5ab0Skjell 	int lo;				/* Loop index */
49592cb5ab0Skjell 	int c;				/* char being read */
49692cb5ab0Skjell 
49792cb5ab0Skjell 	/* Scan from front for preprocessor, C++ comments */
49892cb5ab0Skjell 	for (lo = 0; lo < omax; lo++) {
49992cb5ab0Skjell 		if (!isspace(c = lgetc(lp, lo))) {
50092cb5ab0Skjell 			/* Possible nonblank line */
50192cb5ab0Skjell 			nonblankp = TRUE;
50292cb5ab0Skjell 			/* skip // and # starts */
50392cb5ab0Skjell 			if (c == '#' || (slashp && c == '/')) {
50492cb5ab0Skjell 				nonblankp = FALSE;
50592cb5ab0Skjell 				break;
50692cb5ab0Skjell 			} else if (!slashp && c == '/') {
50792cb5ab0Skjell 				slashp = TRUE;
50892cb5ab0Skjell 				continue;
50992cb5ab0Skjell 			}
51092cb5ab0Skjell 		}
51192cb5ab0Skjell 		slashp = FALSE;
51292cb5ab0Skjell 	}
51392cb5ab0Skjell 	return (nonblankp);
51492cb5ab0Skjell }
515