Merge commit '9992e6a682b1c35b4385c3b512db329ec8ab9ede'
[unleashed.git] / bin / less / main.c
blob6a06cd0679c5622a4877c891492ca0b7aec51c73
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>
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.
9 * For more information, see the README file.
13 * Entry point, initialization, miscellaneous routines.
16 #include <sys/types.h>
18 #include <libgen.h>
19 #include <stdarg.h>
21 #include "less.h"
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;
34 static char *progname;
36 int quitting;
37 int secure;
38 int dohelp;
40 int logfile = -1;
41 int force_logfile = FALSE;
42 char *namelogfile = NULL;
43 char *editor;
44 char *editproto;
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;
63 * Entry point.
65 int
66 main(int argc, char *argv[])
68 IFILE ifile;
69 char *s;
71 progname = basename(argv[0]);
72 argv++;
73 argc--;
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.
80 if (strcmp(progname, "more") == 0)
81 less_is_more = 1;
82 else {
83 s = lgetenv("LESS_IS_MORE");
84 if (s != NULL && *s != '\0')
85 less_is_more = 1;
88 secure = 0;
89 s = lgetenv("LESSSECURE");
90 if (s != NULL && *s != '\0')
91 secure = 1;
93 if (secure) {
94 if (pledge("stdio rpath wpath tty", NULL) == -1) {
95 perror("pledge");
96 exit(1);
98 } else {
99 if (pledge("stdio rpath wpath cpath fattr proc exec tty", NULL) == -1) {
100 perror("pledge");
101 exit(1);
106 * Process command line arguments and LESS environment arguments.
107 * Command line arguments override environment arguments.
109 is_tty = isatty(1);
110 get_term();
111 init_cmds();
112 init_charset();
113 init_line();
114 init_cmdhist();
115 init_option();
116 init_search();
119 init_prompt();
121 if (less_is_more) {
122 /* this is specified by XPG */
123 quit_at_eof = OPT_ON;
125 /* more users don't like the warning */
126 know_dumb = OPT_ON;
128 /* default prompt is medium */
129 pr_type = OPT_ON;
131 /* do not hilight search terms */
132 hilite_search = OPT_OFF;
134 /* do not use LESSOPEN */
135 use_lessopen = OPT_OFF;
137 /* do not set init strings to terminal */
138 no_init = OPT_ON;
140 /* repaint from top of screen */
141 top_scroll = OPT_OFF;
144 s = lgetenv(less_is_more ? "MORE" : "LESS");
145 if (s != NULL)
146 scan_option(estrdup(s));
148 #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
149 while (argc > 0 && (isoptstring(*argv) || isoptpending())) {
150 s = *argv++;
151 argc--;
152 if (strcmp(s, "--") == 0)
153 break;
154 scan_option(s);
156 #undef isoptstring
158 if (isoptpending()) {
160 * Last command line option was a flag requiring a
161 * following string, but there was no following string.
163 nopendopt();
164 quit(QUIT_OK);
167 if (errmsgs) {
168 quit(QUIT_ERROR);
170 if (less_is_more && quit_at_eof == OPT_ONPLUS) {
171 extern int no_init;
172 no_init = OPT_ON;
174 if (less_is_more && pr_type == OPT_ONPLUS) {
175 extern int quiet;
176 quiet = VERY_QUIET;
179 editor = lgetenv("VISUAL");
180 if (editor == NULL || *editor == '\0') {
181 editor = lgetenv("EDITOR");
182 if (editor == NULL || *editor == '\0')
183 editor = EDIT_PGM;
185 editproto = lgetenv("LESSEDIT");
186 if (editproto == NULL || *editproto == '\0')
187 editproto = "%E ?lm+%lm. %f";
190 * Call get_ifile with all the command line filenames
191 * to "register" them with the ifile system.
193 ifile = NULL;
194 if (dohelp)
195 ifile = get_ifile(helpfile(), ifile);
196 while (argc-- > 0) {
197 char *filename;
198 filename = shell_quote(*argv);
199 if (filename == NULL)
200 filename = *argv;
201 argv++;
202 (void) get_ifile(filename, ifile);
203 ifile = prev_ifile(NULL);
204 free(filename);
207 * Set up terminal, etc.
209 if (!is_tty) {
211 * Output is not a tty.
212 * Just copy the input file(s) to output.
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);
222 quit(QUIT_OK);
225 if (missing_cap && !know_dumb)
226 error("WARNING: terminal is not fully functional", NULL);
227 init_mark();
228 open_getchr();
230 if (secure)
231 if (pledge("stdio rpath tty", NULL) == -1) {
232 perror("pledge");
233 exit(1);
236 raw_mode(1);
237 init_signals(1);
240 * Select the first file to examine.
242 if (tagoption != NULL || strcmp(tags, "-") == 0) {
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.
249 if (nifile() > 0) {
250 error("No filenames allowed with -t option", NULL);
251 quit(QUIT_ERROR);
253 findtag(tagoption);
254 if (edit_tagfile()) /* Edit file which contains the tag */
255 quit(QUIT_ERROR);
257 * Search for the line which contains the tag.
258 * Set up initial_scrpos so we display that line.
260 initial_scrpos.pos = tagsearch();
261 if (initial_scrpos.pos == -1)
262 quit(QUIT_ERROR);
263 initial_scrpos.ln = jump_sline;
264 } else if (nifile() == 0) {
265 if (edit_stdin()) /* Edit standard input */
266 quit(QUIT_ERROR);
267 } else {
268 if (edit_first()) /* Edit first valid file in cmd line */
269 quit(QUIT_ERROR);
272 init();
273 commands();
274 quit(QUIT_OK);
275 return (0);
279 * Allocate memory.
280 * Like calloc(), but never returns an error (NULL).
282 void *
283 ecalloc(int count, unsigned int size)
285 void *p;
287 p = calloc(count, size);
288 if (p != NULL)
289 return (p);
290 error("Cannot allocate memory", NULL);
291 quit(QUIT_ERROR);
292 return (NULL);
295 char *
296 easprintf(const char *fmt, ...)
298 char *p = NULL;
299 int rv;
300 va_list ap;
302 va_start(ap, fmt);
303 rv = vasprintf(&p, fmt, ap);
304 va_end(ap);
306 if (p == NULL || rv < 0) {
307 error("Cannot allocate memory", NULL);
308 quit(QUIT_ERROR);
310 return (p);
313 char *
314 estrdup(const char *str)
316 char *n;
318 n = strdup(str);
319 if (n == NULL) {
320 error("Cannot allocate memory", NULL);
321 quit(QUIT_ERROR);
323 return (n);
327 * Skip leading spaces in a string.
329 char *
330 skipsp(char *s)
332 while (*s == ' ' || *s == '\t')
333 s++;
334 return (s);
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.
343 sprefix(char *ps, char *s, int uppercase)
345 int c;
346 int sc;
347 int len = 0;
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);
356 sc = *s;
357 if (len > 0)
358 sc = tolower(sc);
359 if (c != sc)
360 break;
361 len++;
363 return (len);
367 * Exit the program.
369 void
370 quit(int status)
372 static int save_status;
375 * Put cursor at bottom left corner, clear the line,
376 * reset the terminal modes, and exit.
378 if (status < 0)
379 status = save_status;
380 else
381 save_status = status;
382 quitting = 1;
383 edit(NULL);
384 if (!secure)
385 save_cmdhist();
386 if (any_display && is_tty)
387 clear_bot();
388 deinit();
389 flush(1);
390 raw_mode(0);
391 exit(status);
394 char *
395 helpfile(void)
397 return (less_is_more ? HELPDIR "/more.help" : HELPDIR "/less.help");