optfunc.c revision 89019
160786Sps/*
260786Sps * Copyright (C) 1984-2000  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;
3260786Spsextern int cbufs;
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;
5760786Sps#endif
5860786Sps#if MSDOS_COMPILER
5960786Spsextern int nm_fg_color, nm_bg_color;
6060786Spsextern int bo_fg_color, bo_bg_color;
6160786Spsextern int ul_fg_color, ul_bg_color;
6260786Spsextern int so_fg_color, so_bg_color;
6360786Spsextern int bl_fg_color, bl_bg_color;
6460786Sps#endif
6560786Sps
6660786Sps
6760786Sps#if LOGFILE
6860786Sps/*
6960786Sps * Handler for -o option.
7060786Sps */
7160786Sps	public void
7260786Spsopt_o(type, s)
7360786Sps	int type;
7460786Sps	char *s;
7560786Sps{
7660786Sps	PARG parg;
7760786Sps
7860786Sps	if (secure)
7960786Sps	{
8060786Sps		error("log file support is not available", NULL_PARG);
8160786Sps		return;
8260786Sps	}
8360786Sps	switch (type)
8460786Sps	{
8560786Sps	case INIT:
8660786Sps		namelogfile = s;
8760786Sps		break;
8860786Sps	case TOGGLE:
8960786Sps		if (ch_getflags() & CH_CANSEEK)
9060786Sps		{
9160786Sps			error("Input is not a pipe", NULL_PARG);
9260786Sps			return;
9360786Sps		}
9460786Sps		if (logfile >= 0)
9560786Sps		{
9660786Sps			error("Log file is already in use", NULL_PARG);
9760786Sps			return;
9860786Sps		}
9960786Sps		s = skipsp(s);
10060786Sps		namelogfile = lglob(s);
10160786Sps		use_logfile(namelogfile);
10260786Sps		sync_logfile();
10360786Sps		break;
10460786Sps	case QUERY:
10560786Sps		if (logfile < 0)
10660786Sps			error("No log file", NULL_PARG);
10760786Sps		else
10860786Sps		{
10960786Sps			parg.p_string = unquote_file(namelogfile);
11060786Sps			error("Log file \"%s\"", &parg);
11160786Sps			free(parg.p_string);
11260786Sps		}
11360786Sps		break;
11460786Sps	}
11560786Sps}
11660786Sps
11760786Sps/*
11860786Sps * Handler for -O option.
11960786Sps */
12060786Sps	public void
12160786Spsopt__O(type, s)
12260786Sps	int type;
12360786Sps	char *s;
12460786Sps{
12560786Sps	force_logfile = TRUE;
12660786Sps	opt_o(type, s);
12760786Sps}
12860786Sps#endif
12960786Sps
13060786Sps/*
13160786Sps * Handlers for -l option.
13260786Sps */
13360786Sps	public void
13460786Spsopt_l(type, s)
13560786Sps	int type;
13660786Sps	char *s;
13760786Sps{
13860786Sps	int err;
13960786Sps	int n;
14060786Sps	char *t;
14160786Sps
14260786Sps	switch (type)
14360786Sps	{
14460786Sps	case INIT:
14560786Sps		t = s;
14660786Sps		n = getnum(&t, 'l', &err);
14760786Sps		if (err || n <= 0)
14860786Sps		{
14960786Sps			error("Line number is required after -l", NULL_PARG);
15060786Sps			return;
15160786Sps		}
15260786Sps		plusoption = TRUE;
15360786Sps		ungetsc(s);
15460786Sps		break;
15560786Sps	}
15660786Sps}
15760786Sps
15860786Sps#if USERFILE
15960786Sps	public void
16060786Spsopt_k(type, s)
16160786Sps	int type;
16260786Sps	char *s;
16360786Sps{
16460786Sps	PARG parg;
16560786Sps
16660786Sps	switch (type)
16760786Sps	{
16860786Sps	case INIT:
16960786Sps		if (lesskey(s, 0))
17060786Sps		{
17160786Sps			parg.p_string = unquote_file(s);
17260786Sps			error("Cannot use lesskey file \"%s\"", &parg);
17360786Sps			free(parg.p_string);
17460786Sps		}
17560786Sps		break;
17660786Sps	}
17760786Sps}
17860786Sps#endif
17960786Sps
18060786Sps#if TAGS
18160786Sps/*
18260786Sps * Handler for -t option.
18360786Sps */
18460786Sps	public void
18560786Spsopt_t(type, s)
18660786Sps	int type;
18760786Sps	char *s;
18860786Sps{
18960786Sps	IFILE save_ifile;
19060786Sps	POSITION pos;
19160786Sps
19260786Sps	switch (type)
19360786Sps	{
19460786Sps	case INIT:
19560786Sps		tagoption = s;
19660786Sps		/* Do the rest in main() */
19760786Sps		break;
19860786Sps	case TOGGLE:
19960786Sps		if (secure)
20060786Sps		{
20160786Sps			error("tags support is not available", NULL_PARG);
20260786Sps			break;
20360786Sps		}
20460786Sps		findtag(skipsp(s));
20560786Sps		save_ifile = save_curr_ifile();
20660786Sps		if (edit_tagfile())
20760786Sps			break;
20860786Sps		if ((pos = tagsearch()) == NULL_POSITION)
20960786Sps		{
21060786Sps			reedit_ifile(save_ifile);
21160786Sps			break;
21260786Sps		}
21360786Sps		unsave_ifile(save_ifile);
21460786Sps		jump_loc(pos, jump_sline);
21560786Sps		break;
21660786Sps	}
21760786Sps}
21860786Sps
21960786Sps/*
22060786Sps * Handler for -T option.
22160786Sps */
22260786Sps	public void
22360786Spsopt__T(type, s)
22460786Sps	int type;
22560786Sps	char *s;
22660786Sps{
22760786Sps	PARG parg;
22860786Sps
22960786Sps	switch (type)
23060786Sps	{
23160786Sps	case INIT:
23260786Sps		tags = s;
23360786Sps		break;
23460786Sps	case TOGGLE:
23560786Sps		s = skipsp(s);
23660786Sps		tags = lglob(s);
23760786Sps		break;
23860786Sps	case QUERY:
23960786Sps		parg.p_string = unquote_file(tags);
24060786Sps		error("Tags file \"%s\"", &parg);
24160786Sps		free(parg.p_string);
24260786Sps		break;
24360786Sps	}
24460786Sps}
24560786Sps#endif
24660786Sps
24760786Sps/*
24860786Sps * Handler for -p option.
24960786Sps */
25060786Sps	public void
25160786Spsopt_p(type, s)
25260786Sps	int type;
25360786Sps	register char *s;
25460786Sps{
25560786Sps	switch (type)
25660786Sps	{
25760786Sps	case INIT:
25860786Sps		/*
25960786Sps		 * Unget a search command for the specified string.
26060786Sps		 * {{ This won't work if the "/" command is
26160786Sps		 *    changed or invalidated by a .lesskey file. }}
26260786Sps		 */
26360786Sps		plusoption = TRUE;
26460786Sps		ungetsc(s);
26560786Sps		ungetsc("/");
26660786Sps		break;
26760786Sps	}
26860786Sps}
26960786Sps
27060786Sps/*
27160786Sps * Handler for -P option.
27260786Sps */
27360786Sps	public void
27460786Spsopt__P(type, s)
27560786Sps	int type;
27660786Sps	register char *s;
27760786Sps{
27860786Sps	register char **proto;
27960786Sps	PARG parg;
28060786Sps
28160786Sps	switch (type)
28260786Sps	{
28360786Sps	case INIT:
28460786Sps	case TOGGLE:
28560786Sps		/*
28660786Sps		 * Figure out which prototype string should be changed.
28760786Sps		 */
28860786Sps		switch (*s)
28960786Sps		{
29060786Sps		case 's':  proto = &prproto[PR_SHORT];	s++;	break;
29160786Sps		case 'm':  proto = &prproto[PR_MEDIUM];	s++;	break;
29260786Sps		case 'M':  proto = &prproto[PR_LONG];	s++;	break;
29360786Sps		case '=':  proto = &eqproto;		s++;	break;
29460786Sps		case 'h':  proto = &hproto;		s++;	break;
29589019Sps		case 'w':  proto = &wproto;		s++;	break;
29660786Sps		default:   proto = &prproto[PR_SHORT];		break;
29760786Sps		}
29860786Sps		free(*proto);
29960786Sps		*proto = save(s);
30060786Sps		break;
30160786Sps	case QUERY:
30260786Sps		parg.p_string = prproto[pr_type];
30360786Sps		error("%s", &parg);
30460786Sps		break;
30560786Sps	}
30660786Sps}
30760786Sps
30860786Sps/*
30960786Sps * Handler for the -b option.
31060786Sps */
31160786Sps	/*ARGSUSED*/
31260786Sps	public void
31360786Spsopt_b(type, s)
31460786Sps	int type;
31560786Sps	char *s;
31660786Sps{
31760786Sps	switch (type)
31860786Sps	{
31960786Sps	case TOGGLE:
32060786Sps	case QUERY:
32160786Sps		/*
32260786Sps		 * Allocate the new number of buffers.
32360786Sps		 */
32460786Sps		cbufs = ch_nbuf(cbufs);
32560786Sps		break;
32660786Sps	case INIT:
32760786Sps		break;
32860786Sps	}
32960786Sps}
33060786Sps
33160786Sps/*
33260786Sps * Handler for the -i option.
33360786Sps */
33460786Sps	/*ARGSUSED*/
33560786Sps	public void
33660786Spsopt_i(type, s)
33760786Sps	int type;
33860786Sps	char *s;
33960786Sps{
34060786Sps	switch (type)
34160786Sps	{
34260786Sps	case TOGGLE:
34360786Sps		chg_caseless();
34460786Sps		break;
34560786Sps	case QUERY:
34660786Sps	case INIT:
34760786Sps		break;
34860786Sps	}
34960786Sps}
35060786Sps
35160786Sps/*
35260786Sps * Handler for the -V option.
35360786Sps */
35460786Sps	/*ARGSUSED*/
35560786Sps	public void
35660786Spsopt__V(type, s)
35760786Sps	int type;
35860786Sps	char *s;
35960786Sps{
36060786Sps	switch (type)
36160786Sps	{
36260786Sps	case TOGGLE:
36360786Sps	case QUERY:
36460786Sps		dispversion();
36560786Sps		break;
36660786Sps	case INIT:
36760786Sps		/*
36860786Sps		 * Force output to stdout per GNU standard for --version output.
36960786Sps		 */
37060786Sps		any_display = 1;
37160786Sps		putstr("less ");
37260786Sps		putstr(version);
37389019Sps		putstr("\nCopyright (C) 2001 Mark Nudelman\n\n");
37460786Sps		putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
37560786Sps		putstr("For information about the terms of redistribution,\n");
37660786Sps		putstr("see the file named README in the less distribution.\n");
37789019Sps		putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
37860786Sps		quit(QUIT_OK);
37960786Sps		break;
38060786Sps	}
38160786Sps}
38260786Sps
38360786Sps#if MSDOS_COMPILER
38460786Sps/*
38560786Sps * Parse an MSDOS color descriptor.
38660786Sps */
38760786Sps   	static void
38860786Spscolordesc(s, fg_color, bg_color)
38960786Sps	char *s;
39060786Sps	int *fg_color;
39160786Sps	int *bg_color;
39260786Sps{
39360786Sps	int fg, bg;
39460786Sps	int err;
39560786Sps
39660786Sps	fg = getnum(&s, 'D', &err);
39760786Sps	if (err)
39860786Sps	{
39960786Sps		error("Missing fg color in -D", NULL_PARG);
40060786Sps		return;
40160786Sps	}
40260786Sps	if (*s != '.')
40360786Sps		bg = 0;
40460786Sps	else
40560786Sps	{
40660786Sps		s++;
40760786Sps		bg = getnum(&s, 'D', &err);
40860786Sps		if (err)
40960786Sps		{
41060786Sps			error("Missing fg color in -D", NULL_PARG);
41160786Sps			return;
41260786Sps		}
41360786Sps	}
41460786Sps	if (*s != '\0')
41560786Sps		error("Extra characters at end of -D option", NULL_PARG);
41660786Sps	*fg_color = fg;
41760786Sps	*bg_color = bg;
41860786Sps}
41960786Sps
42060786Sps/*
42160786Sps * Handler for the -D option.
42260786Sps */
42360786Sps	/*ARGSUSED*/
42460786Sps	public void
42560786Spsopt_D(type, s)
42660786Sps	int type;
42760786Sps	char *s;
42860786Sps{
42960786Sps	switch (type)
43060786Sps	{
43160786Sps	case INIT:
43260786Sps	case TOGGLE:
43360786Sps		switch (*s++)
43460786Sps		{
43560786Sps		case 'n':
43660786Sps			colordesc(s, &nm_fg_color, &nm_bg_color);
43760786Sps			break;
43860786Sps		case 'd':
43960786Sps			colordesc(s, &bo_fg_color, &bo_bg_color);
44060786Sps			break;
44160786Sps		case 'u':
44260786Sps			colordesc(s, &ul_fg_color, &ul_bg_color);
44360786Sps			break;
44460786Sps		case 'k':
44560786Sps			colordesc(s, &bl_fg_color, &bl_bg_color);
44660786Sps			break;
44760786Sps		case 's':
44860786Sps			colordesc(s, &so_fg_color, &so_bg_color);
44960786Sps			break;
45060786Sps		default:
45160786Sps			error("-D must be followed by n, d, u, k or s", NULL_PARG);
45260786Sps			break;
45360786Sps		}
45460786Sps		if (type == TOGGLE)
45560786Sps		{
45660786Sps			so_enter();
45760786Sps			so_exit();
45860786Sps		}
45960786Sps		break;
46060786Sps	case QUERY:
46160786Sps		break;
46260786Sps	}
46360786Sps}
46460786Sps#endif
46560786Sps
46660786Sps/*
46789019Sps * Handler for the -x option.
46889019Sps */
46989019Sps	public void
47089019Spsopt_x(type, s)
47189019Sps	int type;
47289019Sps	register char *s;
47389019Sps{
47489019Sps	extern int tabstops[];
47589019Sps	extern int ntabstops;
47689019Sps	extern int tabdefault;
47789019Sps	char msg[60+(4*TABSTOP_MAX)];
47889019Sps	int i;
47989019Sps	PARG p;
48089019Sps
48189019Sps	switch (type)
48289019Sps	{
48389019Sps	case INIT:
48489019Sps	case TOGGLE:
48589019Sps		/* Start at 1 because tabstops[0] is always zero. */
48689019Sps		for (i = 1;  i < TABSTOP_MAX;  )
48789019Sps		{
48889019Sps			int n = 0;
48989019Sps			while (*s >= '0' && *s <= '9')
49089019Sps				n = (10 * n) + (*s++ - '0');
49189019Sps			if (n > tabstops[i-1])
49289019Sps				tabstops[i++] = n;
49389019Sps			if (*s++ != ',')
49489019Sps				break;
49589019Sps		}
49689019Sps		if (i < 2)
49789019Sps			return;
49889019Sps		ntabstops = i;
49989019Sps		tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
50089019Sps		break;
50189019Sps	case QUERY:
50289019Sps		strcpy(msg, "Tab stops ");
50389019Sps		if (ntabstops > 2)
50489019Sps		{
50589019Sps			for (i = 1;  i < ntabstops;  i++)
50689019Sps			{
50789019Sps				if (i > 1)
50889019Sps					strcat(msg, ",");
50989019Sps				sprintf(msg+strlen(msg), "%d", tabstops[i]);
51089019Sps			}
51189019Sps			sprintf(msg+strlen(msg), " and then ");
51289019Sps		}
51389019Sps		sprintf(msg+strlen(msg), "every %d spaces",
51489019Sps			tabdefault);
51589019Sps		p.p_string = msg;
51689019Sps		error("%s", &p);
51789019Sps		break;
51889019Sps	}
51989019Sps}
52089019Sps
52189019Sps
52289019Sps/*
52360786Sps * Handler for the -" option.
52460786Sps */
52560786Sps	public void
52660786Spsopt_quote(type, s)
52760786Sps	int type;
52860786Sps	register char *s;
52960786Sps{
53060786Sps	char buf[3];
53160786Sps	PARG parg;
53260786Sps
53360786Sps	switch (type)
53460786Sps	{
53560786Sps	case INIT:
53660786Sps	case TOGGLE:
53760786Sps		if (s[1] != '\0' && s[2] != '\0')
53860786Sps		{
53960786Sps			error("-\" must be followed by 1 or 2 chars", NULL_PARG);
54060786Sps			return;
54160786Sps		}
54260786Sps		openquote = s[0];
54360786Sps		if (s[1] == '\0')
54460786Sps			closequote = openquote;
54560786Sps		else
54660786Sps			closequote = s[1];
54760786Sps		break;
54860786Sps	case QUERY:
54960786Sps		buf[0] = openquote;
55060786Sps		buf[1] = closequote;
55160786Sps		buf[2] = '\0';
55260786Sps		parg.p_string = buf;
55360786Sps		error("quotes %s", &parg);
55460786Sps		break;
55560786Sps	}
55660786Sps}
55760786Sps
55860786Sps/*
55960786Sps * "-?" means display a help message.
56060786Sps * If from the command line, exit immediately.
56160786Sps */
56260786Sps	/*ARGSUSED*/
56360786Sps	public void
56460786Spsopt_query(type, s)
56560786Sps	int type;
56660786Sps	char *s;
56760786Sps{
56860786Sps	switch (type)
56960786Sps	{
57060786Sps	case QUERY:
57160786Sps	case TOGGLE:
57260786Sps		error("Use \"h\" for help", NULL_PARG);
57360786Sps		break;
57460786Sps	case INIT:
57560786Sps		dohelp = 1;
57660786Sps	}
57760786Sps}
57860786Sps
57960786Sps/*
58060786Sps * Get the "screen window" size.
58160786Sps */
58260786Sps	public int
58360786Spsget_swindow()
58460786Sps{
58560786Sps	if (swindow > 0)
58660786Sps		return (swindow);
58760786Sps	return (sc_height + swindow);
58860786Sps}
58960786Sps
590