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