Annotation of src/usr.bin/less/main.c, Revision 1.37
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.33 mmcc 16: #include <sys/types.h>
17:
1.17 nicm 18: #include <libgen.h>
19: #include <stdarg.h>
1.33 mmcc 20:
1.1 etheisen 21: #include "less.h"
22:
1.17 nicm 23: char *every_first_cmd = NULL;
24: int new_file;
25: int is_tty;
1.25 deraadt 26: IFILE curr_ifile = NULL;
27: IFILE old_ifile = NULL;
1.17 nicm 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:
1.18 deraadt 34: static char *progname;
1.17 nicm 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;
1.1 etheisen 45:
1.18 deraadt 46: extern char *tags;
47: extern char *tagoption;
1.17 nicm 48: extern int jump_sline;
1.11 shadchin 49: extern int less_is_more;
1.7 millert 50: extern int missing_cap;
51: extern int know_dumb;
1.17 nicm 52: extern int quit_if_one_screen;
53: extern int quit_at_eof;
1.11 shadchin 54: extern int pr_type;
1.17 nicm 55: extern int hilite_search;
56: extern int use_lessopen;
57: extern int no_init;
58: extern int top_scroll;
59: extern int errmsgs;
1.7 millert 60:
1.1 etheisen 61:
62: /*
63: * Entry point.
64: */
65: int
1.17 nicm 66: main(int argc, char *argv[])
1.1 etheisen 67: {
68: IFILE ifile;
1.7 millert 69: char *s;
1.1 etheisen 70:
1.17 nicm 71: progname = basename(argv[0]);
72: argv++;
73: argc--;
1.1 etheisen 74:
1.17 nicm 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: */
1.26 deraadt 80: if (strcmp(progname, "more") == 0)
1.17 nicm 81: less_is_more = 1;
1.26 deraadt 82: else {
1.17 nicm 83: s = lgetenv("LESS_IS_MORE");
84: if (s != NULL && *s != '\0')
85: less_is_more = 1;
86: }
1.7 millert 87:
88: secure = 0;
89: s = lgetenv("LESSSECURE");
90: if (s != NULL && *s != '\0')
91: secure = 1;
92:
1.23 deraadt 93: if (secure) {
1.28 deraadt 94: if (pledge("stdio rpath wpath tty", NULL) == -1) {
1.27 deraadt 95: perror("pledge");
1.28 deraadt 96: exit(1);
97: }
1.23 deraadt 98: } else {
1.28 deraadt 99: if (pledge("stdio rpath wpath cpath fattr proc exec tty", NULL) == -1) {
1.27 deraadt 100: perror("pledge");
1.28 deraadt 101: exit(1);
102: }
1.23 deraadt 103: }
104:
1.1 etheisen 105: /*
106: * Process command line arguments and LESS environment arguments.
107: * Command line arguments override environment arguments.
108: */
1.7 millert 109: is_tty = isatty(1);
1.1 etheisen 110: get_term();
111: init_cmds();
112: init_charset();
1.7 millert 113: init_line();
1.11 shadchin 114: init_cmdhist();
1.1 etheisen 115: init_option();
1.11 shadchin 116: init_search();
117:
118:
119: init_prompt();
120:
1.17 nicm 121: if (less_is_more) {
122: /* this is specified by XPG */
123: quit_at_eof = OPT_ON;
124:
125: /* more users don't like the warning */
126: know_dumb = OPT_ON;
127:
128: /* default prompt is medium */
129: pr_type = OPT_ON;
130:
131: /* do not hilight search terms */
132: hilite_search = OPT_OFF;
133:
134: /* do not use LESSOPEN */
135: use_lessopen = OPT_OFF;
136:
137: /* do not set init strings to terminal */
138: no_init = OPT_ON;
139:
140: /* repaint from top of screen */
141: top_scroll = OPT_OFF;
142: }
1.34 nicm 143:
144: s = lgetenv(less_is_more ? "MORE" : "LESS");
145: if (s != NULL)
1.36 krw 146: scan_option(estrdup(s), 1);
1.17 nicm 147:
1.7 millert 148: #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
1.17 nicm 149: while (argc > 0 && (isoptstring(*argv) || isoptpending())) {
1.7 millert 150: s = *argv++;
151: argc--;
152: if (strcmp(s, "--") == 0)
1.3 deraadt 153: break;
1.36 krw 154: scan_option(s, 0);
1.3 deraadt 155: }
1.1 etheisen 156: #undef isoptstring
157:
1.17 nicm 158: if (isoptpending()) {
1.1 etheisen 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: }
1.11 shadchin 166:
1.17 nicm 167: if (errmsgs) {
168: quit(QUIT_ERROR);
169: }
170: if (less_is_more && quit_at_eof == OPT_ONPLUS) {
171: extern int no_init;
172: no_init = OPT_ON;
173: }
174: if (less_is_more && pr_type == OPT_ONPLUS) {
175: extern int quiet;
176: quiet = VERY_QUIET;
177: }
178:
1.7 millert 179: editor = lgetenv("VISUAL");
1.17 nicm 180: if (editor == NULL || *editor == '\0') {
1.7 millert 181: editor = lgetenv("EDITOR");
1.1 etheisen 182: if (editor == NULL || *editor == '\0')
183: editor = EDIT_PGM;
184: }
1.7 millert 185: editproto = lgetenv("LESSEDIT");
1.1 etheisen 186: if (editproto == NULL || *editproto == '\0')
187: 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: */
1.25 deraadt 193: ifile = NULL;
1.11 shadchin 194: if (dohelp)
1.15 schwarze 195: ifile = get_ifile(helpfile(), ifile);
1.17 nicm 196: while (argc-- > 0) {
1.7 millert 197: char *filename;
198: filename = shell_quote(*argv);
199: if (filename == NULL)
200: filename = *argv;
201: argv++;
202: (void) get_ifile(filename, ifile);
1.25 deraadt 203: ifile = prev_ifile(NULL);
1.13 shadchin 204: free(filename);
1.1 etheisen 205: }
206: /*
207: * Set up terminal, etc.
208: */
1.17 nicm 209: if (!is_tty) {
1.1 etheisen 210: /*
211: * Output is not a tty.
212: * Just copy the input file(s) to output.
213: */
1.17 nicm 214: if (nifile() == 0) {
1.1 etheisen 215: if (edit_stdin() == 0)
216: cat_file();
1.17 nicm 217: } else if (edit_first() == 0) {
1.1 etheisen 218: do {
219: cat_file();
220: } while (edit_next(1) == 0);
221: }
222: quit(QUIT_OK);
223: }
224:
1.17 nicm 225: if (missing_cap && !know_dumb)
1.24 deraadt 226: error("WARNING: terminal is not fully functional", NULL);
1.1 etheisen 227: init_mark();
1.7 millert 228: open_getchr();
1.23 deraadt 229:
230: if (secure)
1.28 deraadt 231: if (pledge("stdio rpath tty", NULL) == -1) {
1.27 deraadt 232: perror("pledge");
1.28 deraadt 233: exit(1);
234: }
1.23 deraadt 235:
1.1 etheisen 236: raw_mode(1);
237: init_signals(1);
238:
239: /*
240: * Select the first file to examine.
241: */
1.17 nicm 242: if (tagoption != NULL || strcmp(tags, "-") == 0) {
1.1 etheisen 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: */
1.17 nicm 249: if (nifile() > 0) {
1.24 deraadt 250: error("No filenames allowed with -t option", NULL);
1.1 etheisen 251: quit(QUIT_ERROR);
252: }
253: findtag(tagoption);
1.7 millert 254: if (edit_tagfile()) /* Edit file which contains the tag */
1.1 etheisen 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();
1.17 nicm 261: if (initial_scrpos.pos == -1)
1.1 etheisen 262: quit(QUIT_ERROR);
263: initial_scrpos.ln = jump_sline;
1.17 nicm 264: } else if (nifile() == 0) {
1.1 etheisen 265: if (edit_stdin()) /* Edit standard input */
266: quit(QUIT_ERROR);
1.17 nicm 267: } else {
1.1 etheisen 268: if (edit_first()) /* Edit first valid file in cmd line */
269: quit(QUIT_ERROR);
270: }
271:
272: init();
273: commands();
274: quit(QUIT_OK);
1.7 millert 275: return (0);
1.1 etheisen 276: }
277:
278: /*
279: * Allocate memory.
280: * Like calloc(), but never returns an error (NULL).
281: */
1.17 nicm 282: void *
283: ecalloc(int count, unsigned int size)
1.1 etheisen 284: {
1.17 nicm 285: void *p;
1.1 etheisen 286:
1.17 nicm 287: p = calloc(count, size);
1.1 etheisen 288: if (p != NULL)
289: return (p);
1.24 deraadt 290: error("Cannot allocate memory", NULL);
1.1 etheisen 291: quit(QUIT_ERROR);
1.7 millert 292: return (NULL);
1.1 etheisen 293: }
294:
1.17 nicm 295: char *
296: easprintf(const char *fmt, ...)
297: {
298: char *p = NULL;
299: int rv;
300: va_list ap;
301:
302: va_start(ap, fmt);
303: rv = vasprintf(&p, fmt, ap);
304: va_end(ap);
305:
1.37 ! deraadt 306: if (rv == -1) {
1.24 deraadt 307: error("Cannot allocate memory", NULL);
1.17 nicm 308: quit(QUIT_ERROR);
309: }
310: return (p);
311: }
312:
313: char *
314: estrdup(const char *str)
315: {
1.20 tedu 316: char *n;
1.31 deraadt 317:
1.20 tedu 318: n = strdup(str);
319: if (n == NULL) {
1.24 deraadt 320: error("Cannot allocate memory", NULL);
1.20 tedu 321: quit(QUIT_ERROR);
1.17 nicm 322: }
323: return (n);
324: }
325:
1.1 etheisen 326: /*
327: * Skip leading spaces in a string.
328: */
1.17 nicm 329: char *
330: skipsp(char *s)
1.1 etheisen 331: {
1.17 nicm 332: while (*s == ' ' || *s == '\t')
1.1 etheisen 333: s++;
334: return (s);
335: }
336:
337: /*
1.7 millert 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: */
1.17 nicm 342: int
343: sprefix(char *ps, char *s, int uppercase)
1.7 millert 344: {
1.17 nicm 345: int c;
346: int sc;
347: int len = 0;
1.7 millert 348:
1.35 deraadt 349: for (; *s != '\0'; s++, ps++) {
1.7 millert 350: c = *ps;
1.17 nicm 351: if (uppercase) {
1.30 guenther 352: if (len == 0 && islower(c))
1.7 millert 353: return (-1);
1.30 guenther 354: c = tolower(c);
1.7 millert 355: }
356: sc = *s;
1.30 guenther 357: if (len > 0)
1.17 nicm 358: sc = tolower(sc);
1.7 millert 359: if (c != sc)
360: break;
361: len++;
362: }
363: return (len);
364: }
365:
366: /*
1.1 etheisen 367: * Exit the program.
368: */
1.17 nicm 369: void
370: quit(int status)
1.1 etheisen 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: if (status < 0)
379: status = save_status;
380: else
381: save_status = status;
382: quitting = 1;
1.17 nicm 383: edit(NULL);
1.22 deraadt 384: if (!secure)
385: save_cmdhist();
1.7 millert 386: if (any_display && is_tty)
1.1 etheisen 387: clear_bot();
388: deinit();
1.29 nicm 389: flush(1);
1.1 etheisen 390: raw_mode(0);
391: exit(status);
1.15 schwarze 392: }
393:
1.17 nicm 394: char *
1.15 schwarze 395: helpfile(void)
396: {
397: return (less_is_more ? HELPDIR "/more.help" : HELPDIR "/less.help");
1.1 etheisen 398: }