Annotation of src/usr.bin/less/main.c, Revision 1.28
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);
273: /*NOTREACHED*/
1.7 millert 274: return (0);
1.1 etheisen 275: }
276:
277: /*
278: * Allocate memory.
279: * Like calloc(), but never returns an error (NULL).
280: */
1.17 nicm 281: void *
282: ecalloc(int count, unsigned int size)
1.1 etheisen 283: {
1.17 nicm 284: void *p;
1.1 etheisen 285:
1.17 nicm 286: p = calloc(count, size);
1.1 etheisen 287: if (p != NULL)
288: return (p);
1.24 deraadt 289: error("Cannot allocate memory", NULL);
1.1 etheisen 290: quit(QUIT_ERROR);
291: /*NOTREACHED*/
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:
306: if (p == NULL || rv < 0) {
1.24 deraadt 307: error("Cannot allocate memory", NULL);
1.17 nicm 308: quit(QUIT_ERROR);
309: /*NOTREACHED*/
310: }
311: return (p);
312: }
313:
314: char *
315: estrdup(const char *str)
316: {
1.20 tedu 317: char *n;
318:
319: n = strdup(str);
320: if (n == NULL) {
1.24 deraadt 321: error("Cannot allocate memory", NULL);
1.20 tedu 322: quit(QUIT_ERROR);
1.17 nicm 323: }
324: return (n);
325: }
326:
1.1 etheisen 327: /*
328: * Skip leading spaces in a string.
329: */
1.17 nicm 330: char *
331: skipsp(char *s)
1.1 etheisen 332: {
1.17 nicm 333: while (*s == ' ' || *s == '\t')
1.1 etheisen 334: s++;
335: return (s);
336: }
337:
338: /*
1.7 millert 339: * See how many characters of two strings are identical.
340: * If uppercase is true, the first string must begin with an uppercase
341: * character; the remainder of the first string may be either case.
342: */
1.17 nicm 343: int
344: sprefix(char *ps, char *s, int uppercase)
1.7 millert 345: {
1.17 nicm 346: int c;
347: int sc;
348: int len = 0;
1.7 millert 349:
1.17 nicm 350: for (; *s != '\0'; s++, ps++) {
1.7 millert 351: c = *ps;
1.17 nicm 352: if (uppercase) {
353: if (len == 0 && isupper(c))
1.7 millert 354: return (-1);
1.17 nicm 355: if (isupper(c))
356: c = tolower(c);
1.7 millert 357: }
358: sc = *s;
1.17 nicm 359: if (len > 0 && isupper(sc))
360: sc = tolower(sc);
1.7 millert 361: if (c != sc)
362: break;
363: len++;
364: }
365: return (len);
366: }
367:
368: /*
1.1 etheisen 369: * Exit the program.
370: */
1.17 nicm 371: void
372: quit(int status)
1.1 etheisen 373: {
374: static int save_status;
375:
376: /*
377: * Put cursor at bottom left corner, clear the line,
378: * reset the terminal modes, and exit.
379: */
380: if (status < 0)
381: status = save_status;
382: else
383: save_status = status;
384: quitting = 1;
1.17 nicm 385: edit(NULL);
1.22 deraadt 386: if (!secure)
387: save_cmdhist();
1.7 millert 388: if (any_display && is_tty)
1.1 etheisen 389: clear_bot();
390: deinit();
391: flush();
392: raw_mode(0);
393: exit(status);
1.15 schwarze 394: }
395:
1.17 nicm 396: char *
1.15 schwarze 397: helpfile(void)
398: {
399: return (less_is_more ? HELPDIR "/more.help" : HELPDIR "/less.help");
1.1 etheisen 400: }