GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../main.c Lines: 97 161 60.2 %
Date: 2017-11-07 Branches: 46 118 39.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
 * Entry point, initialization, miscellaneous routines.
14
 */
15
16
#include <sys/types.h>
17
18
#include <libgen.h>
19
#include <stdarg.h>
20
21
#include "less.h"
22
23
char	*every_first_cmd = NULL;
24
int	new_file;
25
int	is_tty;
26
IFILE	curr_ifile = NULL;
27
IFILE	old_ifile = NULL;
28
struct scrpos initial_scrpos;
29
int	any_display = FALSE;
30
off_t	start_attnpos = -1;
31
off_t	end_attnpos = -1;
32
int	wscroll;
33
34
static char	*progname;
35
36
int	quitting;
37
int	secure;
38
int	dohelp;
39
40
int logfile = -1;
41
int force_logfile = FALSE;
42
char *namelogfile = NULL;
43
char *editor;
44
char *editproto;
45
46
extern char	*tags;
47
extern char	*tagoption;
48
extern int	jump_sline;
49
extern int	less_is_more;
50
extern int	missing_cap;
51
extern int	know_dumb;
52
extern int	quit_if_one_screen;
53
extern int	quit_at_eof;
54
extern int	pr_type;
55
extern int	hilite_search;
56
extern int	use_lessopen;
57
extern int	no_init;
58
extern int	top_scroll;
59
extern int	errmsgs;
60
61
62
/*
63
 * Entry point.
64
 */
65
int
66
main(int argc, char *argv[])
67
{
68
	IFILE ifile;
69
	char *s;
70
71
78
	progname = basename(argv[0]);
72
39
	argv++;
73
39
	argc--;
74
75
	/*
76
	 * If the name of the executable program is "more",
77
	 * act like LESS_IS_MORE is set.  We have to set this as early
78
	 * as possible for POSIX.
79
	 */
80
39
	if (strcmp(progname, "more") == 0)
81
5
		less_is_more = 1;
82
	else {
83
34
		s = lgetenv("LESS_IS_MORE");
84

34
		if (s != NULL && *s != '\0')
85
			less_is_more = 1;
86
	}
87
88
39
	secure = 0;
89
39
	s = lgetenv("LESSSECURE");
90

39
	if (s != NULL && *s != '\0')
91
		secure = 1;
92
93
39
	if (secure) {
94
		if (pledge("stdio rpath wpath tty flock cpath", NULL) == -1) {
95
			perror("pledge");
96
			exit(1);
97
		}
98
	} else {
99
39
		if (pledge("stdio rpath wpath cpath fattr proc exec tty flock", NULL) == -1) {
100
			perror("pledge");
101
			exit(1);
102
		}
103
	}
104
105
	/*
106
	 * Process command line arguments and LESS environment arguments.
107
	 * Command line arguments override environment arguments.
108
	 */
109
39
	is_tty = isatty(1);
110
39
	get_term();
111
39
	init_cmds();
112
39
	init_charset();
113
39
	init_line();
114
39
	init_cmdhist();
115
39
	init_option();
116
39
	init_search();
117
118
119
39
	init_prompt();
120
121
39
	if (less_is_more) {
122
		/* this is specified by XPG */
123
5
		quit_at_eof = OPT_ON;
124
125
		/* more users don't like the warning */
126
5
		know_dumb = OPT_ON;
127
128
		/* default prompt is medium */
129
5
		pr_type = OPT_ON;
130
131
		/* do not hilight search terms */
132
5
		hilite_search = OPT_OFF;
133
134
		/* do not use LESSOPEN */
135
5
		use_lessopen = OPT_OFF;
136
137
		/* do not set init strings to terminal */
138
5
		no_init = OPT_ON;
139
140
		/* repaint from top of screen */
141
5
		top_scroll = OPT_OFF;
142
5
	}
143
144
39
	s = lgetenv(less_is_more ? "MORE" : "LESS");
145
39
	if (s != NULL)
146
		scan_option(estrdup(s));
147
148
#define	isoptstring(s)	(((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
149


185
	while (argc > 0 && (isoptstring(*argv) || isoptpending())) {
150
15
		s = *argv++;
151
15
		argc--;
152
15
		if (strcmp(s, "--") == 0)
153
			break;
154
15
		scan_option(s);
155
	}
156
#undef isoptstring
157
158
39
	if (isoptpending()) {
159
		/*
160
		 * Last command line option was a flag requiring a
161
		 * following string, but there was no following string.
162
		 */
163
		nopendopt();
164
		quit(QUIT_OK);
165
	}
166
167
39
	if (errmsgs) {
168
		quit(QUIT_ERROR);
169
	}
170
39
	if (less_is_more && quit_at_eof == OPT_ONPLUS) {
171
		extern int no_init;
172
		no_init = OPT_ON;
173
	}
174
39
	if (less_is_more && pr_type == OPT_ONPLUS) {
175
		extern int quiet;
176
		quiet = VERY_QUIET;
177
	}
178
179
39
	editor = lgetenv("VISUAL");
180

39
	if (editor == NULL || *editor == '\0') {
181
39
		editor = lgetenv("EDITOR");
182

39
		if (editor == NULL || *editor == '\0')
183
39
			editor = EDIT_PGM;
184
	}
185
39
	editproto = lgetenv("LESSEDIT");
186

39
	if (editproto == NULL || *editproto == '\0')
187
39
		editproto = "%E ?lm+%lm. %f";
188
189
	/*
190
	 * Call get_ifile with all the command line filenames
191
	 * to "register" them with the ifile system.
192
	 */
193
	ifile = NULL;
194
39
	if (dohelp)
195
		ifile = get_ifile(helpfile(), ifile);
196
93
	while (argc-- > 0) {
197
		char *filename;
198
27
		filename = shell_quote(*argv);
199
27
		if (filename == NULL)
200
			filename = *argv;
201
27
		argv++;
202
27
		(void) get_ifile(filename, ifile);
203
27
		ifile = prev_ifile(NULL);
204
27
		free(filename);
205
	}
206
	/*
207
	 * Set up terminal, etc.
208
	 */
209
39
	if (!is_tty) {
210
		/*
211
		 * Output is not a tty.
212
		 * Just copy the input file(s) to output.
213
		 */
214
		if (nifile() == 0) {
215
			if (edit_stdin() == 0)
216
				cat_file();
217
		} else if (edit_first() == 0) {
218
			do {
219
				cat_file();
220
			} while (edit_next(1) == 0);
221
		}
222
		quit(QUIT_OK);
223
	}
224
225
39
	if (missing_cap && !know_dumb)
226
		error("WARNING: terminal is not fully functional", NULL);
227
39
	init_mark();
228
39
	open_getchr();
229
230
39
	if (secure)
231
		if (pledge("stdio rpath tty flock cpath wpath", NULL) == -1) {
232
			perror("pledge");
233
			exit(1);
234
		}
235
236
39
	raw_mode(1);
237
39
	init_signals(1);
238
239
	/*
240
	 * Select the first file to examine.
241
	 */
242

78
	if (tagoption != NULL || strcmp(tags, "-") == 0) {
243
		/*
244
		 * A -t option was given.
245
		 * Verify that no filenames were also given.
246
		 * Edit the file selected by the "tags" search,
247
		 * and search for the proper line in the file.
248
		 */
249
		if (nifile() > 0) {
250
			error("No filenames allowed with -t option", NULL);
251
			quit(QUIT_ERROR);
252
		}
253
		findtag(tagoption);
254
		if (edit_tagfile())  /* Edit file which contains the tag */
255
			quit(QUIT_ERROR);
256
		/*
257
		 * Search for the line which contains the tag.
258
		 * Set up initial_scrpos so we display that line.
259
		 */
260
		initial_scrpos.pos = tagsearch();
261
		if (initial_scrpos.pos == -1)
262
			quit(QUIT_ERROR);
263
		initial_scrpos.ln = jump_sline;
264
39
	} else if (nifile() == 0) {
265
12
		if (edit_stdin())  /* Edit standard input */
266
			quit(QUIT_ERROR);
267
	} else {
268
27
		if (edit_first())  /* Edit first valid file in cmd line */
269
2
			quit(QUIT_ERROR);
270
	}
271
272
37
	init();
273
37
	commands();
274
37
	quit(QUIT_OK);
275
37
	return (0);
276
}
277
278
/*
279
 * Allocate memory.
280
 * Like calloc(), but never returns an error (NULL).
281
 */
