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