Annotation of src/usr.bin/less/main.c, Revision 1.27
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) {
92: if (pledge("stdio rpath wpath tty", NULL) == -1)
1.27 ! deraadt 93: perror("pledge");
1.23 deraadt 94: } else {
95: if (pledge("stdio rpath wpath cpath fattr proc exec tty", NULL) == -1)
1.27 ! deraadt 96: perror("pledge");
1.23 deraadt 97: }
98:
1.1 etheisen 99: /*
100: * Process command line arguments and LESS environment arguments.
101: * Command line arguments override environment arguments.
102: */
1.7 millert 103: is_tty = isatty(1);
1.1 etheisen 104: get_term();
105: init_cmds();
106: init_charset();
1.7 millert 107: init_line();
1.11 shadchin 108: init_cmdhist();
1.1 etheisen 109: init_option();
1.11 shadchin 110: init_search();
111:
112:
113: init_prompt();
114:
115: s = lgetenv(less_is_more ? "MORE" : "LESS");
1.7 millert 116: if (s != NULL)
1.20 tedu 117: scan_option(estrdup(s));
1.1 etheisen 118:
1.17 nicm 119: if (less_is_more) {
120: /* this is specified by XPG */
121: quit_at_eof = OPT_ON;
122:
123: /* more users don't like the warning */
124: know_dumb = OPT_ON;
125:
126: /* default prompt is medium */
127: pr_type = OPT_ON;
128:
129: /* do not hilight search terms */
130: hilite_search = OPT_OFF;
131:
132: /* do not use LESSOPEN */
133: use_lessopen = OPT_OFF;
134:
135: /* do not set init strings to terminal */
136: no_init = OPT_ON;
137:
138: /* repaint from top of screen */
139: top_scroll = OPT_OFF;
140: }
141:
1.7 millert 142: #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
1.17 nicm 143: while (argc > 0 && (isoptstring(*argv) || isoptpending())) {
1.7 millert 144: s = *argv++;
145: argc--;
146: if (strcmp(s, "--") == 0)
1.3 deraadt 147: break;
1.7 millert 148: scan_option(s);
1.3 deraadt 149: }
1.1 etheisen 150: #undef isoptstring
151:
1.17 nicm 152: if (isoptpending()) {
1.1 etheisen 153: /*
154: * Last command line option was a flag requiring a
155: * following string, but there was no following string.
156: */
157: nopendopt();
158: quit(QUIT_OK);
159: }
1.11 shadchin 160:
1.17 nicm 161: if (errmsgs) {
162: quit(QUIT_ERROR);
163: }
164: if (less_is_more && quit_at_eof == OPT_ONPLUS) {
165: extern int no_init;
166: no_init = OPT_ON;
167: }
168: if (less_is_more && pr_type == OPT_ONPLUS) {
169: extern int quiet;
170: quiet = VERY_QUIET;
171: }
172:
1.7 millert 173: editor = lgetenv("VISUAL");
1.17 nicm 174: if (editor == NULL || *editor == '\0') {
1.7 millert 175: editor = lgetenv("EDITOR");
1.1 etheisen 176: if (editor == NULL || *editor == '\0')
177: editor = EDIT_PGM;
178: }
1.7 millert 179: editproto = lgetenv("LESSEDIT");
1.1 etheisen 180: if (editproto == NULL || *editproto == '\0')
181: editproto = "%E ?lm+%lm. %f";
182:
183: /*
184: * Call get_ifile with all the command line filenames
185: * to "register" them with the ifile system.
186: */
1.25 deraadt 187: ifile = NULL;
1.11 shadchin 188: if (dohelp)
1.15 schwarze 189: ifile = get_ifile(helpfile(), ifile);
1.17 nicm 190: while (argc-- > 0) {
1.7 millert 191: char *filename;
192: filename = shell_quote(*argv);
193: if (filename == NULL)
194: filename = *argv;
195: argv++;
196: (void) get_ifile(filename, ifile);
1.25 deraadt 197: ifile = prev_ifile(NULL);
1.13 shadchin 198: free(filename);
1.1 etheisen 199: }
200: /*
201: * Set up terminal, etc.
202: */
1.17 nicm 203: if (!is_tty) {
1.1 etheisen 204: /*
205: * Output is not a tty.
206: * Just copy the input file(s) to output.
207: */
1.17 nicm 208: if (nifile() == 0) {
1.1 etheisen 209: if (edit_stdin() == 0)
210: cat_file();
1.17 nicm 211: } else if (edit_first() == 0) {
1.1 etheisen 212: do {
213: cat_file();
214: } while (edit_next(1) == 0);
215: }
216: quit(QUIT_OK);
217: }
218:
1.17 nicm 219: if (missing_cap && !know_dumb)
1.24 deraadt 220: error("WARNING: terminal is not fully functional", NULL);
1.1 etheisen 221: init_mark();
1.7 millert 222: open_getchr();
1.23 deraadt 223:
224: if (secure)
225: if (pledge("stdio rpath tty", NULL) == -1)
1.27 ! deraadt 226: perror("pledge");
1.23 deraadt 227:
1.1 etheisen 228: raw_mode(1);
229: init_signals(1);
230:
231: /*
232: * Select the first file to examine.
233: */
1.17 nicm 234: if (tagoption != NULL || strcmp(tags, "-") == 0) {
1.1 etheisen 235: /*
236: * A -t option was given.
237: * Verify that no filenames were also given.
238: * Edit the file selected by the "tags" search,
239: * and search for the proper line in the file.
240: */
1.17 nicm 241: if (nifile() > 0) {
1.24 deraadt 242: error("No filenames allowed with -t option", NULL);
1.1 etheisen 243: quit(QUIT_ERROR);
244: }
245: findtag(tagoption);
1.7 millert 246: if (edit_tagfile()) /* Edit file which contains the tag */
1.1 etheisen 247: quit(QUIT_ERROR);
248: /*
249: * Search for the line which contains the tag.
250: * Set up initial_scrpos so we display that line.
251: */
252: initial_scrpos.pos = tagsearch();
1.17 nicm 253: if (initial_scrpos.pos == -1)
1.1 etheisen 254: quit(QUIT_ERROR);
255: initial_scrpos.ln = jump_sline;
1.17 nicm 256: } else if (nifile() == 0) {
1.1 etheisen 257: if (edit_stdin()) /* Edit standard input */
258: quit(QUIT_ERROR);
1.17 nicm 259: } else {
1.1 etheisen 260: if (edit_first()) /* Edit first valid file in cmd line */
261: quit(QUIT_ERROR);
262: }
263:
264: init();
265: commands();
266: quit(QUIT_OK);
267: /*NOTREACHED*/
1.7 millert 268: return (0);
1.1 etheisen 269: }
270:
271: /*
272: * Allocate memory.
273: * Like calloc(), but never returns an error (NULL).
274: */
1.17 nicm 275: void *
276: ecalloc(int count, unsigned int size)
1.1 etheisen 277: {
1.17 nicm 278: void *p;
1.1 etheisen 279:
1.17 nicm 280: p = calloc(count, size);
1.1 etheisen 281: if (p != NULL)
282: return (p);
1.24 deraadt 283: error("Cannot allocate memory", NULL);
1.1 etheisen 284: quit(QUIT_ERROR);
285: /*NOTREACHED*/
1.7 millert 286: return (NULL);
1.1 etheisen 287: }
288:
1.17 nicm 289: char *
290: easprintf(const char *fmt, ...)
291: {
292: char *p = NULL;
293: int rv;
294: va_list ap;
295:
296: va_start(ap, fmt);
297: rv = vasprintf(&p, fmt, ap);
298: va_end(ap);
299:
300: if (p == NULL || rv < 0) {
1.24 deraadt 301: error("Cannot allocate memory", NULL);
1.17 nicm 302: quit(QUIT_ERROR);
303: /*NOTREACHED*/
304: }
305: return (p);
306: }
307:
308: char *
309: estrdup(const char *str)
310: {
1.20 tedu 311: char *n;
312:
313: n = strdup(str);
314: if (n == NULL) {
1.24 deraadt 315: error("Cannot allocate memory", NULL);
1.20 tedu 316: quit(QUIT_ERROR);
1.17 nicm 317: }
318: return (n);
319: }
320:
1.1 etheisen 321: /*
322: * Skip leading spaces in a string.
323: */
1.17 nicm 324: char *
325: skipsp(char *s)
1.1 etheisen 326: {
1.17 nicm 327: while (*s == ' ' || *s == '\t')
1.1 etheisen 328: s++;
329: return (s);
330: }
331:
332: /*
1.7 millert 333: * See how many characters of two strings are identical.
334: * If uppercase is true, the first string must begin with an uppercase
335: * character; the remainder of the first string may be either case.
336: */
1.17 nicm 337: int
338: sprefix(char *ps, char *s, int uppercase)
1.7 millert 339: {
1.17 nicm 340: int c;
341: int sc;
342: int len = 0;
1.7 millert 343:
1.17 nicm 344: for (; *s != '\0'; s++, ps++) {
1.7 millert 345: c = *ps;
1.17 nicm 346: if (uppercase) {
347: if (len == 0 && isupper(c))
1.7 millert 348: return (-1);
1.17 nicm 349: if (isupper(c))
350: c = tolower(c);
1.7 millert 351: }
352: sc = *s;
1.17 nicm 353: if (len > 0 && isupper(sc))
354: sc = tolower(sc);
1.7 millert 355: if (c != sc)
356: break;
357: len++;
358: }
359: return (len);
360: }
361:
362: /*
1.1 etheisen 363: * Exit the program.
364: */
1.17 nicm 365: void
366: quit(int status)
1.1 etheisen 367: {
368: static int save_status;
369:
370: /*
371: * Put cursor at bottom left corner, clear the line,
372: * reset the terminal modes, and exit.
373: */
374: if (status < 0)
375: status = save_status;
376: else
377: save_status = status;
378: quitting = 1;
1.17 nicm 379: edit(NULL);
1.22 deraadt 380: if (!secure)
381: save_cmdhist();
1.7 millert 382: if (any_display && is_tty)
1.1 etheisen 383: clear_bot();
384: deinit();
385: flush();
386: raw_mode(0);
387: exit(status);
1.15 schwarze 388: }
389:
1.17 nicm 390: char *
1.15 schwarze 391: helpfile(void)
392: {
393: return (less_is_more ? HELPDIR "/more.help" : HELPDIR "/less.help");
1.1 etheisen 394: }