1238730Sdelphij/*
2294286Sdelphij * Copyright (C) 1984-2015  Mark Nudelman
3238730Sdelphij *
4238730Sdelphij * You may distribute under the terms of either the GNU General Public
5238730Sdelphij * License or the Less License, as specified in the README file.
6238730Sdelphij *
7238730Sdelphij * For more information, see the README file.
8238730Sdelphij */
960786Sps
1060786Sps
1160786Sps/*
1260786Sps * Handling functions for command line options.
1360786Sps *
1460786Sps * Most options are handled by the generic code in option.c.
1560786Sps * But all string options, and a few non-string options, require
1660786Sps * special handling specific to the particular option.
1760786Sps * This special processing is done by the "handling functions" in this file.
1860786Sps *
1960786Sps * Each handling function is passed a "type" and, if it is a string
2060786Sps * option, the string which should be "assigned" to the option.
2160786Sps * The type may be one of:
2260786Sps *	INIT	The option is being initialized from the command line.
2360786Sps *	TOGGLE	The option is being changed from within the program.
2460786Sps *	QUERY	The setting of the option is merely being queried.
2560786Sps */
2660786Sps
2760786Sps#include "less.h"
2860786Sps#include "option.h"
2960786Sps
3060786Spsextern int nbufs;
31128345Stjrextern int bufspace;
3260786Spsextern int pr_type;
3360786Spsextern int plusoption;
3460786Spsextern int swindow;
35195941Sdelphijextern int sc_width;
3660786Spsextern int sc_height;
3760786Spsextern int secure;
3860786Spsextern int dohelp;
3960786Spsextern int any_display;
4060786Spsextern char openquote;
4160786Spsextern char closequote;
4260786Spsextern char *prproto[];
4360786Spsextern char *eqproto;
4460786Spsextern char *hproto;
4589019Spsextern char *wproto;
46294286Sdelphijextern char *every_first_cmd;
4760786Spsextern IFILE curr_ifile;
4860786Spsextern char version[];
49170964Sdelphijextern int jump_sline;
50170964Sdelphijextern int jump_sline_fraction;
51195941Sdelphijextern int shift_count;
52195941Sdelphijextern int shift_count_fraction;
53170964Sdelphijextern int less_is_more;
5460786Sps#if LOGFILE
5560786Spsextern char *namelogfile;
5660786Spsextern int force_logfile;
5760786Spsextern int logfile;
5860786Sps#endif
5960786Sps#if TAGS
6060786Spspublic char *tagoption = NULL;
6160786Spsextern char *tags;
62294286Sdelphijextern char ztags[];
6360786Sps#endif
6460786Sps#if MSDOS_COMPILER
6560786Spsextern int nm_fg_color, nm_bg_color;
6660786Spsextern int bo_fg_color, bo_bg_color;
6760786Spsextern int ul_fg_color, ul_bg_color;
6860786Spsextern int so_fg_color, so_bg_color;
6960786Spsextern int bl_fg_color, bl_bg_color;
7060786Sps#endif
7160786Sps
7260786Sps
7360786Sps#if LOGFILE
7460786Sps/*
7560786Sps * Handler for -o option.
7660786Sps */
7760786Sps	public void
7860786Spsopt_o(type, s)
7960786Sps	int type;
8060786Sps	char *s;
8160786Sps{
8260786Sps	PARG parg;
8360786Sps
8460786Sps	if (secure)
8560786Sps	{
8660786Sps		error("log file support is not available", NULL_PARG);
8760786Sps		return;
8860786Sps	}
8960786Sps	switch (type)
9060786Sps	{
9160786Sps	case INIT:
92294286Sdelphij		namelogfile = save(s);
9360786Sps		break;
9460786Sps	case TOGGLE:
9560786Sps		if (ch_getflags() & CH_CANSEEK)
9660786Sps		{
9760786Sps			error("Input is not a pipe", NULL_PARG);
9860786Sps			return;
9960786Sps		}
10060786Sps		if (logfile >= 0)
10160786Sps		{
10260786Sps			error("Log file is already in use", NULL_PARG);
10360786Sps			return;
10460786Sps		}
10560786Sps		s = skipsp(s);
106294286Sdelphij		if (namelogfile != NULL)
107294286Sdelphij			free(namelogfile);
10860786Sps		namelogfile = lglob(s);
10960786Sps		use_logfile(namelogfile);
11060786Sps		sync_logfile();
11160786Sps		break;
11260786Sps	case QUERY:
11360786Sps		if (logfile < 0)
11460786Sps			error("No log file", NULL_PARG);
11560786Sps		else
11660786Sps		{
117128345Stjr			parg.p_string = namelogfile;
11860786Sps			error("Log file \"%s\"", &parg);
11960786Sps		}
12060786Sps		break;
12160786Sps	}
12260786Sps}
12360786Sps
12460786Sps/*
12560786Sps * Handler for -O option.
12660786Sps */
12760786Sps	public void
12860786Spsopt__O(type, s)
12960786Sps	int type;
13060786Sps	char *s;
13160786Sps{
13260786Sps	force_logfile = TRUE;
13360786Sps	opt_o(type, s);
13460786Sps}
13560786Sps#endif
13660786Sps
13760786Sps/*
138170256Sdelphij * Handlers for -j option.
139170256Sdelphij */
140170256Sdelphij	public void
141170256Sdelphijopt_j(type, s)
142170256Sdelphij	int type;
143170256Sdelphij	char *s;
144170256Sdelphij{
145170256Sdelphij	PARG parg;
146170256Sdelphij	char buf[16];
147170256Sdelphij	int len;
148170256Sdelphij	int err;
149170256Sdelphij
150170256Sdelphij	switch (type)
151170256Sdelphij	{
152170256Sdelphij	case INIT:
153170256Sdelphij	case TOGGLE:
154170256Sdelphij		if (*s == '.')
155170256Sdelphij		{
156170256Sdelphij			s++;
157170256Sdelphij			jump_sline_fraction = getfraction(&s, "j", &err);
158170256Sdelphij			if (err)
159170256Sdelphij				error("Invalid line fraction", NULL_PARG);
160170256Sdelphij			else
161170256Sdelphij				calc_jump_sline();
162170256Sdelphij		} else
163170256Sdelphij		{
164170256Sdelphij			int sline = getnum(&s, "j", &err);
165170256Sdelphij			if (err)
166170256Sdelphij				error("Invalid line number", NULL_PARG);
167170256Sdelphij			else
168170256Sdelphij			{
169170256Sdelphij				jump_sline = sline;
170170256Sdelphij				jump_sline_fraction = -1;
171170256Sdelphij			}
172170256Sdelphij		}
173170256Sdelphij		break;
174170256Sdelphij	case QUERY:
175170256Sdelphij		if (jump_sline_fraction < 0)
176170256Sdelphij		{
177170256Sdelphij			parg.p_int =  jump_sline;
178170256Sdelphij			error("Position target at screen line %d", &parg);
179170256Sdelphij		} else
180170256Sdelphij		{
181170256Sdelphij
182170256Sdelphij			sprintf(buf, ".%06d", jump_sline_fraction);
183294286Sdelphij			len = (int) strlen(buf);
184170256Sdelphij			while (len > 2 && buf[len-1] == '0')
185170256Sdelphij				len--;
186170256Sdelphij			buf[len] = '\0';
187170256Sdelphij			parg.p_string = buf;
188170256Sdelphij			error("Position target at screen position %s", &parg);
189170256Sdelphij		}
190170256Sdelphij		break;
191170256Sdelphij	}
192170256Sdelphij}
193170256Sdelphij
194170256Sdelphij	public void
195170256Sdelphijcalc_jump_sline()
196170256Sdelphij{
197170256Sdelphij	if (jump_sline_fraction < 0)
198170256Sdelphij		return;
199170256Sdelphij	jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
200170256Sdelphij}
201170256Sdelphij
202195941Sdelphij/*
203195941Sdelphij * Handlers for -# option.
204195941Sdelphij */
205195941Sdelphij	public void
206195941Sdelphijopt_shift(type, s)
207195941Sdelphij	int type;
208195941Sdelphij	char *s;
209195941Sdelphij{
210195941Sdelphij	PARG parg;
211195941Sdelphij	char buf[16];
212195941Sdelphij	int len;
213195941Sdelphij	int err;
214195941Sdelphij
215195941Sdelphij	switch (type)
216195941Sdelphij	{
217195941Sdelphij	case INIT:
218195941Sdelphij	case TOGGLE:
219195941Sdelphij		if (*s == '.')
220195941Sdelphij		{
221195941Sdelphij			s++;
222195941Sdelphij			shift_count_fraction = getfraction(&s, "#", &err);
223195941Sdelphij			if (err)
224195941Sdelphij				error("Invalid column fraction", NULL_PARG);
225195941Sdelphij			else
226195941Sdelphij				calc_shift_count();
227195941Sdelphij		} else
228195941Sdelphij		{
229195941Sdelphij			int hs = getnum(&s, "#", &err);
230195941Sdelphij			if (err)
231195941Sdelphij				error("Invalid column number", NULL_PARG);
232195941Sdelphij			else
233195941Sdelphij			{
234195941Sdelphij				shift_count = hs;
235195941Sdelphij				shift_count_fraction = -1;
236195941Sdelphij			}
237195941Sdelphij		}
238195941Sdelphij		break;
239195941Sdelphij	case QUERY:
240195941Sdelphij		if (shift_count_fraction < 0)
241195941Sdelphij		{
242195941Sdelphij			parg.p_int = shift_count;
243195941Sdelphij			error("Horizontal shift %d columns", &parg);
244195941Sdelphij		} else
245195941Sdelphij		{
246195941Sdelphij
247195941Sdelphij			sprintf(buf, ".%06d", shift_count_fraction);
248294286Sdelphij			len = (int) strlen(buf);
249195941Sdelphij			while (len > 2 && buf[len-1] == '0')
250195941Sdelphij				len--;
251195941Sdelphij			buf[len] = '\0';
252195941Sdelphij			parg.p_string = buf;
253195941Sdelphij			error("Horizontal shift %s of screen width", &parg);
254195941Sdelphij		}
255195941Sdelphij		break;
256195941Sdelphij	}
257195941Sdelphij}
258195941Sdelphij	public void
259195941Sdelphijcalc_shift_count()
260195941Sdelphij{
261195941Sdelphij	if (shift_count_fraction < 0)
262195941Sdelphij		return;
263195941Sdelphij	shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
264195941Sdelphij}
265195941Sdelphij
26660786Sps#if USERFILE
26760786Sps	public void
26860786Spsopt_k(type, s)
26960786Sps	int type;
27060786Sps	char *s;
27160786Sps{
27260786Sps	PARG parg;
27360786Sps
27460786Sps	switch (type)
27560786Sps	{
27660786Sps	case INIT:
27760786Sps		if (lesskey(s, 0))
27860786Sps		{
279128345Stjr			parg.p_string = s;
28060786Sps			error("Cannot use lesskey file \"%s\"", &parg);
28160786Sps		}
28260786Sps		break;
28360786Sps	}
28460786Sps}
28560786Sps#endif
28660786Sps
28760786Sps#if TAGS
28860786Sps/*
28960786Sps * Handler for -t option.
29060786Sps */
29160786Sps	public void
29260786Spsopt_t(type, s)
29360786Sps	int type;
29460786Sps	char *s;
29560786Sps{
29660786Sps	IFILE save_ifile;
29760786Sps	POSITION pos;
29860786Sps
29960786Sps	switch (type)
30060786Sps	{
30160786Sps	case INIT:
302294286Sdelphij		tagoption = save(s);
30360786Sps		/* Do the rest in main() */
30460786Sps		break;
30560786Sps	case TOGGLE:
30660786Sps		if (secure)
30760786Sps		{
30860786Sps			error("tags support is not available", NULL_PARG);
30960786Sps			break;
31060786Sps		}
31160786Sps		findtag(skipsp(s));
31260786Sps		save_ifile = save_curr_ifile();
313161475Sdelphij		/*
314161475Sdelphij		 * Try to open the file containing the tag
315161475Sdelphij		 * and search for the tag in that file.
316161475Sdelphij		 */
317161475Sdelphij		if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
31860786Sps		{
319161475Sdelphij			/* Failed: reopen the old file. */
32060786Sps			reedit_ifile(save_ifile);
32160786Sps			break;
32260786Sps		}
32360786Sps		unsave_ifile(save_ifile);
32460786Sps		jump_loc(pos, jump_sline);
32560786Sps		break;
32660786Sps	}
32760786Sps}
32860786Sps
32960786Sps/*
33060786Sps * Handler for -T option.
33160786Sps */
33260786Sps	public void
33360786Spsopt__T(type, s)
33460786Sps	int type;
33560786Sps	char *s;
33660786Sps{
33760786Sps	PARG parg;
33860786Sps
33960786Sps	switch (type)
34060786Sps	{
34160786Sps	case INIT:
342294286Sdelphij		tags = save(s);
34360786Sps		break;
34460786Sps	case TOGGLE:
34560786Sps		s = skipsp(s);
346294286Sdelphij		if (tags != NULL && tags != ztags)
347294286Sdelphij			free(tags);
34860786Sps		tags = lglob(s);
34960786Sps		break;
35060786Sps	case QUERY:
351128345Stjr		parg.p_string = tags;
35260786Sps		error("Tags file \"%s\"", &parg);
35360786Sps		break;
35460786Sps	}
35560786Sps}
35660786Sps#endif
35760786Sps
35860786Sps/*
35960786Sps * Handler for -p option.
36060786Sps */
36160786Sps	public void
36260786Spsopt_p(type, s)
36360786Sps	int type;
36460786Sps	register char *s;
36560786Sps{
36660786Sps	switch (type)
36760786Sps	{
36860786Sps	case INIT:
36960786Sps		/*
370294286Sdelphij		 * Unget a command for the specified string.
37160786Sps		 */
372294286Sdelphij		if (less_is_more)
373294286Sdelphij		{
374294286Sdelphij			/*
375294286Sdelphij			 * In "more" mode, the -p argument is a command,
376294286Sdelphij			 * not a search string, so we don't need a slash.
377294286Sdelphij			 */
378294286Sdelphij			every_first_cmd = save(s);
379294286Sdelphij		} else
380294286Sdelphij		{
381294286Sdelphij			plusoption = TRUE;
382294286Sdelphij			ungetcc(CHAR_END_COMMAND);
383294286Sdelphij			ungetsc(s);
384294286Sdelphij			 /*
385294286Sdelphij			  * {{ This won't work if the "/" command is
386294286Sdelphij			  *    changed or invalidated by a .lesskey file. }}
387294286Sdelphij			  */
388161475Sdelphij			ungetsc("/");
389294286Sdelphij		}
39060786Sps		break;
39160786Sps	}
39260786Sps}
39360786Sps
39460786Sps/*
39560786Sps * Handler for -P option.
39660786Sps */
39760786Sps	public void
39860786Spsopt__P(type, s)
39960786Sps	int type;
40060786Sps	register char *s;
40160786Sps{
40260786Sps	register char **proto;
40360786Sps	PARG parg;
40460786Sps
40560786Sps	switch (type)
40660786Sps	{
40760786Sps	case INIT:
40860786Sps	case TOGGLE:
40960786Sps		/*
41060786Sps		 * Figure out which prototype string should be changed.
41160786Sps		 */
41260786Sps		switch (*s)
41360786Sps		{
41460786Sps		case 's':  proto = &prproto[PR_SHORT];	s++;	break;
41560786Sps		case 'm':  proto = &prproto[PR_MEDIUM];	s++;	break;
41660786Sps		case 'M':  proto = &prproto[PR_LONG];	s++;	break;
41760786Sps		case '=':  proto = &eqproto;		s++;	break;
41860786Sps		case 'h':  proto = &hproto;		s++;	break;
41989019Sps		case 'w':  proto = &wproto;		s++;	break;
42060786Sps		default:   proto = &prproto[PR_SHORT];		break;
42160786Sps		}
42260786Sps		free(*proto);
42360786Sps		*proto = save(s);
42460786Sps		break;
42560786Sps	case QUERY:
42660786Sps		parg.p_string = prproto[pr_type];
42760786Sps		error("%s", &parg);
42860786Sps		break;
42960786Sps	}
43060786Sps}
43160786Sps
43260786Sps/*
43360786Sps * Handler for the -b option.
43460786Sps */
43560786Sps	/*ARGSUSED*/
43660786Sps	public void
43760786Spsopt_b(type, s)
43860786Sps	int type;
43960786Sps	char *s;
44060786Sps{
44160786Sps	switch (type)
44260786Sps	{
443128345Stjr	case INIT:
44460786Sps	case TOGGLE:
44560786Sps		/*
446128345Stjr		 * Set the new number of buffers.
44760786Sps		 */
448128345Stjr		ch_setbufspace(bufspace);
44960786Sps		break;
450128345Stjr	case QUERY:
45160786Sps		break;
45260786Sps	}
45360786Sps}
45460786Sps
45560786Sps/*
45660786Sps * Handler for the -i option.
45760786Sps */
45860786Sps	/*ARGSUSED*/
45960786Sps	public void
46060786Spsopt_i(type, s)
46160786Sps	int type;
46260786Sps	char *s;
46360786Sps{
46460786Sps	switch (type)
46560786Sps	{
46660786Sps	case TOGGLE:
46760786Sps		chg_caseless();
46860786Sps		break;
46960786Sps	case QUERY:
47060786Sps	case INIT:
47160786Sps		break;
47260786Sps	}
47360786Sps}
47460786Sps
47560786Sps/*
47660786Sps * Handler for the -V option.
47760786Sps */
47860786Sps	/*ARGSUSED*/
47960786Sps	public void
48060786Spsopt__V(type, s)
48160786Sps	int type;
48260786Sps	char *s;
48360786Sps{
48460786Sps	switch (type)
48560786Sps	{
48660786Sps	case TOGGLE:
48760786Sps	case QUERY:
48860786Sps		dispversion();
48960786Sps		break;
49060786Sps	case INIT:
49160786Sps		/*
49260786Sps		 * Force output to stdout per GNU standard for --version output.
49360786Sps		 */
49460786Sps		any_display = 1;
49560786Sps		putstr("less ");
49660786Sps		putstr(version);
497237613Sdelphij		putstr(" (");
498237613Sdelphij#if HAVE_GNU_REGEX
499237613Sdelphij		putstr("GNU ");
500237613Sdelphij#endif
501237613Sdelphij#if HAVE_POSIX_REGCOMP
502237613Sdelphij		putstr("POSIX ");
503237613Sdelphij#endif
504237613Sdelphij#if HAVE_PCRE
505237613Sdelphij		putstr("PCRE ");
506237613Sdelphij#endif
507237613Sdelphij#if HAVE_RE_COMP
508237613Sdelphij		putstr("BSD ");
509237613Sdelphij#endif
510237613Sdelphij#if HAVE_REGCMP
511237613Sdelphij		putstr("V8 ");
512237613Sdelphij#endif
513237613Sdelphij#if HAVE_V8_REGCOMP
514237613Sdelphij		putstr("Spencer V8 ");
515237613Sdelphij#endif
516237613Sdelphij#if !HAVE_GNU_REGEX && !HAVE_POSIX_REGCOMP && !HAVE_PCRE && !HAVE_RE_COMP && !HAVE_REGCMP && !HAVE_V8_REGCOMP
517237613Sdelphij		putstr("no ");
518237613Sdelphij#endif
519237613Sdelphij		putstr("regular expressions)\n");
520294286Sdelphij		putstr("Copyright (C) 1984-2015  Mark Nudelman\n\n");
52160786Sps		putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
52260786Sps		putstr("For information about the terms of redistribution,\n");
52360786Sps		putstr("see the file named README in the less distribution.\n");
52489019Sps		putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
52560786Sps		quit(QUIT_OK);
52660786Sps		break;
52760786Sps	}
52860786Sps}
52960786Sps
53060786Sps#if MSDOS_COMPILER
53160786Sps/*
53260786Sps * Parse an MSDOS color descriptor.
53360786Sps */
53460786Sps   	static void
53560786Spscolordesc(s, fg_color, bg_color)
53660786Sps	char *s;
53760786Sps	int *fg_color;
53860786Sps	int *bg_color;
53960786Sps{
54060786Sps	int fg, bg;
54160786Sps	int err;
54260786Sps
543128345Stjr	fg = getnum(&s, "D", &err);
54460786Sps	if (err)
54560786Sps	{
54660786Sps		error("Missing fg color in -D", NULL_PARG);
54760786Sps		return;
54860786Sps	}
54960786Sps	if (*s != '.')
550191930Sdelphij		bg = nm_bg_color;
55160786Sps	else
55260786Sps	{
55360786Sps		s++;
554128345Stjr		bg = getnum(&s, "D", &err);
55560786Sps		if (err)
55660786Sps		{
557191930Sdelphij			error("Missing bg color in -D", NULL_PARG);
55860786Sps			return;
55960786Sps		}
56060786Sps	}
56160786Sps	if (*s != '\0')
56260786Sps		error("Extra characters at end of -D option", NULL_PARG);
56360786Sps	*fg_color = fg;
56460786Sps	*bg_color = bg;
56560786Sps}
56660786Sps
56760786Sps/*
56860786Sps * Handler for the -D option.
56960786Sps */
57060786Sps	/*ARGSUSED*/
57160786Sps	public void
57260786Spsopt_D(type, s)
57360786Sps	int type;
57460786Sps	char *s;
57560786Sps{
57660786Sps	switch (type)
57760786Sps	{
57860786Sps	case INIT:
57960786Sps	case TOGGLE:
58060786Sps		switch (*s++)
58160786Sps		{
58260786Sps		case 'n':
58360786Sps			colordesc(s, &nm_fg_color, &nm_bg_color);
58460786Sps			break;
58560786Sps		case 'd':
58660786Sps			colordesc(s, &bo_fg_color, &bo_bg_color);
58760786Sps			break;
58860786Sps		case 'u':
58960786Sps			colordesc(s, &ul_fg_color, &ul_bg_color);
59060786Sps			break;
59160786Sps		case 'k':
59260786Sps			colordesc(s, &bl_fg_color, &bl_bg_color);
59360786Sps			break;
59460786Sps		case 's':
59560786Sps			colordesc(s, &so_fg_color, &so_bg_color);
59660786Sps			break;
59760786Sps		default:
59860786Sps			error("-D must be followed by n, d, u, k or s", NULL_PARG);
59960786Sps			break;
60060786Sps		}
60160786Sps		if (type == TOGGLE)
60260786Sps		{
603161475Sdelphij			at_enter(AT_STANDOUT);
604161475Sdelphij			at_exit();
60560786Sps		}
60660786Sps		break;
60760786Sps	case QUERY:
60860786Sps		break;
60960786Sps	}
61060786Sps}
61160786Sps#endif
61260786Sps
61360786Sps/*
61489019Sps * Handler for the -x option.
61589019Sps */
61689019Sps	public void
61789019Spsopt_x(type, s)
61889019Sps	int type;
61989019Sps	register char *s;
62089019Sps{
62189019Sps	extern int tabstops[];
62289019Sps	extern int ntabstops;
62389019Sps	extern int tabdefault;
62489019Sps	char msg[60+(4*TABSTOP_MAX)];
62589019Sps	int i;
62689019Sps	PARG p;
62789019Sps
62889019Sps	switch (type)
62989019Sps	{
63089019Sps	case INIT:
63189019Sps	case TOGGLE:
63289019Sps		/* Start at 1 because tabstops[0] is always zero. */
63389019Sps		for (i = 1;  i < TABSTOP_MAX;  )
63489019Sps		{
63589019Sps			int n = 0;
636128345Stjr			s = skipsp(s);
63789019Sps			while (*s >= '0' && *s <= '9')
63889019Sps				n = (10 * n) + (*s++ - '0');
63989019Sps			if (n > tabstops[i-1])
64089019Sps				tabstops[i++] = n;
641128345Stjr			s = skipsp(s);
64289019Sps			if (*s++ != ',')
64389019Sps				break;
64489019Sps		}
64589019Sps		if (i < 2)
64689019Sps			return;
64789019Sps		ntabstops = i;
64889019Sps		tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
64989019Sps		break;
65089019Sps	case QUERY:
65189019Sps		strcpy(msg, "Tab stops ");
65289019Sps		if (ntabstops > 2)
65389019Sps		{
65489019Sps			for (i = 1;  i < ntabstops;  i++)
65589019Sps			{
65689019Sps				if (i > 1)
65789019Sps					strcat(msg, ",");
65889019Sps				sprintf(msg+strlen(msg), "%d", tabstops[i]);
65989019Sps			}
66089019Sps			sprintf(msg+strlen(msg), " and then ");
66189019Sps		}
66289019Sps		sprintf(msg+strlen(msg), "every %d spaces",
66389019Sps			tabdefault);
66489019Sps		p.p_string = msg;
66589019Sps		error("%s", &p);
66689019Sps		break;
66789019Sps	}
66889019Sps}
66989019Sps
67089019Sps
67189019Sps/*
67260786Sps * Handler for the -" option.
67360786Sps */
67460786Sps	public void
67560786Spsopt_quote(type, s)
67660786Sps	int type;
67760786Sps	register char *s;
67860786Sps{
67960786Sps	char buf[3];
68060786Sps	PARG parg;
68160786Sps
68260786Sps	switch (type)
68360786Sps	{
68460786Sps	case INIT:
68560786Sps	case TOGGLE:
686128345Stjr		if (s[0] == '\0')
687128345Stjr		{
688128345Stjr			openquote = closequote = '\0';
689128345Stjr			break;
690128345Stjr		}
69160786Sps		if (s[1] != '\0' && s[2] != '\0')
69260786Sps		{
69360786Sps			error("-\" must be followed by 1 or 2 chars", NULL_PARG);
69460786Sps			return;
69560786Sps		}
69660786Sps		openquote = s[0];
69760786Sps		if (s[1] == '\0')
69860786Sps			closequote = openquote;
69960786Sps		else
70060786Sps			closequote = s[1];
70160786Sps		break;
70260786Sps	case QUERY:
70360786Sps		buf[0] = openquote;
70460786Sps		buf[1] = closequote;
70560786Sps		buf[2] = '\0';
70660786Sps		parg.p_string = buf;
70760786Sps		error("quotes %s", &parg);
70860786Sps		break;
70960786Sps	}
71060786Sps}
71160786Sps
71260786Sps/*
71360786Sps * "-?" means display a help message.
71460786Sps * If from the command line, exit immediately.
71560786Sps */
71660786Sps	/*ARGSUSED*/
71760786Sps	public void
71860786Spsopt_query(type, s)
71960786Sps	int type;
72060786Sps	char *s;
72160786Sps{
72260786Sps	switch (type)
72360786Sps	{
72460786Sps	case QUERY:
72560786Sps	case TOGGLE:
72660786Sps		error("Use \"h\" for help", NULL_PARG);
72760786Sps		break;
72860786Sps	case INIT:
72960786Sps		dohelp = 1;
73060786Sps	}
73160786Sps}
73260786Sps
73360786Sps/*
73460786Sps * Get the "screen window" size.
73560786Sps */
73660786Sps	public int
73760786Spsget_swindow()
73860786Sps{
73960786Sps	if (swindow > 0)
74060786Sps		return (swindow);
74160786Sps	return (sc_height + swindow);
74260786Sps}
74360786Sps
744