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