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