optfunc.c revision 294286
1193323Sed/*
2193323Sed * Copyright (C) 1984-2015  Mark Nudelman
3193323Sed *
4193323Sed * You may distribute under the terms of either the GNU General Public
5193323Sed * License or the Less License, as specified in the README file.
6193323Sed *
7193323Sed * For more information, see the README file.
8193323Sed */
9193323Sed
10193323Sed
11193323Sed/*
12193323Sed * Handling functions for command line options.
13249423Sdim *
14243830Sdim * Most options are handled by the generic code in option.c.
15218893Sdim * But all string options, and a few non-string options, require
16206083Srdivacky * special handling specific to the particular option.
17193323Sed * This special processing is done by the "handling functions" in this file.
18249423Sdim *
19193323Sed * Each handling function is passed a "type" and, if it is a string
20193323Sed * option, the string which should be "assigned" to the option.
21193323Sed * The type may be one of:
22193323Sed *	INIT	The option is being initialized from the command line.
23206083Srdivacky *	TOGGLE	The option is being changed from within the program.
24193323Sed *	QUERY	The setting of the option is merely being queried.
25198090Srdivacky */
26193323Sed
27206083Srdivacky#include "less.h"
28206083Srdivacky#include "option.h"
29206083Srdivacky
30206083Srdivackyextern int nbufs;
31206083Srdivackyextern int bufspace;
32206083Srdivackyextern int pr_type;
33206083Srdivackyextern int plusoption;
34206083Srdivackyextern int swindow;
35206083Srdivackyextern int sc_width;
36206083Srdivackyextern int sc_height;
37206083Srdivackyextern int secure;
38206083Srdivackyextern int dohelp;
39206083Srdivackyextern int any_display;
40206083Srdivackyextern char openquote;
41206083Srdivackyextern char closequote;
42206083Srdivackyextern char *prproto[];
43206083Srdivackyextern char *eqproto;
44206083Srdivackyextern char *hproto;
45206083Srdivackyextern char *wproto;
46206083Srdivackyextern char *every_first_cmd;
47206083Srdivackyextern IFILE curr_ifile;
48206083Srdivackyextern char version[];
49206083Srdivackyextern int jump_sline;
50206083Srdivackyextern int jump_sline_fraction;
51206083Srdivackyextern int shift_count;
52206083Srdivackyextern int shift_count_fraction;
53206083Srdivackyextern int less_is_more;
54206083Srdivacky#if LOGFILE
55206083Srdivackyextern char *namelogfile;
56206083Srdivackyextern int force_logfile;
57206083Srdivackyextern int logfile;
58206083Srdivacky#endif
59206083Srdivacky#if TAGS
60206083Srdivackypublic char *tagoption = NULL;
61206083Srdivackyextern char *tags;
62206083Srdivackyextern char ztags[];
63206083Srdivacky#endif
64206083Srdivacky#if MSDOS_COMPILER
65206083Srdivackyextern int nm_fg_color, nm_bg_color;
66206083Srdivackyextern int bo_fg_color, bo_bg_color;
67206083Srdivackyextern int ul_fg_color, ul_bg_color;
68206083Srdivackyextern int so_fg_color, so_bg_color;
69206083Srdivackyextern int bl_fg_color, bl_bg_color;
70206083Srdivacky#endif
71206083Srdivacky
72193323Sed
73198090Srdivacky#if LOGFILE
74193323Sed/*
75193323Sed * Handler for -o option.
76249423Sdim */
77193323Sed	public void
78193323Sedopt_o(type, s)
79193323Sed	int type;
80193323Sed	char *s;
81206083Srdivacky{
82206083Srdivacky	PARG parg;
83193323Sed
84193323Sed	if (secure)
85206083Srdivacky	{
86206083Srdivacky		error("log file support is not available", NULL_PARG);
87193323Sed		return;
88206083Srdivacky	}
89206083Srdivacky	switch (type)
90206083Srdivacky	{
91206083Srdivacky	case INIT:
92206083Srdivacky		namelogfile = save(s);
93193323Sed		break;
94206083Srdivacky	case TOGGLE:
95193323Sed		if (ch_getflags() & CH_CANSEEK)
96193323Sed		{
97206083Srdivacky			error("Input is not a pipe", NULL_PARG);
98193323Sed			return;
99206083Srdivacky		}
100206083Srdivacky		if (logfile >= 0)
101206083Srdivacky		{
102206083Srdivacky			error("Log file is already in use", NULL_PARG);
103206083Srdivacky			return;
104206083Srdivacky		}
105206083Srdivacky		s = skipsp(s);
106206083Srdivacky		if (namelogfile != NULL)
107193323Sed			free(namelogfile);
108193323Sed		namelogfile = lglob(s);
109193323Sed		use_logfile(namelogfile);
110193323Sed		sync_logfile();
111193323Sed		break;
112193323Sed	case QUERY:
113193323Sed		if (logfile < 0)
114193323Sed			error("No log file", NULL_PARG);
115193323Sed		else
116193323Sed		{
117193323Sed			parg.p_string = namelogfile;
118193323Sed			error("Log file \"%s\"", &parg);
119193323Sed		}
120193323Sed		break;
121193323Sed	}
122193323Sed}
123193323Sed
124249423Sdim/*
125193323Sed * Handler for -O option.
126193323Sed */
127193323Sed	public void
128193323Sedopt__O(type, s)
129243830Sdim	int type;
130193323Sed	char *s;
131193323Sed{
132193323Sed	force_logfile = TRUE;
133193323Sed	opt_o(type, s);
134193323Sed}
135206083Srdivacky#endif
136193323Sed
137193323Sed/*
138206083Srdivacky * Handlers for -j option.
139193323Sed */
140193323Sed	public void
141193323Sedopt_j(type, s)
142193323Sed	int type;
143193323Sed	char *s;
144193323Sed{
145193323Sed	PARG parg;
146193323Sed	char buf[16];
147193323Sed	int len;
148193323Sed	int err;
149210299Sed
150210299Sed	switch (type)
151210299Sed	{
152210299Sed	case INIT:
153193323Sed	case TOGGLE:
154193323Sed		if (*s == '.')
155193323Sed		{
156193323Sed			s++;
157193323Sed			jump_sline_fraction = getfraction(&s, "j", &err);
158193323Sed			if (err)
159193323Sed				error("Invalid line fraction", NULL_PARG);
160193323Sed			else
161193323Sed				calc_jump_sline();
162193323Sed		} else
163206083Srdivacky		{
164206083Srdivacky			int sline = getnum(&s, "j", &err);
165206083Srdivacky			if (err)
166206083Srdivacky				error("Invalid line number", NULL_PARG);
167243830Sdim			else
168243830Sdim			{
169193323Sed				jump_sline = sline;
170206083Srdivacky				jump_sline_fraction = -1;
171206083Srdivacky			}
172193323Sed		}
173206083Srdivacky		break;
174206083Srdivacky	case QUERY:
175206083Srdivacky		if (jump_sline_fraction < 0)
176206083Srdivacky		{
177206083Srdivacky			parg.p_int =  jump_sline;
178206083Srdivacky			error("Position target at screen line %d", &parg);
179206083Srdivacky		} else
180206083Srdivacky		{
181193323Sed
182193323Sed			sprintf(buf, ".%06d", jump_sline_fraction);
183206083Srdivacky			len = (int) strlen(buf);
184206083Srdivacky			while (len > 2 && buf[len-1] == '0')
185206083Srdivacky				len--;
186193323Sed			buf[len] = '\0';
187193323Sed			parg.p_string = buf;
188193323Sed			error("Position target at screen position %s", &parg);
189193323Sed		}
190193323Sed		break;
191	}
192}
193
194	public void
195calc_jump_sline()
196{
197	if (jump_sline_fraction < 0)
198		return;
199	jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
200}
201
202/*
203 * Handlers for -# option.
204 */
205	public void
206opt_shift(type, s)
207	int type;
208	char *s;
209{
210	PARG parg;
211	char buf[16];
212	int len;
213	int err;
214
215	switch (type)
216	{
217	case INIT:
218	case TOGGLE:
219		if (*s == '.')
220		{
221			s++;
222			shift_count_fraction = getfraction(&s, "#", &err);
223			if (err)
224				error("Invalid column fraction", NULL_PARG);
225			else
226				calc_shift_count();
227		} else
228		{
229			int hs = getnum(&s, "#", &err);
230			if (err)
231				error("Invalid column number", NULL_PARG);
232			else
233			{
234				shift_count = hs;
235				shift_count_fraction = -1;
236			}
237		}
238		break;
239	case QUERY:
240		if (shift_count_fraction < 0)
241		{
242			parg.p_int = shift_count;
243			error("Horizontal shift %d columns", &parg);
244		} else
245		{
246
247			sprintf(buf, ".%06d", shift_count_fraction);
248			len = (int) strlen(buf);
249			while (len > 2 && buf[len-1] == '0')
250				len--;
251			buf[len] = '\0';
252			parg.p_string = buf;
253			error("Horizontal shift %s of screen width", &parg);
254		}
255		break;
256	}
257}
258	public void
259calc_shift_count()
260{
261	if (shift_count_fraction < 0)
262		return;
263	shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
264}
265
266#if USERFILE
267	public void
268opt_k(type, s)
269	int type;
270	char *s;
271{
272	PARG parg;
273
274	switch (type)
275	{
276	case INIT:
277		if (lesskey(s, 0))
278		{
279			parg.p_string = s;
280			error("Cannot use lesskey file \"%s\"", &parg);
281		}
282		break;
283	}
284}
285#endif
286
287#if TAGS
288/*
289 * Handler for -t option.
290 */
291	public void
292opt_t(type, s)
293	int type;
294	char *s;
295{
296	IFILE save_ifile;
297	POSITION pos;
298
299	switch (type)
300	{
301	case INIT:
302		tagoption = save(s);
303		/* Do the rest in main() */
304		break;
305	case TOGGLE:
306		if (secure)
307		{
308			error("tags support is not available", NULL_PARG);
309			break;
310		}
311		findtag(skipsp(s));
312		save_ifile = save_curr_ifile();
313		/*
314		 * Try to open the file containing the tag
315		 * and search for the tag in that file.
316		 */
317		if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
318		{
319			/* Failed: reopen the old file. */
320			reedit_ifile(save_ifile);
321			break;
322		}
323		unsave_ifile(save_ifile);
324		jump_loc(pos, jump_sline);
325		break;
326	}
327}
328
329/*
330 * Handler for -T option.
331 */
332	public void
333opt__T(type, s)
334	int type;
335	char *s;
336{
337	PARG parg;
338
339	switch (type)
340	{
341	case INIT:
342		tags = save(s);
343		break;
344	case TOGGLE:
345		s = skipsp(s);
346		if (tags != NULL && tags != ztags)
347			free(tags);
348		tags = lglob(s);
349		break;
350	case QUERY:
351		parg.p_string = tags;
352		error("Tags file \"%s\"", &parg);
353		break;
354	}
355}
356#endif
357
358/*
359 * Handler for -p option.
360 */
361	public void
362opt_p(type, s)
363	int type;
364	register char *s;
365{
366	switch (type)
367	{
368	case INIT:
369		/*
370		 * Unget a command for the specified string.
371		 */
372		if (less_is_more)
373		{
374			/*
375			 * In "more" mode, the -p argument is a command,
376			 * not a search string, so we don't need a slash.
377			 */
378			every_first_cmd = save(s);
379		} else
380		{
381			plusoption = TRUE;
382			ungetcc(CHAR_END_COMMAND);
383			ungetsc(s);
384			 /*
385			  * {{ This won't work if the "/" command is
386			  *    changed or invalidated by a .lesskey file. }}
387			  */
388			ungetsc("/");
389		}
390		break;
391	}
392}
393
394/*
395 * Handler for -P option.
396 */
397	public void
398opt__P(type, s)
399	int type;
400	register char *s;
401{
402	register char **proto;
403	PARG parg;
404
405	switch (type)
406	{
407	case INIT:
408	case TOGGLE:
409		/*
410		 * Figure out which prototype string should be changed.
411		 */
412		switch (*s)
413		{
414		case 's':  proto = &prproto[PR_SHORT];	s++;	break;
415		case 'm':  proto = &prproto[PR_MEDIUM];	s++;	break;
416		case 'M':  proto = &prproto[PR_LONG];	s++;	break;
417		case '=':  proto = &eqproto;		s++;	break;
418		case 'h':  proto = &hproto;		s++;	break;
419		case 'w':  proto = &wproto;		s++;	break;
420		default:   proto = &prproto[PR_SHORT];		break;
421		}
422		free(*proto);
423		*proto = save(s);
424		break;
425	case QUERY:
426		parg.p_string = prproto[pr_type];
427		error("%s", &parg);
428		break;
429	}
430}
431
432/*
433 * Handler for the -b option.
434 */
435	/*ARGSUSED*/
436	public void
437opt_b(type, s)
438	int type;
439	char *s;
440{
441	switch (type)
442	{
443	case INIT:
444	case TOGGLE:
445		/*
446		 * Set the new number of buffers.
447		 */
448		ch_setbufspace(bufspace);
449		break;
450	case QUERY:
451		break;
452	}
453}
454
455/*
456 * Handler for the -i option.
457 */
458	/*ARGSUSED*/
459	public void
460opt_i(type, s)
461	int type;
462	char *s;
463{
464	switch (type)
465	{
466	case TOGGLE:
467		chg_caseless();
468		break;
469	case QUERY:
470	case INIT:
471		break;
472	}
473}
474
475/*
476 * Handler for the -V option.
477 */
478	/*ARGSUSED*/
479	public void
480opt__V(type, s)
481	int type;
482	char *s;
483{
484	switch (type)
485	{
486	case TOGGLE:
487	case QUERY:
488		dispversion();
489		break;
490	case INIT:
491		/*
492		 * Force output to stdout per GNU standard for --version output.
493		 */
494		any_display = 1;
495		putstr("less ");
496		putstr(version);
497		putstr(" (");
498#if HAVE_GNU_REGEX
499		putstr("GNU ");
500#endif
501#if HAVE_POSIX_REGCOMP
502		putstr("POSIX ");
503#endif
504#if HAVE_PCRE
505		putstr("PCRE ");
506#endif
507#if HAVE_RE_COMP
508		putstr("BSD ");
509#endif
510#if HAVE_REGCMP
511		putstr("V8 ");
512#endif
513#if HAVE_V8_REGCOMP
514		putstr("Spencer V8 ");
515#endif
516#if !HAVE_GNU_REGEX && !HAVE_POSIX_REGCOMP && !HAVE_PCRE && !HAVE_RE_COMP && !HAVE_REGCMP && !HAVE_V8_REGCOMP
517		putstr("no ");
518#endif
519		putstr("regular expressions)\n");
520		putstr("Copyright (C) 1984-2015  Mark Nudelman\n\n");
521		putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
522		putstr("For information about the terms of redistribution,\n");
523		putstr("see the file named README in the less distribution.\n");
524		putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
525		quit(QUIT_OK);
526		break;
527	}
528}
529
530#if MSDOS_COMPILER
531/*
532 * Parse an MSDOS color descriptor.
533 */
534   	static void
535colordesc(s, fg_color, bg_color)
536	char *s;
537	int *fg_color;
538	int *bg_color;
539{
540	int fg, bg;
541	int err;
542
543	fg = getnum(&s, "D", &err);
544	if (err)
545	{
546		error("Missing fg color in -D", NULL_PARG);
547		return;
548	}
549	if (*s != '.')
550		bg = nm_bg_color;
551	else
552	{
553		s++;
554		bg = getnum(&s, "D", &err);
555		if (err)
556		{
557			error("Missing bg color in -D", NULL_PARG);
558			return;
559		}
560	}
561	if (*s != '\0')
562		error("Extra characters at end of -D option", NULL_PARG);
563	*fg_color = fg;
564	*bg_color = bg;
565}
566
567/*
568 * Handler for the -D option.
569 */
570	/*ARGSUSED*/
571	public void
572opt_D(type, s)
573	int type;
574	char *s;
575{
576	switch (type)
577	{
578	case INIT:
579	case TOGGLE:
580		switch (*s++)
581		{
582		case 'n':
583			colordesc(s, &nm_fg_color, &nm_bg_color);
584			break;
585		case 'd':
586			colordesc(s, &bo_fg_color, &bo_bg_color);
587			break;
588		case 'u':
589			colordesc(s, &ul_fg_color, &ul_bg_color);
590			break;
591		case 'k':
592			colordesc(s, &bl_fg_color, &bl_bg_color);
593			break;
594		case 's':
595			colordesc(s, &so_fg_color, &so_bg_color);
596			break;
597		default:
598			error("-D must be followed by n, d, u, k or s", NULL_PARG);
599			break;
600		}
601		if (type == TOGGLE)
602		{
603			at_enter(AT_STANDOUT);
604			at_exit();
605		}
606		break;
607	case QUERY:
608		break;
609	}
610}
611#endif
612
613/*
614 * Handler for the -x option.
615 */
616	public void
617opt_x(type, s)
618	int type;
619	register char *s;
620{
621	extern int tabstops[];
622	extern int ntabstops;
623	extern int tabdefault;
624	char msg[60+(4*TABSTOP_MAX)];
625	int i;
626	PARG p;
627
628	switch (type)
629	{
630	case INIT:
631	case TOGGLE:
632		/* Start at 1 because tabstops[0] is always zero. */
633		for (i = 1;  i < TABSTOP_MAX;  )
634		{
635			int n = 0;
636			s = skipsp(s);
637			while (*s >= '0' && *s <= '9')
638				n = (10 * n) + (*s++ - '0');
639			if (n > tabstops[i-1])
640				tabstops[i++] = n;
641			s = skipsp(s);
642			if (*s++ != ',')
643				break;
644		}
645		if (i < 2)
646			return;
647		ntabstops = i;
648		tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
649		break;
650	case QUERY:
651		strcpy(msg, "Tab stops ");
652		if (ntabstops > 2)
653		{
654			for (i = 1;  i < ntabstops;  i++)
655			{
656				if (i > 1)
657					strcat(msg, ",");
658				sprintf(msg+strlen(msg), "%d", tabstops[i]);
659			}
660			sprintf(msg+strlen(msg), " and then ");
661		}
662		sprintf(msg+strlen(msg), "every %d spaces",
663			tabdefault);
664		p.p_string = msg;
665		error("%s", &p);
666		break;
667	}
668}
669
670
671/*
672 * Handler for the -" option.
673 */
674	public void
675opt_quote(type, s)
676	int type;
677	register char *s;
678{
679	char buf[3];
680	PARG parg;
681
682	switch (type)
683	{
684	case INIT:
685	case TOGGLE:
686		if (s[0] == '\0')
687		{
688			openquote = closequote = '\0';
689			break;
690		}
691		if (s[1] != '\0' && s[2] != '\0')
692		{
693			error("-\" must be followed by 1 or 2 chars", NULL_PARG);
694			return;
695		}
696		openquote = s[0];
697		if (s[1] == '\0')
698			closequote = openquote;
699		else
700			closequote = s[1];
701		break;
702	case QUERY:
703		buf[0] = openquote;
704		buf[1] = closequote;
705		buf[2] = '\0';
706		parg.p_string = buf;
707		error("quotes %s", &parg);
708		break;
709	}
710}
711
712/*
713 * "-?" means display a help message.
714 * If from the command line, exit immediately.
715 */
716	/*ARGSUSED*/
717	public void
718opt_query(type, s)
719	int type;
720	char *s;
721{
722	switch (type)
723	{
724	case QUERY:
725	case TOGGLE:
726		error("Use \"h\" for help", NULL_PARG);
727		break;
728	case INIT:
729		dohelp = 1;
730	}
731}
732
733/*
734 * Get the "screen window" size.
735 */
736	public int
737get_swindow()
738{
739	if (swindow > 0)
740		return (swindow);
741	return (sc_height + swindow);
742}
743
744