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