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