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