282
void *
283
ecalloc(int count, unsigned int size)
284
{
285
	void *p;
286
287
62950
	p = calloc(count, size);
288
31475
	if (p != NULL)
289
31475
		return (p);
290
	error("Cannot allocate memory", NULL);
291
	quit(QUIT_ERROR);
292
	return (NULL);
293
31475
}
294
295
char *
296
easprintf(const char *fmt, ...)
297
{
298
72
	char *p = NULL;
299
	int rv;
300
36
	va_list ap;
301
302
36
	va_start(ap, fmt);
303
36
	rv = vasprintf(&p, fmt, ap);
304
36
	va_end(ap);
305
306
36
	if (p == NULL || rv < 0) {
307
		error("Cannot allocate memory", NULL);
308
		quit(QUIT_ERROR);
309
	}
310
72
	return (p);
311
36
}
312
313
char *
314
estrdup(const char *str)
315
{
316
	char *n;
317
318
938
	n = strdup(str);
319
469
	if (n == NULL) {
320
		error("Cannot allocate memory", NULL);
321
		quit(QUIT_ERROR);
322
	}
323
469
	return (n);
324
}
325
326
/*
327
 * Skip leading spaces in a string.
328
 */
329
char *
330
skipsp(char *s)
331
{
332
	while (*s == ' ' || *s == '\t')
333
		s++;
334
	return (s);
335
}
336
337
/*
338
 * See how many characters of two strings are identical.
339
 * If uppercase is true, the first string must begin with an uppercase
340
 * character; the remainder of the first string may be either case.
341
 */
342
int
343
sprefix(char *ps, char *s, int uppercase)
344
{
345
	int c;
346
	int sc;
347
	int len = 0;
348
349
	for (; *s != '\0'; s++, ps++) {
350
		c = *ps;
351
		if (uppercase) {
352
			if (len == 0 && islower(c))
353
				return (-1);
354
			c = tolower(c);
355
		}
356
		sc = *s;
357
		if (len > 0)
358
			sc = tolower(sc);
359
		if (c != sc)
360
			break;
361
		len++;
362
	}
363
	return (len);
364
}
365
366
/*
367
 * Exit the program.
368
 */
369
void
370
quit(int status)
371
{
372
	static int save_status;
373
374
	/*
375
	 * Put cursor at bottom left corner, clear the line,
376
	 * reset the terminal modes, and exit.
377
	 */
378
78
	if (status < 0)
379
		status = save_status;
380
	else
381
39
		save_status = status;
382
39
	quitting = 1;
383
39
	edit(NULL);
384
39
	if (!secure)
385
39
		save_cmdhist();
386
39
	if (any_display && is_tty)
387
37
		clear_bot();
388
	deinit();
389
	flush(1);
390
	raw_mode(0);
391
	exit(status);
392
}
393
394
char *
395
helpfile(void)
396
{
397
78
	return (less_is_more ? HELPDIR "/more.help" : HELPDIR "/less.help");
398
}