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