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