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