optfunc.c revision 89019
1/*
2 * Copyright (C) 1984-2000  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 cbufs;
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 char openquote;
41extern char closequote;
42extern char *prproto[];
43extern char *eqproto;
44extern char *hproto;
45extern char *wproto;
46extern IFILE curr_ifile;
47extern char version[];
48#if LOGFILE
49extern char *namelogfile;
50extern int force_logfile;
51extern int logfile;
52#endif
53#if TAGS
54public char *tagoption = NULL;
55extern char *tags;
56extern int jump_sline;
57#endif
58#if MSDOS_COMPILER
59extern int nm_fg_color, nm_bg_color;
60extern int bo_fg_color, bo_bg_color;
61extern int ul_fg_color, ul_bg_color;
62extern int so_fg_color, so_bg_color;
63extern int bl_fg_color, bl_bg_color;
64#endif
65
66
67#if LOGFILE
68/*
69 * Handler for -o option.
70 */
71	public void
72opt_o(type, s)
73	int type;
74	char *s;
75{
76	PARG parg;
77
78	if (secure)
79	{
80		error("log file support is not available", NULL_PARG);
81		return;
82	}
83	switch (type)
84	{
85	case INIT:
86		namelogfile = s;
87		break;
88	case TOGGLE:
89		if (ch_getflags() & CH_CANSEEK)
90		{
91			error("Input is not a pipe", NULL_PARG);
92			return;
93		}
94		if (logfile >= 0)
95		{
96			error("Log file is already in use", NULL_PARG);
97			return;
98		}
99		s = skipsp(s);
100		namelogfile = lglob(s);
101		use_logfile(namelogfile);
102		sync_logfile();
103		break;
104	case QUERY:
105		if (logfile < 0)
106			error("No log file", NULL_PARG);
107		else
108		{
109			parg.p_string = unquote_file(namelogfile);
110			error("Log file \"%s\"", &parg);
111			free(parg.p_string);
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 = unquote_file(s);
172			error("Cannot use lesskey file \"%s\"", &parg);
173			free(parg.p_string);
174		}
175		break;
176	}
177}
178#endif
179
180#if TAGS
181/*
182 * Handler for -t option.
183 */
184	public void
185opt_t(type, s)
186	int type;
187	char *s;
188{
189	IFILE save_ifile;
190	POSITION pos;
191
192	switch (type)
193	{
194	case INIT:
195		tagoption = s;
196		/* Do the rest in main() */
197		break;
198	case TOGGLE:
199		if (secure)
200		{
201			error("tags support is not available", NULL_PARG);
202			break;
203		}
204		findtag(skipsp(s));
205		save_ifile = save_curr_ifile();
206		if (edit_tagfile())
207			break;
208		if ((pos = tagsearch()) == NULL_POSITION)
209		{
210			reedit_ifile(save_ifile);
211			break;
212		}
213		unsave_ifile(save_ifile);
214		jump_loc(pos, jump_sline);
215		break;
216	}
217}
218
219/*
220 * Handler for -T option.
221 */
222	public void
223opt__T(type, s)
224	int type;
225	char *s;
226{
227	PARG parg;
228
229	switch (type)
230	{
231	case INIT:
232		tags = s;
233		break;
234	case TOGGLE:
235		s = skipsp(s);
236		tags = lglob(s);
237		break;
238	case QUERY:
239		parg.p_string = unquote_file(tags);
240		error("Tags file \"%s\"", &parg);
241		free(parg.p_string);
242		break;
243	}
244}
245#endif
246
247/*
248 * Handler for -p option.
249 */
250	public void
251opt_p(type, s)
252	int type;
253	register char *s;
254{
255	switch (type)
256	{
257	case INIT:
258		/*
259		 * Unget a search command for the specified string.
260		 * {{ This won't work if the "/" command is
261		 *    changed or invalidated by a .lesskey file. }}
262		 */
263		plusoption = TRUE;
264		ungetsc(s);
265		ungetsc("/");
266		break;
267	}
268}
269
270/*
271 * Handler for -P option.
272 */
273	public void
274opt__P(type, s)
275	int type;
276	register char *s;
277{
278	register char **proto;
279	PARG parg;
280
281	switch (type)
282	{
283	case INIT:
284	case TOGGLE:
285		/*
286		 * Figure out which prototype string should be changed.
287		 */
288		switch (*s)
289		{
290		case 's':  proto = &prproto[PR_SHORT];	s++;	break;
291		case 'm':  proto = &prproto[PR_MEDIUM];	s++;	break;
292		case 'M':  proto = &prproto[PR_LONG];	s++;	break;
293		case '=':  proto = &eqproto;		s++;	break;
294		case 'h':  proto = &hproto;		s++;	break;
295		case 'w':  proto = &wproto;		s++;	break;
296		default:   proto = &prproto[PR_SHORT];		break;
297		}
298		free(*proto);
299		*proto = save(s);
300		break;
301	case QUERY:
302		parg.p_string = prproto[pr_type];
303		error("%s", &parg);
304		break;
305	}
306}
307
308/*
309 * Handler for the -b option.
310 */
311	/*ARGSUSED*/
312	public void
313opt_b(type, s)
314	int type;
315	char *s;
316{
317	switch (type)
318	{
319	case TOGGLE:
320	case QUERY:
321		/*
322		 * Allocate the new number of buffers.
323		 */
324		cbufs = ch_nbuf(cbufs);
325		break;
326	case INIT:
327		break;
328	}
329}
330
331/*
332 * Handler for the -i option.
333 */
334	/*ARGSUSED*/
335	public void
336opt_i(type, s)
337	int type;
338	char *s;
339{
340	switch (type)
341	{
342	case TOGGLE:
343		chg_caseless();
344		break;
345	case QUERY:
346	case INIT:
347		break;
348	}
349}
350
351/*
352 * Handler for the -V option.
353 */
354	/*ARGSUSED*/
355	public void
356opt__V(type, s)
357	int type;
358	char *s;
359{
360	switch (type)
361	{
362	case TOGGLE:
363	case QUERY:
364		dispversion();
365		break;
366	case INIT:
367		/*
368		 * Force output to stdout per GNU standard for --version output.
369		 */
370		any_display = 1;
371		putstr("less ");
372		putstr(version);
373		putstr("\nCopyright (C) 2001 Mark Nudelman\n\n");
374		putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
375		putstr("For information about the terms of redistribution,\n");
376		putstr("see the file named README in the less distribution.\n");
377		putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
378		quit(QUIT_OK);
379		break;
380	}
381}
382
383#if MSDOS_COMPILER
384/*
385 * Parse an MSDOS color descriptor.
386 */
387   	static void
388colordesc(s, fg_color, bg_color)
389	char *s;
390	int *fg_color;
391	int *bg_color;
392{
393	int fg, bg;
394	int err;
395
396	fg = getnum(&s, 'D', &err);
397	if (err)
398	{
399		error("Missing fg color in -D", NULL_PARG);
400		return;
401	}
402	if (*s != '.')
403		bg = 0;
404	else
405	{
406		s++;
407		bg = getnum(&s, 'D', &err);
408		if (err)
409		{
410			error("Missing fg color in -D", NULL_PARG);
411			return;
412		}
413	}
414	if (*s != '\0')
415		error("Extra characters at end of -D option", NULL_PARG);
416	*fg_color = fg;
417	*bg_color = bg;
418}
419
420/*
421 * Handler for the -D option.
422 */
423	/*ARGSUSED*/
424	public void
425opt_D(type, s)
426	int type;
427	char *s;
428{
429	switch (type)
430	{
431	case INIT:
432	case TOGGLE:
433		switch (*s++)
434		{
435		case 'n':
436			colordesc(s, &nm_fg_color, &nm_bg_color);
437			break;
438		case 'd':
439			colordesc(s, &bo_fg_color, &bo_bg_color);
440			break;
441		case 'u':
442			colordesc(s, &ul_fg_color, &ul_bg_color);
443			break;
444		case 'k':
445			colordesc(s, &bl_fg_color, &bl_bg_color);
446			break;
447		case 's':
448			colordesc(s, &so_fg_color, &so_bg_color);
449			break;
450		default:
451			error("-D must be followed by n, d, u, k or s", NULL_PARG);
452			break;
453		}
454		if (type == TOGGLE)
455		{
456			so_enter();
457			so_exit();
458		}
459		break;
460	case QUERY:
461		break;
462	}
463}
464#endif
465
466/*
467 * Handler for the -x option.
468 */
469	public void
470opt_x(type, s)
471	int type;
472	register char *s;
473{
474	extern int tabstops[];
475	extern int ntabstops;
476	extern int tabdefault;
477	char msg[60+(4*TABSTOP_MAX)];
478	int i;
479	PARG p;
480
481	switch (type)
482	{
483	case INIT:
484	case TOGGLE:
485		/* Start at 1 because tabstops[0] is always zero. */
486		for (i = 1;  i < TABSTOP_MAX;  )
487		{
488			int n = 0;
489			while (*s >= '0' && *s <= '9')
490				n = (10 * n) + (*s++ - '0');
491			if (n > tabstops[i-1])
492				tabstops[i++] = n;
493			if (*s++ != ',')
494				break;
495		}
496		if (i < 2)
497			return;
498		ntabstops = i;
499		tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
500		break;
501	case QUERY:
502		strcpy(msg, "Tab stops ");
503		if (ntabstops > 2)
504		{
505			for (i = 1;  i < ntabstops;  i++)
506			{
507				if (i > 1)
508					strcat(msg, ",");
509				sprintf(msg+strlen(msg), "%d", tabstops[i]);
510			}
511			sprintf(msg+strlen(msg), " and then ");
512		}
513		sprintf(msg+strlen(msg), "every %d spaces",
514			tabdefault);
515		p.p_string = msg;
516		error("%s", &p);
517		break;
518	}
519}
520
521
522/*
523 * Handler for the -" option.
524 */
525	public void
526opt_quote(type, s)
527	int type;
528	register char *s;
529{
530	char buf[3];
531	PARG parg;
532
533	switch (type)
534	{
535	case INIT:
536	case TOGGLE:
537		if (s[1] != '\0' && s[2] != '\0')
538		{
539			error("-\" must be followed by 1 or 2 chars", NULL_PARG);
540			return;
541		}
542		openquote = s[0];
543		if (s[1] == '\0')
544			closequote = openquote;
545		else
546			closequote = s[1];
547		break;
548	case QUERY:
549		buf[0] = openquote;
550		buf[1] = closequote;
551		buf[2] = '\0';
552		parg.p_string = buf;
553		error("quotes %s", &parg);
554		break;
555	}
556}
557
558/*
559 * "-?" means display a help message.
560 * If from the command line, exit immediately.
561 */
562	/*ARGSUSED*/
563	public void
564opt_query(type, s)
565	int type;
566	char *s;
567{
568	switch (type)
569	{
570	case QUERY:
571	case TOGGLE:
572		error("Use \"h\" for help", NULL_PARG);
573		break;
574	case INIT:
575		dohelp = 1;
576	}
577}
578
579/*
580 * Get the "screen window" size.
581 */
582	public int
583get_swindow()
584{
585	if (swindow > 0)
586		return (swindow);
587	return (sc_height + swindow);
588}
589
590