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