Annotation of src/usr.bin/less/main.c, Revision 1.32
1.1 etheisen 1: /*
1.13 shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.19 nicm 3: * Modified for use with illumos by Garrett D'Amore.
4: * Copyright 2014 Garrett D'Amore <garrett@damore.org>
1.1 etheisen 5: *
1.7 millert 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.
1.1 etheisen 8: *
1.13 shadchin 9: * For more information, see the README file.
1.17 nicm 10: */
1.1 etheisen 11:
12: /*
13: * Entry point, initialization, miscellaneous routines.
14: */
15:
1.17 nicm 16: #include <libgen.h>
17: #include <stdarg.h>
18: #include <sys/types.h>
1.1 etheisen 19: #include "less.h"
20:
1.17 nicm 21: char *every_first_cmd = NULL;
22: int new_file;
23: int is_tty;
1.25 deraadt 24: IFILE curr_ifile = NULL;
25: IFILE old_ifile = NULL;
1.17 nicm 26: struct scrpos initial_scrpos;
27: int any_display = FALSE;
28: off_t start_attnpos = -1;
29: off_t end_attnpos = -1;
30: int wscroll;
31:
1.18 deraadt 32: static char *progname;
1.17 nicm 33:
34: int quitting;
35: int secure;
36: int dohelp;
37:
38: int logfile = -1;
39: int force_logfile = FALSE;
40: char *namelogfile = NULL;
41: char *editor;
42: char *editproto;
1.1 etheisen 43:
1.18 deraadt 44: extern char *tags;
45: extern char *tagoption;
1.17 nicm 46: extern int jump_sline;
1.11 shadchin 47: extern int less_is_more;
1.7 millert 48: extern int missing_cap;
49: extern int know_dumb;
1.17 nicm 50: extern int quit_if_one_screen;
51: extern int quit_at_eof;
1.11 shadchin 52: extern int pr_type;
1.17 nicm 53: extern int hilite_search;
54: extern int use_lessopen;
55: extern int no_init;
56: extern int top_scroll;
57: extern int errmsgs;
1.7 millert 58:
1.1 etheisen 59:
60: /*
61: * Entry point.
62: */
63: int
1.17 nicm 64: main(int argc, char *argv[])
1.1 etheisen 65: {
66: IFILE ifile;
1.7 millert 67: char *s;
1.1 etheisen 68:
1.17 nicm 69: progname = basename(argv[0]);
70: argv++;
71: argc--;
1.1 etheisen 72:
1.17 nicm 73: /*
74: * If the name of the executable program is "more",
75: * act like LESS_IS_MORE is set. We have to set this as early
76: * as possible for POSIX.
77: */
1.26 deraadt 78: if (strcmp(progname, "more") == 0)
1.17 nicm 79: less_is_more = 1;
1.26 deraadt 80: else {
1.17 nicm 81: s = lgetenv("LESS_IS_MORE");
82: if (s != NULL && *s != '\0')
83: less_is_more = 1;
84: }
1.7 millert 85:
86: secure = 0;
87: s = lgetenv("LESSSECURE");
88: if (s != NULL && *s != '\0')
89: secure = 1;
90:
1.23 deraadt 91: if (secure) {
1.28 deraadt 92: if (pledge("stdio rpath wpath tty", NULL) == -1) {
1.27 deraadt 93: perror("pledge");
1.28 deraadt 94: exit(1);
95: }
1.23 deraadt 96: } else {
1.28 deraadt 97: if (pledge("stdio rpath wpath cpath fattr proc exec tty", NULL) == -1) {
1.27 deraadt 98: perror("pledge");
1.28 deraadt 99: exit(1);
100: }
1.23 deraadt 101: }
102:
1.1 etheisen 103: /*
104: * Process command line arguments and LESS environment arguments.
105: * Command line arguments override environment arguments.
106: */
1.7 millert 107: is_tty = isatty(1);
1.1 etheisen 108: get_term();
109: init_cmds();
110: init_charset();
1.7 millert 111: init_line();
1.11 shadchin 112: init_cmdhist();
1.1 etheisen 113: init_option();
1.11 shadchin 114: init_search();
115:
116:
117: init_prompt();
118:
119: s = lgetenv(less_is_more ? "MORE" : "LESS");
1.7 millert 120: if (s != NULL)
1.20 tedu 121: scan_option(estrdup(s));
1.1 etheisen 122:
1.17 nicm 123: if (less_is_more) {
124: /* this is specified by XPG */
125: quit_at_eof = OPT_ON;
126:
127: /* more users don't like the warning */
128: know_dumb = OPT_ON;
129:
130: /* default prompt is medium */
131: pr_type = OPT_ON;
132:
133: /* do not hilight search terms */
134: hilite_search = OPT_OFF;
135:
136: /* do not use LESSOPEN */
137: use_lessopen = OPT_OFF;
138:
139: /* do not set init strings to terminal */
140: no_init = OPT_ON;
141:
142: /* repaint from top of screen */
143: top_scroll = OPT_OFF;
144: }
145:
1.7 millert 146: #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
1.17 nicm 147: while (argc > 0 && (isoptstring(*argv) || isoptpending())) {
1.7 millert 148: s = *argv++;
149: argc--;
150: if (strcmp(s, "--") == 0)
1.3 deraadt 151: break;
1.7 millert 152: scan_option(s);
1.3 deraadt 153: }
1.1 etheisen 154: #undef isoptstring
155:
1.17 nicm 156: if (isoptpending()) {
1.1 etheisen 157: /*
158: * Last command line option was a flag requiring a
159: * following string, but there was no following string.
160: */
161: nopendopt();
162: quit(QUIT_OK);
163: }
1.11 shadchin 164:
1.17 nicm 165: if (errmsgs) {
166: quit(QUIT_ERROR);
167: }
168: if (less_is_more && quit_at_eof == OPT_ONPLUS) {
169: extern int no_init;
170: no_init = OPT_ON;
171: }
172: if (less_is_more && pr_type == OPT_ONPLUS) {
173: extern int quiet;
174: quiet = VERY_QUIET;
175: }
176:
1.7 millert 177: editor = lgetenv("VISUAL");
1.17 nicm 178: if (editor == NULL || *editor == '\0') {
1.7 millert 179: editor = lgetenv("EDITOR");
1.1 etheisen 180: if (editor == NULL || *editor == '\0')
181: editor = EDIT_PGM;
182: }
1.7 millert 183: editproto = lgetenv("LESSEDIT");
1.1 etheisen 184: if (editproto == NULL || *editproto == '\0')
185: editproto = "%E ?lm+%lm. %f";
186:
187: /*
188: * Call get_ifile with all the command line filenames
189: * to "register" them with the ifile system.
190: */
1.25 deraadt 191: ifile = NULL;
1.11 shadchin 192: if (dohelp)
1.15 schwarze 193: ifile = get_ifile(helpfile(), ifile);
1.17 nicm 194: while (argc-- > 0) {
1.7 millert 195: char *filename;
196: filename = shell_quote(*argv);
197: if (filename == NULL)
198: filename = *argv;
199: argv++;
200: (void) get_ifile(filename, ifile);
1.25 deraadt 201: ifile = prev_ifile(NULL);
1.13 shadchin 202: free(filename);
1.1 etheisen 203: }
204: /*
205: * Set up terminal, etc.
206: */
1.17 nicm 207: if (!is_tty) {
1.1 etheisen 208: /*
209: * Output is not a tty.
210: * Just copy the input file(s) to output.
211: */
1.17 nicm 212: if (nifile() == 0) {
1.1 etheisen 213: if (edit_stdin() == 0)
214: cat_file();
1.17 nicm 215: } else if (edit_first() == 0) {
1.1 etheisen 216: do {
217: cat_file();
218: } while (edit_next(1) == 0);
219: }
220: quit(QUIT_OK);
221: }
222:
1.17 nicm 223: if (missing_cap && !know_dumb)
1.24 deraadt 224: error("WARNING: terminal is not fully functional", NULL);
1.1 etheisen 225: init_mark();
1.7 millert 226: open_getchr();
1.23 deraadt 227:
228: if (secure)
1.28 deraadt 229: if (pledge("stdio rpath tty", NULL) == -1) {
1.27 deraadt 230: perror("pledge");
1.28 deraadt 231: exit(1);
232: }
1.23 deraadt 233:
1.1 etheisen 234: raw_mode(1);
235: init_signals(1);
236:
237: /*
238: * Select the first file to examine.
239: */
1.17 nicm 240: if (tagoption != NULL || strcmp(tags, "-") == 0) {
1.1 etheisen 241: /*
242: * A -t option was given.
243: * Verify that no filenames were also given.
244: * Edit the file selected by the "tags" search,
245: * and search for the proper line in the file.
246: */
1.17 nicm 247: if (nifile() > 0) {
1.24 deraadt 248: error("No filenames allowed with -t option", NULL);
1.1 etheisen 249: quit(QUIT_ERROR);
250: }
251: findtag(tagoption);
1.7 millert 252: if (edit_tagfile()) /* Edit file which contains the tag */
1.1 etheisen 253: quit(QUIT_ERROR);
254: /*
255: * Search for the line which contains the tag.
256: * Set up initial_scrpos so we display that line.
257: */
258: initial_scrpos.pos = tagsearch();
1.17 nicm 259: if (initial_scrpos.pos == -1)
1.1 etheisen 260: quit(QUIT_ERROR);
261: initial_scrpos.ln = jump_sline;
1.17 nicm 262: } else if (nifile() == 0) {
1.1 etheisen 263: if (edit_stdin()) /* Edit standard input */
264: quit(QUIT_ERROR);
1.17 nicm 265: } else {
1.1 etheisen 266: if (edit_first()) /* Edit first valid file in cmd line */
267: quit(QUIT_ERROR);
268: }
269:
270: init();
271: commands();
272: quit(QUIT_OK);
1.7 millert 273: return (0);
1.1 etheisen 274: }
275:
276: /*
277: * Allocate memory.
278: * Like calloc(), but never returns an error (NULL).
279: */
1.17 nicm 280: void *
281: ecalloc(int count, unsigned int size)
1.1 etheisen 282: {
1.17 nicm 283: void *p;
1.1 etheisen 284:
1.17 nicm 285: p = calloc(count, size);
1.1 etheisen 286: if (p != NULL)
287: return (p);
1.24 deraadt 288: error("Cannot allocate memory", NULL);
1.1 etheisen 289: quit(QUIT_ERROR);
1.7 millert 290: return (NULL);
1.1 etheisen 291: }
292:
1.17 nicm 293: char *
294: easprintf(const char *fmt, ...)
295: {
296: char *p = NULL;
297: int rv;
298: va_list ap;
299:
300: va_start(ap, fmt);
301: rv = vasprintf(&p, fmt, ap);
302: va_end(ap);
303:
304: if (p == NULL || rv < 0) {
1.24 deraadt 305: error("Cannot allocate memory", NULL);
1.17 nicm 306: quit(QUIT_ERROR);
307: }
308: return (p);
309: }
310:
311: char *
312: estrdup(const char *str)
313: {
1.20 tedu 314: char *n;
1.31 deraadt 315:
1.20 tedu 316: n = strdup(str);
317: if (n == NULL) {
1.24 deraadt 318: error("Cannot allocate memory", NULL);
1.20 tedu 319: quit(QUIT_ERROR);
1.17 nicm 320: }
321: return (n);
322: }
323:
1.1 etheisen 324: /*
325: * Skip leading spaces in a string.
326: */
1.17 nicm 327: char *
328: skipsp(char *s)
1.1 etheisen 329: {
1.17 nicm 330: while (*s == ' ' || *s == '\t')
1.1 etheisen 331: s++;
332: return (s);
333: }
334:
335: /*
1.7 millert 336: * See how many characters of two strings are identical.
337: * If uppercase is true, the first string must begin with an uppercase
338: * character; the remainder of the first string may be either case.
339: */
1.17 nicm 340: int
341: sprefix(char *ps, char *s, int uppercase)
1.7 millert 342: {
1.17 nicm 343: int c;
344: int sc;
345: int len = 0;
1.7 millert 346:
1.17 nicm 347: for (; *s != '\0'; s++, ps++) {
1.7 millert 348: c = *ps;
1.17 nicm 349: if (uppercase) {
1.30 guenther 350: if (len == 0 && islower(c))
1.7 millert 351: return (-1);
1.30 guenther 352: c = tolower(c);
1.7 millert 353: }
354: sc = *s;
1.30 guenther 355: if (len > 0)
1.17 nicm 356: sc = tolower(sc);
1.7 millert 357: if (c != sc)
358: break;
359: len++;
360: }
361: return (len);
362: }
363:
364: /*
1.1 etheisen 365: * Exit the program.
366: */
1.17 nicm 367: void
368: quit(int status)
1.1 etheisen 369: {
370: static int save_status;
371:
372: /*
373: * Put cursor at bottom left corner, clear the line,
374: * reset the terminal modes, and exit.
375: */
376: if (status < 0)
377: status = save_status;
378: else
379: save_status = status;
380: quitting = 1;
1.17 nicm 381: edit(NULL);
1.22 deraadt 382: if (!secure)
383: save_cmdhist();
1.7 millert 384: if (any_display && is_tty)
1.1 etheisen 385: clear_bot();
386: deinit();
1.29 nicm 387: flush(1);
1.1 etheisen 388: raw_mode(0);
389: exit(status);
1.15 schwarze 390: }
391:
1.17 nicm 392: char *
1.15 schwarze 393: helpfile(void)
394: {
395: return (less_is_more ? HELPDIR "/more.help" : HELPDIR "/less.help");
1.1 etheisen 396: }