GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../optfunc.c Lines: 19 220 8.6 %
Date: 2017-11-07 Branches: 9 129 7.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (C) 1984-2012  Mark Nudelman
3
 * Modified for use with illumos by Garrett D'Amore.
4
 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
5
 *
6
 * You may distribute under the terms of either the GNU General Public
7
 * License or the Less License, as specified in the README file.
8
 *
9
 * For more information, see the README file.
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 bufspace;
32
extern int pr_type;
33
extern int plusoption;
34
extern int swindow;
35
extern int sc_width;
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
extern char *namelogfile;
52
extern int force_logfile;
53
extern int logfile;
54
char *tagoption = NULL;
55
extern char *tags;
56
57
int shift_count;	/* Number of positions to shift horizontally */
58
static int shift_count_fraction = -1;
59
60
/*
61
 * Handler for -o option.
62
 */
63
void
64
opt_o(int type, char *s)
65
{
66
2
	PARG parg;
67
68
1
	if (secure) {
69
		error("log file support is not available", NULL);
70
		return;
71
	}
72

2
	switch (type) {
73
	case INIT:
74
		namelogfile = s;
75
		break;
76
	case TOGGLE:
77
		if (ch_getflags() & CH_CANSEEK) {
78
			error("Input is not a pipe", NULL);
79
			return;
80
		}
81
		if (logfile >= 0) {
82
			error("Log file is already in use", NULL);
83
			return;
84
		}
85
		s = skipsp(s);
86
		namelogfile = lglob(s);
87
		use_logfile(namelogfile);
88
		sync_logfile();
89
		break;
90
	case QUERY:
91
1
		if (logfile < 0) {
92
1
			error("No log file", NULL);
93
1
		} else {
94
			parg.p_string = namelogfile;
95
			error("Log file \"%s\"", &parg);
96
		}
97
		break;
98
	}
99
2
}
100
101
/*
102
 * Handler for -O option.
103
 */
104
void
105
opt__O(int type, char *s)
106
{
107
	force_logfile = TRUE;
108
	opt_o(type, s);
109
}
110
111
/*
112
 * Handlers for -j option.
113
 */
114
void
115
opt_j(int type, char *s)
116
{
117
	PARG parg;
118
	char buf[16];
119
	int len;
120
	int err;
121
122
	switch (type) {
123
	case INIT:
124
	case TOGGLE:
125
		if (*s == '.') {
126
			s++;
127
			jump_sline_fraction = getfraction(&s, "j", &err);
128
			if (err)
129
				error("Invalid line fraction", NULL);
130
			else
131
				calc_jump_sline();
132
		} else {
133
			int sline = getnum(&s, "j", &err);
134
			if (err) {
135
				error("Invalid line number", NULL);
136
			} else {
137
				jump_sline = sline;
138
				jump_sline_fraction = -1;
139
			}
140
		}
141
		break;
142
	case QUERY:
143
		if (jump_sline_fraction < 0) {
144
			parg.p_int =  jump_sline;
145
			error("Position target at screen line %d", &parg);
146
		} else {
147
			(void) snprintf(buf, sizeof (buf), ".%06d",
148
			    jump_sline_fraction);
149
			len = strlen(buf);
150
			while (len > 2 && buf[len-1] == '0')
151
				len--;
152
			buf[len] = '\0';
153
			parg.p_string = buf;
154
			error("Position target at screen position %s", &parg);
155
		}
156
		break;
157
	}
158
}
159
160
void
161
calc_jump_sline(void)
162
{
163
	if (jump_sline_fraction < 0)
164
		return;
165
	jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
166
}
167
168
/*
169
 * Handlers for -# option.
170
 */
171
void
172
opt_shift(int type, char *s)
173
{
174
	PARG parg;
175
	char buf[16];
176
	int len;
177
	int err;
178
179
	switch (type) {
180
	case INIT:
181
	case TOGGLE:
182
		if (*s == '.') {
183
			s++;
184
			shift_count_fraction = getfraction(&s, "#", &err);
185
			if (err)
186
				error("Invalid column fraction", NULL);
187
			else
188
				calc_shift_count();
189
		} else {
190
			int hs = getnum(&s, "#", &err);
191
			if (err) {
192
				error("Invalid column number", NULL);
193
			} else {
194
				shift_count = hs;
195
				shift_count_fraction = -1;
196
			}
197
		}
198
		break;
199
	case QUERY:
200
		if (shift_count_fraction < 0) {
201
			parg.p_int = shift_count;
202
			error("Horizontal shift %d columns", &parg);
203
		} else {
204
205
			(void) snprintf(buf, sizeof (buf), ".%06d",
206
			    shift_count_fraction);
207
			len = strlen(buf);
208
			while (len > 2 && buf[len-1] == '0')
209
				len--;
210
			buf[len] = '\0';
211
			parg.p_string = buf;
212
			error("Horizontal shift %s of screen width", &parg);
213
		}
214
		break;
215
	}
216
}
217
218
void
219
calc_shift_count(void)
220
{
221
	if (shift_count_fraction < 0)
222
		return;
223
	shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
224
}
225
226
void
227
opt_k(int type, char *s)
228
{
229
	PARG parg;
230
231
	switch (type) {
232
	case INIT:
233
		if (lesskey(s, 0)) {
234
			parg.p_string = s;
235
			error("Cannot use lesskey file \"%s\"", &parg);
236
		}
237
		break;
238
	}
239
}
240
241
/*
242
 * Handler for -t option.
243
 */
