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