optfunc.c revision 170256
160786Sps/*
2170256Sdelphij * Copyright (C) 1984-2007  Mark Nudelman
360786Sps *
460786Sps * You may distribute under the terms of either the GNU General Public
560786Sps * License or the Less License, as specified in the README file.
660786Sps *
760786Sps * For more information about less, or for information on how to
860786Sps * contact the author, see the README file.
960786Sps */
1060786Sps
1160786Sps
1260786Sps/*
1360786Sps * Handling functions for command line options.
1460786Sps *
1560786Sps * Most options are handled by the generic code in option.c.
1660786Sps * But all string options, and a few non-string options, require
1760786Sps * special handling specific to the particular option.
1860786Sps * This special processing is done by the "handling functions" in this file.
1960786Sps *
2060786Sps * Each handling function is passed a "type" and, if it is a string
2160786Sps * option, the string which should be "assigned" to the option.
2260786Sps * The type may be one of:
2360786Sps *	INIT	The option is being initialized from the command line.
2460786Sps *	TOGGLE	The option is being changed from within the program.
2560786Sps *	QUERY	The setting of the option is merely being queried.
2660786Sps */
2760786Sps
2860786Sps#include "less.h"
2960786Sps#include "option.h"
3060786Sps
3160786Spsextern int nbufs;
32128345Stjrextern int bufspace;
3360786Spsextern int pr_type;
3460786Spsextern int plusoption;
3560786Spsextern int swindow;
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;
4660786Spsextern IFILE curr_ifile;
4760786Spsextern char version[];
4860786Sps#if LOGFILE
4960786Spsextern char *namelogfile;
5060786Spsextern int force_logfile;
5160786Spsextern int logfile;
5260786Sps#endif
5360786Sps#if TAGS
5460786Spspublic char *tagoption = NULL;
5560786Spsextern char *tags;
5660786Spsextern int jump_sline;
57170256Sdelphijextern int jump_sline_fraction;
58170256Sdelphijextern int less_is_more;
5960786Sps#endif
6060786Sps#if MSDOS_COMPILER
6160786Spsextern int nm_fg_color, nm_bg_color;
6260786Spsextern int bo_fg_color, bo_bg_color;
6360786Spsextern int ul_fg_color, ul_bg_color;
6460786Spsextern int so_fg_color, so_bg_color;
6560786Spsextern int bl_fg_color, bl_bg_color;
6660786Sps#endif
6760786Sps
6860786Sps
6960786Sps#if LOGFILE
7060786Sps/*
7160786Sps * Handler for -o option.
7260786Sps */
7360786Sps	public void
7460786Spsopt_o(type, s)
7560786Sps	int type;
7660786Sps	char *s;
7760786Sps{
7860786Sps	PARG parg;
7960786Sps
8060786Sps	if (secure)
8160786Sps	{
8260786Sps		error("log file support is not available", NULL_PARG);
8360786Sps		return;
8460786Sps	}
8560786Sps	switch (type)
8660786Sps	{
8760786Sps	case INIT:
8860786Sps		namelogfile = s;
8960786Sps		break;
9060786Sps	case TOGGLE:
9160786Sps		if (ch_getflags() & CH_CANSEEK)
9260786Sps		{
9360786Sps			error("Input is not a pipe", NULL_PARG);
9460786Sps			return;
9560786Sps		}
9660786Sps		if (logfile >= 0)
9760786Sps		{
9860786Sps			error("Log file is already in use", NULL_PARG);
9960786Sps			return;
10060786Sps		}
10160786Sps		s = skipsp(s);
10260786Sps		namelogfile = lglob(s);
10360786Sps		use_logfile(namelogfile);
10460786Sps		sync_logfile();
10560786Sps		break;
10660786Sps	case QUERY:
10760786Sps		if (logfile < 0)
10860786Sps			error("No log file", NULL_PARG);
10960786Sps		else
11060786Sps		{
111128345Stjr			parg.p_string = namelogfile;
11260786Sps			error("Log file \"%s\"", &parg);
11360786Sps		}
11460786Sps		break;
11560786Sps	}
11660786Sps}
11760786Sps
11860786Sps/*
11960786Sps * Handler for -O option.
12060786Sps */
12160786Sps	public void
12260786Spsopt__O(type, s)
12360786Sps	int type;
12460786Sps	char *s;
12560786Sps{
12660786Sps	force_logfile = TRUE;
12760786Sps	opt_o(type, s);
12860786Sps}
12960786Sps#endif
13060786Sps
13160786Sps/*
13260786Sps * Handlers for -l option.
13360786Sps */
13460786Sps	public void
13560786Spsopt_l(type, s)
13660786Sps	int type;
13760786Sps	char *s;
13860786Sps{
13960786Sps	int err;
14060786Sps	int n;
14160786Sps	char *t;
14260786Sps
14360786Sps	switch (type)
14460786Sps	{
14560786Sps	case INIT:
14660786Sps		t = s;
147128345Stjr		n = getnum(&t, "l", &err);
14860786Sps		if (err || n <= 0)
14960786Sps		{
15060786Sps			error("Line number is required after -l", NULL_PARG);
15160786Sps			return;
15260786Sps		}
15360786Sps		plusoption = TRUE;
15460786Sps		ungetsc(s);
15560786Sps		break;
15660786Sps	}
15760786Sps}
15860786Sps
159170256Sdelphij/*
160170256Sdelphij * Handlers for -j option.
161170256Sdelphij */
162170256Sdelphij	public void
163170256Sdelphijopt_j(type, s)
164170256Sdelphij	int type;
165170256Sdelphij	char *s;
166170256Sdelphij{
167170256Sdelphij	PARG parg;
168170256Sdelphij	char buf[16];
169170256Sdelphij	int len;
170170256Sdelphij	int err;
171170256Sdelphij
172170256Sdelphij	switch (type)
173170256Sdelphij	{
174170256Sdelphij	case INIT:
175170256Sdelphij	case TOGGLE:
176170256Sdelphij		if (*s == '.')
177170256Sdelphij		{
178170256Sdelphij			s++;
179170256Sdelphij			jump_sline_fraction = getfraction(&s, "j", &err);
180170256Sdelphij			if (err)
181170256Sdelphij				error("Invalid line fraction", NULL_PARG);
182170256Sdelphij			else
183170256Sdelphij				calc_jump_sline();
184170256Sdelphij		} else
185170256Sdelphij		{
186170256Sdelphij			int sline = getnum(&s, "j", &err);
187170256Sdelphij			if (err)
188170256Sdelphij				error("Invalid line number", NULL_PARG);
189170256Sdelphij			else
190170256Sdelphij			{
191170256Sdelphij				jump_sline = sline;
192170256Sdelphij				jump_sline_fraction = -1;
193170256Sdelphij			}
194170256Sdelphij		}
195170256Sdelphij		break;
196170256Sdelphij	case QUERY:
197170256Sdelphij		if (jump_sline_fraction < 0)
198170256Sdelphij		{
199170256Sdelphij			parg.p_int =  jump_sline;
200170256Sdelphij			error("Position target at screen line %d", &parg);
201170256Sdelphij		} else
202170256Sdelphij		{
203170256Sdelphij
204170256Sdelphij			sprintf(buf, ".%06d", jump_sline_fraction);
205170256Sdelphij			len = strlen(buf);
206170256Sdelphij			while (len > 2 && buf[len-1] == '0')
207170256Sdelphij				len--;
208170256Sdelphij			buf[len] = '\0';
209170256Sdelphij			parg.p_string = buf;
210170256Sdelphij			error("Position target at screen position %s", &parg);
211170256Sdelphij		}
212170256Sdelphij		break;
213170256Sdelphij	}
214170256Sdelphij}
215170256Sdelphij
216170256Sdelphij	public void
217170256Sdelphijcalc_jump_sline()
218170256Sdelphij{
219170256Sdelphij	if (jump_sline_fraction < 0)
220170256Sdelphij		return;
221170256Sdelphij	jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
222170256Sdelphij}
223170256Sdelphij
22460786Sps#if USERFILE
22560786Sps	public void
22660786Spsopt_k(type, s)
22760786Sps	int type;
22860786Sps	char *s;
22960786Sps{
23060786Sps	PARG parg;
23160786Sps
23260786Sps	switch (type)
23360786Sps	{
23460786Sps	case INIT:
23560786Sps		if (lesskey(s, 0))
23660786Sps		{
237128345Stjr			parg.p_string = s;
23860786Sps			error("Cannot use lesskey file \"%s\"", &parg);
23960786Sps		}
24060786Sps		break;
24160786Sps	}
24260786Sps}
24360786Sps#endif
24460786Sps
24560786Sps#if TAGS
24660786Sps/*
24760786Sps * Handler for -t option.
24860786Sps */
24960786Sps	public void
25060786Spsopt_t(type, s)
25160786Sps	int type;
25260786Sps	char *s;
25360786Sps{
25460786Sps	IFILE save_ifile;
25560786Sps	POSITION pos;
25660786Sps
25760786Sps	switch (type)
25860786Sps	{
25960786Sps	case INIT:
26060786Sps		tagoption = s;
26160786Sps		/* Do the rest in main() */
26260786Sps		break;
26360786Sps	case TOGGLE:
26460786Sps		if (secure)
26560786Sps		{
26660786Sps			error("tags support is not available", NULL_PARG);
26760786Sps			break;
26860786Sps		}
26960786Sps		findtag(skipsp(s));
27060786Sps		save_ifile = save_curr_ifile();
271161475Sdelphij		/*
272161475Sdelphij		 * Try to open the file containing the tag
273161475Sdelphij		 * and search for the tag in that file.
274161475Sdelphij		 */
275161475Sdelphij		if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
27660786Sps		{
277161475Sdelphij			/* Failed: reopen the old file. */
27860786Sps			reedit_ifile(save_ifile);
27960786Sps			break;
28060786Sps		}
28160786Sps		unsave_ifile(save_ifile);
28260786Sps		jump_loc(pos, jump_sline);
28360786Sps		break;
28460786Sps	}
28560786Sps}
28660786Sps
28760786Sps/*
28860786Sps * Handler for -T option.
28960786Sps */
29060786Sps	public void
29160786Spsopt__T(type, s)
29260786Sps	int type;
29360786Sps	char *s;
29460786Sps{
29560786Sps	PARG parg;
29660786Sps
29760786Sps	switch (type)
29860786Sps	{
29960786Sps	case INIT:
30060786Sps		tags = s;
30160786Sps		break;
30260786Sps	case TOGGLE:
30360786Sps		s = skipsp(s);
30460786Sps		tags = lglob(s);
30560786Sps		break;
30660786Sps	case QUERY:
307128345Stjr		parg.p_string = tags;
30860786Sps		error("Tags file \"%s\"", &parg);
30960786Sps		break;
31060786Sps	}
31160786Sps}
31260786Sps#endif
31360786Sps
31460786Sps/*
31560786Sps * Handler for -p option.
31660786Sps */
31760786Sps	public void
31860786Spsopt_p(type, s)
31960786Sps	int type;
32060786Sps	register char *s;
32160786Sps{
32260786Sps	switch (type)
32360786Sps	{
32460786Sps	case INIT:
32560786Sps		/*
32660786Sps		 * Unget a search command for the specified string.
32760786Sps		 * {{ This won't work if the "/" command is
32860786Sps		 *    changed or invalidated by a .lesskey file. }}
32960786Sps		 */
33060786Sps		plusoption = TRUE;
33160786Sps		ungetsc(s);
332161475Sdelphij		/*
333161475Sdelphij		 * In "more" mode, the -p argument is a command,
334161475Sdelphij		 * not a search string, so we don't need a slash.
335161475Sdelphij		 */
336170256Sdelphij		if (!less_is_more)
337161475Sdelphij			ungetsc("/");
33860786Sps		break;
33960786Sps	}
34060786Sps}
34160786Sps
34260786Sps/*
34360786Sps * Handler for -P option.
34460786Sps */
34560786Sps	public void
34660786Spsopt__P(type, s)
34760786Sps	int type;
34860786Sps	register char *s;
34960786Sps{
35060786Sps	register char **proto;
35160786Sps	PARG parg;
35260786Sps
35360786Sps	switch (type)
35460786Sps	{
35560786Sps	case INIT:
35660786Sps	case TOGGLE:
35760786Sps		/*
35860786Sps		 * Figure out which prototype string should be changed.
35960786Sps		 */
36060786Sps		switch (*s)
36160786Sps		{
36260786Sps		case 's':  proto = &prproto[PR_SHORT];	s++;	break;
36360786Sps		case 'm':  proto = &prproto[PR_MEDIUM];	s++;	break;
36460786Sps		case 'M':  proto = &prproto[PR_LONG];	s++;	break;
36560786Sps		case '=':  proto = &eqproto;		s++;	break;
36660786Sps		case 'h':  proto = &hproto;		s++;	break;
36789019Sps		case 'w':  proto = &wproto;		s++;	break;
36860786Sps		default:   proto = &prproto[PR_SHORT];		break;
36960786Sps		}
37060786Sps		free(*proto);
37160786Sps		*proto = save(s);
37260786Sps		break;
37360786Sps	case QUERY:
37460786Sps		parg.p_string = prproto[pr_type];
37560786Sps		error("%s", &parg);
37660786Sps		break;
37760786Sps	}
37860786Sps}
37960786Sps
38060786Sps/*
38160786Sps * Handler for the -b option.
38260786Sps */
38360786Sps	/*ARGSUSED*/
38460786Sps	public void
38560786Spsopt_b(type, s)
38660786Sps	int type;
38760786Sps	char *s;
38860786Sps{
38960786Sps	switch (type)
39060786Sps	{
391128345Stjr	case INIT:
39260786Sps	case TOGGLE:
39360786Sps		/*
394128345Stjr		 * Set the new number of buffers.
39560786Sps		 */
396128345Stjr		ch_setbufspace(bufspace);
39760786Sps		break;
398128345Stjr	case QUERY:
39960786Sps		break;
40060786Sps	}
40160786Sps}
40260786Sps
40360786Sps/*
40460786Sps * Handler for the -i option.
40560786Sps */
40660786Sps	/*ARGSUSED*/
40760786Sps	public void
40860786Spsopt_i(type, s)
40960786Sps	int type;
41060786Sps	char *s;
41160786Sps{
41260786Sps	switch (type)
41360786Sps	{
41460786Sps	case TOGGLE:
41560786Sps		chg_caseless();
41660786Sps		break;
41760786Sps	case QUERY:
41860786Sps	case INIT:
41960786Sps		break;
42060786Sps	}
42160786Sps}
42260786Sps
42360786Sps/*
42460786Sps * Handler for the -V option.
42560786Sps */
42660786Sps	/*ARGSUSED*/
42760786Sps	public void
42860786Spsopt__V(type, s)
42960786Sps	int type;
43060786Sps	char *s;
43160786Sps{
43260786Sps	switch (type)
43360786Sps	{
43460786Sps	case TOGGLE:
43560786Sps	case QUERY:
43660786Sps		dispversion();
43760786Sps		break;
43860786Sps	case INIT:
43960786Sps		/*
44060786Sps		 * Force output to stdout per GNU standard for --version output.
44160786Sps		 */
44260786Sps		any_display = 1;
44360786Sps		putstr("less ");
44460786Sps		putstr(version);
445161475Sdelphij		putstr("\nCopyright (C) 1984-2005 Mark Nudelman\n\n");
44660786Sps		putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
44760786Sps		putstr("For information about the terms of redistribution,\n");
44860786Sps		putstr("see the file named README in the less distribution.\n");
44989019Sps		putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
45060786Sps		quit(QUIT_OK);
45160786Sps		break;
45260786Sps	}
45360786Sps}
45460786Sps
45560786Sps#if MSDOS_COMPILER
45660786Sps/*
45760786Sps * Parse an MSDOS color descriptor.
45860786Sps */
45960786Sps   	static void
46060786Spscolordesc(s, fg_color, bg_color)
46160786Sps	char *s;
46260786Sps	int *fg_color;
46360786Sps	int *bg_color;
46460786Sps{
46560786Sps	int fg, bg;
46660786Sps	int err;
46760786Sps
468128345Stjr	fg = getnum(&s, "D", &err);
46960786Sps	if (err)
47060786Sps	{
47160786Sps		error("Missing fg color in -D", NULL_PARG);
47260786Sps		return;
47360786Sps	}
47460786Sps	if (*s != '.')
47560786Sps		bg = 0;
47660786Sps	else
47760786Sps	{
47860786Sps		s++;
479128345Stjr		bg = getnum(&s, "D", &err);
48060786Sps		if (err)
48160786Sps		{
48260786Sps			error("Missing fg color in -D", NULL_PARG);
48360786Sps			return;
48460786Sps		}
48560786Sps	}
48660786Sps	if (*s != '\0')
48760786Sps		error("Extra characters at end of -D option", NULL_PARG);
48860786Sps	*fg_color = fg;
48960786Sps	*bg_color = bg;
49060786Sps}
49160786Sps
49260786Sps/*
49360786Sps * Handler for the -D option.
49460786Sps */
49560786Sps	/*ARGSUSED*/
49660786Sps	public void
49760786Spsopt_D(type, s)
49860786Sps	int type;
49960786Sps	char *s;
50060786Sps{
50160786Sps	switch (type)
50260786Sps	{
50360786Sps	case INIT:
50460786Sps	case TOGGLE:
50560786Sps		switch (*s++)
50660786Sps		{
50760786Sps		case 'n':
50860786Sps			colordesc(s, &nm_fg_color, &nm_bg_color);
50960786Sps			break;
51060786Sps		case 'd':
51160786Sps			colordesc(s, &bo_fg_color, &bo_bg_color);
51260786Sps			break;
51360786Sps		case 'u':
51460786Sps			colordesc(s, &ul_fg_color, &ul_bg_color);
51560786Sps			break;
51660786Sps		case 'k':
51760786Sps			colordesc(s, &bl_fg_color, &bl_bg_color);
51860786Sps			break;
51960786Sps		case 's':
52060786Sps			colordesc(s, &so_fg_color, &so_bg_color);
52160786Sps			break;
52260786Sps		default:
52360786Sps			error("-D must be followed by n, d, u, k or s", NULL_PARG);
52460786Sps			break;
52560786Sps		}
52660786Sps		if (type == TOGGLE)
52760786Sps		{
528161475Sdelphij			at_enter(AT_STANDOUT);
529161475Sdelphij			at_exit();
53060786Sps		}
53160786Sps		break;
53260786Sps	case QUERY:
53360786Sps		break;
53460786Sps	}
53560786Sps}
53660786Sps#endif
53760786Sps
53860786Sps/*
53989019Sps * Handler for the -x option.
54089019Sps */
54189019Sps	public void
54289019Spsopt_x(type, s)
54389019Sps	int type;
54489019Sps	register char *s;
54589019Sps{
54689019Sps	extern int tabstops[];
54789019Sps	extern int ntabstops;
54889019Sps	extern int tabdefault;
54989019Sps	char msg[60+(4*TABSTOP_MAX)];
55089019Sps	int i;
55189019Sps	PARG p;
55289019Sps
55389019Sps	switch (type)
55489019Sps	{
55589019Sps	case INIT:
55689019Sps	case TOGGLE:
55789019Sps		/* Start at 1 because tabstops[0] is always zero. */
55889019Sps		for (i = 1;  i < TABSTOP_MAX;  )
55989019Sps		{
56089019Sps			int n = 0;
561128345Stjr			s = skipsp(s);
56289019Sps			while (*s >= '0' && *s <= '9')
56389019Sps				n = (10 * n) + (*s++ - '0');
56489019Sps			if (n > tabstops[i-1])
56589019Sps				tabstops[i++] = n;
566128345Stjr			s = skipsp(s);
56789019Sps			if (*s++ != ',')
56889019Sps				break;
56989019Sps		}
57089019Sps		if (i < 2)
57189019Sps			return;
57289019Sps		ntabstops = i;
57389019Sps		tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
57489019Sps		break;
57589019Sps	case QUERY:
57689019Sps		strcpy(msg, "Tab stops ");
57789019Sps		if (ntabstops > 2)
57889019Sps		{
57989019Sps			for (i = 1;  i < ntabstops;  i++)
58089019Sps			{
58189019Sps				if (i > 1)
58289019Sps					strcat(msg, ",");
58389019Sps				sprintf(msg+strlen(msg), "%d", tabstops[i]);
58489019Sps			}
58589019Sps			sprintf(msg+strlen(msg), " and then ");
58689019Sps		}
58789019Sps		sprintf(msg+strlen(msg), "every %d spaces",
58889019Sps			tabdefault);
58989019Sps		p.p_string = msg;
59089019Sps		error("%s", &p);
59189019Sps		break;
59289019Sps	}
59389019Sps}
59489019Sps
59589019Sps
59689019Sps/*
59760786Sps * Handler for the -" option.
59860786Sps */
59960786Sps	public void
60060786Spsopt_quote(type, s)
60160786Sps	int type;
60260786Sps	register char *s;
60360786Sps{
60460786Sps	char buf[3];
60560786Sps	PARG parg;
60660786Sps
60760786Sps	switch (type)
60860786Sps	{
60960786Sps	case INIT:
61060786Sps	case TOGGLE:
611128345Stjr		if (s[0] == '\0')
612128345Stjr		{
613128345Stjr			openquote = closequote = '\0';
614128345Stjr			break;
615128345Stjr		}
61660786Sps		if (s[1] != '\0' && s[2] != '\0')
61760786Sps		{
61860786Sps			error("-\" must be followed by 1 or 2 chars", NULL_PARG);
61960786Sps			return;
62060786Sps		}
62160786Sps		openquote = s[0];
62260786Sps		if (s[1] == '\0')
62360786Sps			closequote = openquote;
62460786Sps		else
62560786Sps			closequote = s[1];
62660786Sps		break;
62760786Sps	case QUERY:
62860786Sps		buf[0] = openquote;
62960786Sps		buf[1] = closequote;
63060786Sps		buf[2] = '\0';
63160786Sps		parg.p_string = buf;
63260786Sps		error("quotes %s", &parg);
63360786Sps		break;
63460786Sps	}
63560786Sps}
63660786Sps
63760786Sps/*
63860786Sps * "-?" means display a help message.
63960786Sps * If from the command line, exit immediately.
64060786Sps */
64160786Sps	/*ARGSUSED*/
64260786Sps	public void
64360786Spsopt_query(type, s)
64460786Sps	int type;
64560786Sps	char *s;
64660786Sps{
64760786Sps	switch (type)
64860786Sps	{
64960786Sps	case QUERY:
65060786Sps	case TOGGLE:
65160786Sps		error("Use \"h\" for help", NULL_PARG);
65260786Sps		break;
65360786Sps	case INIT:
65460786Sps		dohelp = 1;
65560786Sps	}
65660786Sps}
65760786Sps
65860786Sps/*
65960786Sps * Get the "screen window" size.
66060786Sps */
66160786Sps	public int
66260786Spsget_swindow()
66360786Sps{
66460786Sps	if (swindow > 0)
66560786Sps		return (swindow);
66660786Sps	return (sc_height + swindow);
66760786Sps}
66860786Sps
669