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