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