244
void
245
opt_t(int type, char *s)
246
{
247
	IFILE save_ifile;
248
	off_t pos;
249
250
	switch (type) {
251
	case INIT:
252
		tagoption = s;
253
		/* Do the rest in main() */
254
		break;
255
	case TOGGLE:
256
		if (secure) {
257
			error("tags support is not available", NULL);
258
			break;
259
		}
260
		findtag(skipsp(s));
261
		save_ifile = save_curr_ifile();
262
		/*
263
		 * Try to open the file containing the tag
264
		 * and search for the tag in that file.
265
		 */
266
		if (edit_tagfile() || (pos = tagsearch()) == -1) {
267
			/* Failed: reopen the old file. */
268
			reedit_ifile(save_ifile);
269
			break;
270
		}
271
		unsave_ifile(save_ifile);
272
		jump_loc(pos, jump_sline);
273
		break;
274
	}
275
}
276
277
/*
278
 * Handler for -T option.
279
 */
280
void
281
opt__T(int type, char *s)
282
{
283
15
	PARG parg;
284
285

10
	switch (type) {
286
	case INIT:
287
5
		tags = s;
288
5
		break;
289
	case TOGGLE:
290
		s = skipsp(s);
291
		tags = lglob(s);
292
		break;
293
	case QUERY:
294
		parg.p_string = tags;
295
		error("Tags file \"%s\"", &parg);
296
		break;
297
	}
298
5
}
299
300
/*
301
 * Handler for -p option.
302
 */
303
void
304
opt_p(int type, char *s)
305
{
306
	switch (type) {
307
	case INIT:
308
		/*
309
		 * Unget a search command for the specified string.
310
		 * {{ This won't work if the "/" command is
311
		 *    changed or invalidated by a .lesskey file. }}
312
		 */
313
		plusoption = TRUE;
314
		ungetsc(s);
315
		/*
316
		 * In "more" mode, the -p argument is a command,
317
		 * not a search string, so we don't need a slash.
318
		 */
319
		if (!less_is_more)
320
			ungetsc("/");
321
		break;
322
	}
323
}
324
325
/*
326
 * Handler for -P option.
327
 */
328
void
329
opt__P(int type, char *s)
330
{
331
	char **proto;
332
	PARG parg;
333
334
	switch (type) {
335
	case INIT:
336
	case TOGGLE:
337
		/*
338
		 * Figure out which prototype string should be changed.
339
		 */
340
		switch (*s) {
341
		case 's':  proto = &prproto[PR_SHORT];	s++;	break;
342
		case 'm':  proto = &prproto[PR_MEDIUM];	s++;	break;
343
		case 'M':  proto = &prproto[PR_LONG];	s++;	break;
344
		case '=':  proto = &eqproto;		s++;	break;
345
		case 'h':  proto = &hproto;		s++;	break;
346
		case 'w':  proto = &wproto;		s++;	break;
347
		default:   proto = &prproto[PR_SHORT];		break;
348
		}
349
		free(*proto);
350
		*proto = estrdup(s);
351
		break;
352
	case QUERY:
353
		parg.p_string = prproto[pr_type];
354
		error("%s", &parg);
355
		break;
356
	}
357
}
358
359
/*
360
 * Handler for the -b option.
361
 */
362
void
363
opt_b(int type, char *s)
364
{
365
117
	switch (type) {
366
	case INIT:
367
	case TOGGLE:
368
		/*
369
		 * Set the new number of buffers.
370
		 */
371
39
		ch_setbufspace(bufspace);
372
39
		break;
373
	case QUERY:
374
		break;
375
	}
376
39
}
377
378
/*
379
 * Handler for the -i option.
380
 */
