optfunc.c revision 161475
1/*
2 * Copyright (C) 1984-2005  Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
10
11
12/*
13 * Handling functions for command line options.
14 *
15 * Most options are handled by the generic code in option.c.
16 * But all string options, and a few non-string options, require
17 * special handling specific to the particular option.
18 * This special processing is done by the "handling functions" in this file.
19 *
20 * Each handling function is passed a "type" and, if it is a string
21 * option, the string which should be "assigned" to the option.
22 * The type may be one of:
23 *	INIT	The option is being initialized from the command line.
24 *	TOGGLE	The option is being changed from within the program.
25 *	QUERY	The setting of the option is merely being queried.
26 */
27
28#include "less.h"
29#include "option.h"
30
31extern int nbufs;
32extern int bufspace;
33extern int pr_type;
34extern int plusoption;
35extern int swindow;
36extern int sc_height;
37extern int secure;
38extern int dohelp;
39extern int any_display;
40extern int less_is_more;
41extern char openquote;
42extern char closequote;
43extern char *prproto[];
44extern char *eqproto;
45extern char *hproto;
46extern char *wproto;
47extern IFILE curr_ifile;
48extern char version[];
49#if LOGFILE
50extern char *namelogfile;
51extern int force_logfile;
52extern int logfile;
53#endif
54#if TAGS
55public char *tagoption = NULL;
56extern char *tags;
57extern int jump_sline;
58#endif
59#if MSDOS_COMPILER
60extern int nm_fg_color, nm_bg_color;
61extern int bo_fg_color, bo_bg_color;
62extern int ul_fg_color, ul_bg_color;
63extern int so_fg_color, so_bg_color;
64extern int bl_fg_color, bl_bg_color;
65#endif
66
67
68#if LOGFILE
69/*
70 * Handler for -o option.
71 */
72	public void
73opt_o(type, s)
74	int type;
75	char *s;
76{
77	PARG parg;
78
79	if (secure)
80	{
81		error("log file support is not available", NULL_PARG);
82		return;
83	}
84	switch (type)
85	{
86	case INIT:
87		namelogfile = s;
88		break;
89	case TOGGLE:
90		if (ch_getflags() & CH_CANSEEK)
91		{
92			error("Input is not a pipe", NULL_PARG);
93			return;
94		}
95		if (logfile >= 0)
96		{
97			error("Log file is already in use", NULL_PARG);
98			return;
99		}
100		s = skipsp(s);
101		namelogfile = lglob(s);
102		use_logfile(namelogfile);
103		sync_logfile();
104		break;
105	case QUERY:
106		if (logfile < 0)
107			error("No log file", NULL_PARG);
108		else
109		{
110			parg.p_string = namelogfile;
111			error("Log file \"%s\"", &parg);
112		}
113		break;
114	}
115}
116
117/*
118 * Handler for -O option.
119 */
120	public void
121opt__O(type, s)
122	int type;
123	char *s;
124{
125	force_logfile = TRUE;
126	opt_o(type, s);
127}
128#endif
129
130/*
131 * Handlers for -l option.
132 */
133	public void
134opt_l(type, s)
135	int type;
136	char *s;
137{
138	int err;
139	int n;
140	char *t;
141
142	switch (type)
143	{
144	case INIT:
145		t = s;
146		n = getnum(&t, "l", &err);
147		if (err || n <= 0)
148		{
149			error("Line number is required after -l", NULL_PARG);
150			return;
151		}
152		plusoption = TRUE;
153		ungetsc(s);
154		break;
155	}
156}
157
158#if USERFILE
159	public void
160opt_k(type, s)
161	int type;
162	char *s;
163{
164	PARG parg;
165
166	switch (type)
167	{
168	case INIT:
169		if (lesskey(s, 0))
170		{
171			parg.p_string = s;
172			error("Cannot use lesskey file \"%s\"", &parg);
173		}
174		break;
175	}
176}
177#endif
178
179#if TAGS
180/*
181 * Handler for -t option.
182 */
183	public void
184opt_t(type, s)
185	int type;
186	char *s;
187{
188	IFILE save_ifile;
189	POSITION pos;
190
191	switch (type)
192	{
193	case INIT:
194		tagoption = s;
195		/* Do the rest in main() */
196		break;
197	case TOGGLE:
198		if (secure)
199		{
200			error("tags support is not available", NULL_PARG);
201			break;
202		}
203		findtag(skipsp(s));
204		save_ifile = save_curr_ifile();
205		/*
206		 * Try to open the file containing the tag
207		 * and search for the tag in that file.
208		 */
209		if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
210		{
211			/* Failed: reopen the old file. */
212			reedit_ifile(save_ifile);
213			break;
214		}
215		unsave_ifile(save_ifile);
216		jump_loc(pos, jump_sline);
217		break;
218	}
219}
220
221/*
222 * Handler for -T option.
223 */
224	public void
225opt__T(type, s)
226	int type;
227	char *s;
228{
229	PARG parg;
230
231	switch (type)
232	{
233	case INIT:
234		tags = s;
235		break;
236	case TOGGLE:
237		s = skipsp(s);
238		tags = lglob(s);
239		break;
240	case QUERY:
241		parg.p_string = tags;
242		error("Tags file \"%s\"", &parg);
243		break;
244	}
245}
246#endif
247
248/*
249 * Handler for -p option.
250 */
251	public void
252opt_p(type, s)
253	int type;
254	register char *s;
255{
256	switch (type)
257	{
258	case INIT:
259		/*
260		 * Unget a search command for the specified string.
261		 * {{ This won't work if the "/" command is
262		 *    changed or invalidated by a .lesskey file. }}
263		 */
264		plusoption = TRUE;
265		ungetsc(s);
266		/*
267		 * In "more" mode, the -p argument is a command,
268		 * not a search string, so we don't need a slash.
269		 */
270		if (!less_is_more);
271			ungetsc("/");
272		break;
273	}
274}
275
276/*
277 * Handler for -P option.
278 */
279	public void
280opt__P(type, s)
281	int type;
282	register char *s;
283{
284	register char **proto;
285	PARG parg;
286
287	switch (type)
288	{
289	case INIT:
290	case TOGGLE:
291		/*
292		 * Figure out which prototype string should be changed.
293		 */
294		switch (*s)
295		{
296		case 's':  proto = &prproto[PR_SHORT];	s++;	break;
297		case 'm':  proto = &prproto[PR_MEDIUM];	s++;	break;
298		case 'M':  proto = &prproto[PR_LONG];	s++;	break;
299		case '=':  proto = &eqproto;		s++;	break;
300		case 'h':  proto = &hproto;		s++;	break;
301		case 'w':  proto = &wproto;		s++;	break;
302		default:   proto = &prproto[PR_SHORT];		break;
303		}
304		free(*proto);
305		*proto = save(s);
306		break;
307	case QUERY:
308		parg.p_string = prproto[pr_type];
309		error("%s", &parg);
310		break;
311	}
312}
313
314/*
315 * Handler for the -b option.
316 */
317	/*ARGSUSED*/
318	public void
319opt_b(type, s)
320	int type;
321	char *s;
322{
323	switch (type)
324	{
325	case INIT:
326	case TOGGLE:
327		/*
328		 * Set the new number of buffers.
329		 */
330		ch_setbufspace(bufspace);
331		break;
332	case QUERY:
333		break;
334	}
335}
336
337/*
338 * Handler for the -i option.
339 */
340	/*ARGSUSED*/
341	public void
342opt_i(type, s)
343	int type;
344	char *s;
345{
346	switch (type)
347	{
348	case TOGGLE:
349		chg_caseless();
350		break;
351	case QUERY:
352	case INIT:
353		break;
354	}
355}
356
357/*
358 * Handler for the -V option.
359 */
360	/*ARGSUSED*/
361	public void
362opt__V(type, s)
363	int type;
364	char *s;
365{
366	switch (type)
367	{
368	case TOGGLE:
369	case QUERY:
370		dispversion();
371		break;
372	case INIT:
373		/*
374		 * Force output to stdout per GNU standard for --version output.
375		 */
376		any_display = 1;
377		putstr("less ");
378		putstr(version);
379		putstr("\nCopyright (C) 1984-2005 Mark Nudelman\n\n");
380		putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
381		putstr("For information about the terms of redistribution,\n");
382		putstr("see the file named README in the less distribution.\n");
383		putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
384		quit(QUIT_OK);
385		break;
386	}
387}
388
389#if MSDOS_COMPILER
390/*
391 * Parse an MSDOS color descriptor.
392 */
393   	static void
394colordesc(s, fg_color, bg_color)
395	char *s;
396	int *fg_color;
397	int *bg_color;
398{
399	int fg, bg;
400	int err;
401
402	fg = getnum(&s, "D", &err);
403	if (err)
404	{
405		error("Missing fg color in -D", NULL_PARG);
406		return;
407	}
408	if (*s != '.')
409		bg = 0;
410	else
411	{
412		s++;
413		bg = getnum(&s, "D", &err);
414		if (err)
415		{
416			error("Missing fg color in -D", NULL_PARG);
417			return;
418		}
419	}
420	if (*s != '\0')
421		error("Extra characters at end of -D option", NULL_PARG);
422	*fg_color = fg;
423	*bg_color = bg;
424}
425
426/*
427 * Handler for the -D option.
428 */
429	/*ARGSUSED*/
430	public void
431opt_D(type, s)
432	int type;
433	char *s;
434{
435	switch (type)
436	{
437	case INIT:
438	case TOGGLE:
439		switch (*s++)
440		{
441		case 'n':
442			colordesc(s, &nm_fg_color, &nm_bg_color);
443			break;
444		case 'd':
445			colordesc(s, &bo_fg_color, &bo_bg_color);
446			break;
447		case 'u':
448			colordesc(s, &ul_fg_color, &ul_bg_color);
449			break;
450		case 'k':
451			colordesc(s, &bl_fg_color, &bl_bg_color);
452			break;
453		case 's':
454			colordesc(s, &so_fg_color, &so_bg_color);
455			break;
456		default:
457			error("-D must be followed by n, d, u, k or s", NULL_PARG);
458			break;
459		}
460		if (type == TOGGLE)
461		{
462			at_enter(AT_STANDOUT);
463			at_exit();
464		}
465		break;
466	case QUERY:
467		break;
468	}
469}
470#endif
471
472/*
473 * Handler for the -x option.
474 */
475	public void
476opt_x(type, s)
477	int type;
478	register char *s;
479{
480	extern int tabstops[];
481	extern int ntabstops;
482	extern int tabdefault;
483	char msg[60+(4*TABSTOP_MAX)];
484	int i;
485	PARG p;
486
487	switch (type)
488	{
489	case INIT:
490	case TOGGLE:
491		/* Start at 1 because tabstops[0] is always zero. */
492		for (i = 1;  i < TABSTOP_MAX;  )
493		{
494			int n = 0;
495			s = skipsp(s);
496			while (*s >= '0' && *s <= '9')
497				n = (10 * n) + (*s++ - '0');
498			if (n > tabstops[i-1])
499				tabstops[i++] = n;
500			s = skipsp(s);
501			if (*s++ != ',')
502				break;
503		}
504		if (i < 2)
505			return;
506		ntabstops = i;
507		tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
508		break;
509	case QUERY:
510		strcpy(msg, "Tab stops ");
511		if (ntabstops > 2)
512		{
513			for (i = 1;  i < ntabstops;  i++)
514			{
515				if (i > 1)
516					strcat(msg, ",");
517				sprintf(msg+strlen(msg), "%d", tabstops[i]);
518			}
519			sprintf(msg+strlen(msg), " and then ");
520		}
521		sprintf(msg+strlen(msg), "every %d spaces",
522			tabdefault);
523		p.p_string = msg;
524		error("%s", &p);
525		break;
526	}
527}
528
529
530/*
531 * Handler for the -" option.
532 */
533	public void
534opt_quote(type, s)
535	int type;
536	register char *s;
537{
538	char buf[3];
539	PARG parg;
540
541	switch (type)
542	{
543	case INIT:
544	case TOGGLE:
545		if (s[0] == '\0')
546		{
547			openquote = closequote = '\0';
548			break;
549		}
550		if (s[1] != '\0' && s[2] != '\0')
551		{
552			error("-\" must be followed by 1 or 2 chars", NULL_PARG);
553			return;
554		}
555		openquote = s[0];
556		if (s[1] == '\0')
557			closequote = openquote;
558		else
559			closequote = s[1];
560		break;
561	case QUERY:
562		buf[0] = openquote;
563		buf[1] = closequote;
564		buf[2] = '\0';
565		parg.p_string = buf;
566		error("quotes %s", &parg);
567		break;
568	}
569}
570
571/*
572 * "-?" means display a help message.
573 * If from the command line, exit immediately.
574 */
575	/*ARGSUSED*/
576	public void
577opt_query(type, s)
578	int type;
579	char *s;
580{
581	switch (type)
582	{
583	case QUERY:
584	case TOGGLE:
585		error("Use \"h\" for help", NULL_PARG);
586		break;
587	case INIT:
588		dohelp = 1;
589	}
590}
591
592/*
593 * Get the "screen window" size.
594 */
595	public int
596get_swindow()
597{
598	if (swindow > 0)
599		return (swindow);
600	return (sc_height + swindow);
601}
602
603