xref: /netbsd-src/external/bsd/less/dist/optfunc.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
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 
33 extern int nbufs;
34 extern int bufspace;
35 extern int pr_type;
36 extern int plusoption;
37 extern int swindow;
38 extern int sc_width;
39 extern int sc_height;
40 extern int secure;
41 extern int dohelp;
42 extern int any_display;
43 extern char openquote;
44 extern char closequote;
45 extern char *prproto[];
46 extern char *eqproto;
47 extern char *hproto;
48 extern char *wproto;
49 extern IFILE curr_ifile;
50 extern char version[];
51 extern int jump_sline;
52 extern int jump_sline_fraction;
53 extern int shift_count;
54 extern int shift_count_fraction;
55 extern int less_is_more;
56 #if LOGFILE
57 extern char *namelogfile;
58 extern int force_logfile;
59 extern int logfile;
60 #endif
61 #if TAGS
62 public char *tagoption = NULL;
63 extern char *tags;
64 #endif
65 #if MSDOS_COMPILER
66 extern int nm_fg_color, nm_bg_color;
67 extern int bo_fg_color, bo_bg_color;
68 extern int ul_fg_color, ul_bg_color;
69 extern int so_fg_color, so_bg_color;
70 extern int bl_fg_color, bl_bg_color;
71 #endif
72 
73 
74 #if LOGFILE
75 /*
76  * Handler for -o option.
77  */
78 	public void
79 opt_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
127 opt__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
140 opt_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
194 calc_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
205 opt_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
258 calc_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
267 opt_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
291 opt_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
332 opt__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
359 opt_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
387 opt__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
426 opt_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
449 opt_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
469 opt__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
501 colordesc(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
538 opt_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
583 opt_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
641 opt_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
684 opt_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
703 get_swindow()
704 {
705 	if (swindow > 0)
706 		return (swindow);
707 	return (sc_height + swindow);
708 }
709 
710