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