381
void
382
opt_i(int type, char *s)
383
{
384
	switch (type) {
385
	case TOGGLE:
386
		chg_caseless();
387
		break;
388
	case QUERY:
389
	case INIT:
390
		break;
391
	}
392
}
393
394
/*
395
 * Handler for the -V option.
396
 */
397
void
398
opt__V(int type, char *s)
399
{
400
	switch (type) {
401
	case TOGGLE:
402
	case QUERY:
403
		dispversion();
404
		break;
405
	case INIT:
406
		/*
407
		 * Force output to stdout per GNU standard for --version output.
408
		 */
409
		any_display = 1;
410
		putstr("less ");
411
		putstr(version);
412
		putstr(" (");
413
		putstr("POSIX ");
414
		putstr("regular expressions)\n");
415
		putstr("Copyright (C) 1984-2012 Mark Nudelman\n");
416
		putstr("Modified for use with illumos by Garrett D'Amore.\n");
417
		putstr("Copyright 2014 Garrett D'Amore\n\n");
418
		putstr("less comes with NO WARRANTY, ");
419
		putstr("to the extent permitted by law.\n");
420
		putstr("For information about the terms of redistribution,\n");
421
		putstr("see the file named README in the less distribution.\n");
422
		putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
423
		putstr("\n");
424
		quit(QUIT_OK);
425
		break;
426
	}
427
}
428
429
/*
430
 * Handler for the -x option.
431
 */
432
void
433
opt_x(int type, char *s)
434
{
435
	extern int tabstops[];
436
	extern int ntabstops;
437
	extern int tabdefault;
438
	char tabs[60+(4*TABSTOP_MAX)];
439
	int i;
440
	PARG p;
441
442
	switch (type) {
443
	case INIT:
444
	case TOGGLE:
445
		/* Start at 1 because tabstops[0] is always zero. */
446
		for (i = 1; i < TABSTOP_MAX; ) {
447
			int n = 0;
448
			s = skipsp(s);
449
			while (*s >= '0' && *s <= '9')
450
				n = (10 * n) + (*s++ - '0');
451
			if (n > tabstops[i-1])
452
				tabstops[i++] = n;
453
			s = skipsp(s);
454
			if (*s++ != ',')
455
				break;
456
		}
457
		if (i < 2)
458
			return;
459
		ntabstops = i;
460
		tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
461
		break;
462
	case QUERY:
463
		(void) strlcpy(tabs, "Tab stops ", sizeof(tabs));
464
		if (ntabstops > 2) {
465
			for (i = 1; i < ntabstops; i++) {
466
				if (i > 1)
467
					strlcat(tabs, ",", sizeof(tabs));
468
				(void) snprintf(tabs+strlen(tabs),
469
				    sizeof(tabs)-strlen(tabs),
470
				    "%d", tabstops[i]);
471
			}
472
			(void) snprintf(tabs+strlen(tabs),
473
			    sizeof(tabs)-strlen(tabs), " and then ");
474
		}
475
		(void) snprintf(tabs+strlen(tabs), sizeof(tabs)-strlen(tabs),
476
		    "every %d spaces", tabdefault);
477
		p.p_string = tabs;
478
		error("%s", &p);
479
		break;
480
	}
481
}
482
483
484
/*
485
 * Handler for the -" option.
486
 */
487
void
488
opt_quote(int type, char *s)
489
{
490
	char buf[3];
491
	PARG parg;
492
493
	switch (type) {
494
	case INIT:
495
	case TOGGLE:
496
		if (s[0] == '\0') {
497
			openquote = closequote = '\0';
498
			break;
499
		}
500
		if (s[1] != '\0' && s[2] != '\0') {
501
			error("-\" must be followed by 1 or 2 chars",
502
			    NULL);
503
			return;
504
		}
505
		openquote = s[0];
506
		if (s[1] == '\0')
507
			closequote = openquote;
508
		else
509
			closequote = s[1];
510
		break;
511
	case QUERY:
512
		buf[0] = openquote;
513
		buf[1] = closequote;
514
		buf[2] = '\0';
515
		parg.p_string = buf;
516
		error("quotes %s", &parg);
517
		break;
518
	}
519
}
520
521
/*
522
 * "-?" means display a help message.
523
 * If from the command line, exit immediately.
524
 */
525
void
526
opt_query(int type, char *s)
527
{
528
	switch (type) {
529
	case QUERY:
530
	case TOGGLE:
531
		error("Use \"h\" for help", NULL);
532
		break;
533
	case INIT:
534
		dohelp = 1;
535
	}
536
}
537
538
/*
539
 * Get the "screen window" size.
540
 */
541
int
542
get_swindow(void)
543
{
544
1510
	if (swindow > 0)
545
		return (swindow);
546
755
	return (sc_height + swindow);
547
755
}