Annotation of src/usr.bin/less/main.c, Revision 1.14
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: */
9:
10:
11: /*
12: * Entry point, initialization, miscellaneous routines.
13: */
14:
15: #include "less.h"
1.7 millert 16: #if MSDOS_COMPILER==WIN32C
17: #include <windows.h>
18: #endif
1.1 etheisen 19:
20: public char * every_first_cmd = NULL;
21: public int new_file;
22: public int is_tty;
23: public IFILE curr_ifile = NULL_IFILE;
24: public IFILE old_ifile = NULL_IFILE;
25: public struct scrpos initial_scrpos;
26: public int any_display = FALSE;
1.7 millert 27: public POSITION start_attnpos = NULL_POSITION;
28: public POSITION end_attnpos = NULL_POSITION;
1.1 etheisen 29: public int wscroll;
30: public char * progname;
31: public int quitting;
1.7 millert 32: public int secure;
1.11 shadchin 33: public int dohelp;
1.1 etheisen 34:
35: #if LOGFILE
36: public int logfile = -1;
37: public int force_logfile = FALSE;
38: public char * namelogfile = NULL;
39: #endif
40:
41: #if EDITOR
42: public char * editor;
43: public char * editproto;
44: #endif
45:
46: #if TAGS
1.7 millert 47: extern char * tags;
1.1 etheisen 48: extern char * tagoption;
49: extern int jump_sline;
50: #endif
51:
1.7 millert 52: #ifdef WIN32
53: static char consoleTitle[256];
54: #endif
1.1 etheisen 55:
1.11 shadchin 56: extern int less_is_more;
1.7 millert 57: extern int missing_cap;
58: extern int know_dumb;
1.11 shadchin 59: extern int pr_type;
1.7 millert 60:
1.1 etheisen 61:
62: /*
63: * Entry point.
64: */
65: int
66: main(argc, argv)
67: int argc;
68: char *argv[];
69: {
70: IFILE ifile;
1.7 millert 71: char *s;
1.1 etheisen 72:
73: #ifdef __EMX__
74: _response(&argc, &argv);
75: _wildcard(&argc, &argv);
76: #endif
77:
78: progname = *argv++;
1.7 millert 79: argc--;
80:
81: secure = 0;
82: s = lgetenv("LESSSECURE");
83: if (s != NULL && *s != '\0')
84: secure = 1;
85:
86: #ifdef WIN32
87: if (getenv("HOME") == NULL)
88: {
89: /*
90: * If there is no HOME environment variable,
91: * try the concatenation of HOMEDRIVE + HOMEPATH.
92: */
93: char *drive = getenv("HOMEDRIVE");
94: char *path = getenv("HOMEPATH");
95: if (drive != NULL && path != NULL)
96: {
97: size_t len = strlen(drive) + strlen(path) + 6;
98: char *env = (char *) ecalloc(len, sizeof(char));
99: strlcpy(env, "HOME=", len);
100: strlcat(env, drive, len);
101: strlcat(env, path, len);
102: putenv(env);
103: }
104: }
105: GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char));
106: #endif /* WIN32 */
1.1 etheisen 107:
108: /*
109: * Process command line arguments and LESS environment arguments.
110: * Command line arguments override environment arguments.
111: */
1.7 millert 112: is_tty = isatty(1);
1.1 etheisen 113: get_term();
114: init_cmds();
115: init_charset();
1.7 millert 116: init_line();
1.11 shadchin 117: init_cmdhist();
1.1 etheisen 118: init_option();
1.11 shadchin 119: init_search();
120:
121: /*
122: * If the name of the executable program is "more",
123: * act like LESS_IS_MORE is set.
124: */
125: for (s = progname + strlen(progname); s > progname; s--)
126: {
127: if (s[-1] == PATHNAME_SEP[0])
128: break;
129: }
130: if (strcmp(s, "more") == 0)
131: less_is_more = 1;
132:
133: init_prompt();
134:
135: if (less_is_more) {
1.2 etheisen 136: scan_option("-G");
1.7 millert 137: scan_option("-L");
1.11 shadchin 138: scan_option("-X");
1.12 nicm 139: scan_option("-c");
1.11 shadchin 140: }
141:
142: s = lgetenv(less_is_more ? "MORE" : "LESS");
1.7 millert 143: if (s != NULL)
144: scan_option(save(s));
1.1 etheisen 145:
1.7 millert 146: #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
147: while (argc > 0 && (isoptstring(*argv) || isoptpending()))
1.1 etheisen 148: {
1.7 millert 149: s = *argv++;
150: argc--;
151: if (strcmp(s, "--") == 0)
1.3 deraadt 152: break;
1.7 millert 153: scan_option(s);
1.3 deraadt 154: }
1.1 etheisen 155: #undef isoptstring
156:
157: if (isoptpending())
158: {
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.1 etheisen 167: #if EDITOR
1.7 millert 168: editor = lgetenv("VISUAL");
1.1 etheisen 169: if (editor == NULL || *editor == '\0')
170: {
1.7 millert 171: editor = lgetenv("EDITOR");
1.1 etheisen 172: if (editor == NULL || *editor == '\0')
173: editor = EDIT_PGM;
174: }
1.7 millert 175: editproto = lgetenv("LESSEDIT");
1.1 etheisen 176: if (editproto == NULL || *editproto == '\0')
177: editproto = "%E ?lm+%lm. %f";
178: #endif
179:
180: /*
181: * Call get_ifile with all the command line filenames
182: * to "register" them with the ifile system.
183: */
184: ifile = NULL_IFILE;
1.11 shadchin 185: #if !SMALL
186: if (dohelp)
187: ifile = get_ifile(HELPFILE, ifile);
188: #endif /* !SMALL */
1.7 millert 189: while (argc-- > 0)
1.1 etheisen 190: {
1.7 millert 191: char *filename;
192: #if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC)
1.1 etheisen 193: /*
194: * Because the "shell" doesn't expand filename patterns,
195: * treat each argument as a filename pattern rather than
196: * a single filename.
197: * Expand the pattern and iterate over the expanded list.
198: */
199: struct textlist tlist;
200: char *gfilename;
201:
1.7 millert 202: gfilename = lglob(*argv++);
1.1 etheisen 203: init_textlist(&tlist, gfilename);
204: filename = NULL;
205: while ((filename = forw_textlist(&tlist, filename)) != NULL)
1.7 millert 206: {
207: (void) get_ifile(filename, ifile);
208: ifile = prev_ifile(NULL_IFILE);
209: }
1.1 etheisen 210: free(gfilename);
211: #else
1.7 millert 212: filename = shell_quote(*argv);
213: if (filename == NULL)
214: filename = *argv;
215: argv++;
216: (void) get_ifile(filename, ifile);
217: ifile = prev_ifile(NULL_IFILE);
1.13 shadchin 218: free(filename);
1.1 etheisen 219: #endif
220: }
221: /*
222: * Set up terminal, etc.
223: */
224: if (!is_tty)
225: {
226: /*
227: * Output is not a tty.
228: * Just copy the input file(s) to output.
229: */
1.7 millert 230: SET_BINARY(1);
1.1 etheisen 231: if (nifile() == 0)
232: {
233: if (edit_stdin() == 0)
234: cat_file();
235: } else if (edit_first() == 0)
236: {
237: do {
238: cat_file();
239: } while (edit_next(1) == 0);
240: }
241: quit(QUIT_OK);
242: }
243:
1.11 shadchin 244: if (missing_cap && !know_dumb && !less_is_more)
1.7 millert 245: error("WARNING: terminal is not fully functional", NULL_PARG);
1.1 etheisen 246: init_mark();
1.7 millert 247: open_getchr();
1.1 etheisen 248: raw_mode(1);
249: init_signals(1);
250:
251: /*
252: * Select the first file to examine.
253: */
254: #if TAGS
1.7 millert 255: if (tagoption != NULL || strcmp(tags, "-") == 0)
1.1 etheisen 256: {
257: /*
258: * A -t option was given.
259: * Verify that no filenames were also given.
260: * Edit the file selected by the "tags" search,
261: * and search for the proper line in the file.
262: */
263: if (nifile() > 0)
264: {
265: error("No filenames allowed with -t option", NULL_PARG);
266: quit(QUIT_ERROR);
267: }
268: findtag(tagoption);
1.7 millert 269: if (edit_tagfile()) /* Edit file which contains the tag */
1.1 etheisen 270: quit(QUIT_ERROR);
271: /*
272: * Search for the line which contains the tag.
273: * Set up initial_scrpos so we display that line.
274: */
275: initial_scrpos.pos = tagsearch();
276: if (initial_scrpos.pos == NULL_POSITION)
277: quit(QUIT_ERROR);
278: initial_scrpos.ln = jump_sline;
279: } else
280: #endif
281: if (nifile() == 0)
282: {
283: if (edit_stdin()) /* Edit standard input */
284: quit(QUIT_ERROR);
285: } else
286: {
287: if (edit_first()) /* Edit first valid file in cmd line */
288: quit(QUIT_ERROR);
289: }
290:
291: init();
292: commands();
293: quit(QUIT_OK);
294: /*NOTREACHED*/
1.7 millert 295: return (0);
1.1 etheisen 296: }
297:
298: /*
299: * Copy a string to a "safe" place
300: * (that is, to a buffer allocated by calloc).
301: */
302: public char *
303: save(s)
304: char *s;
305: {
1.7 millert 306: register char *p;
1.11 shadchin 307: size_t len = strlen(s) + 1;
1.1 etheisen 308:
1.6 deraadt 309: p = (char *) ecalloc(len, sizeof(char));
310: strlcpy(p, s, len);
1.1 etheisen 311: return (p);
312: }
313:
314: /*
315: * Allocate memory.
316: * Like calloc(), but never returns an error (NULL).
317: */
318: public VOID_POINTER
319: ecalloc(count, size)
320: int count;
321: unsigned int size;
322: {
1.7 millert 323: register VOID_POINTER p;
1.1 etheisen 324:
325: p = (VOID_POINTER) calloc(count, size);
326: if (p != NULL)
327: return (p);
328: error("Cannot allocate memory", NULL_PARG);
329: quit(QUIT_ERROR);
330: /*NOTREACHED*/
1.7 millert 331: return (NULL);
1.1 etheisen 332: }
333:
334: /*
335: * Skip leading spaces in a string.
336: */
337: public char *
338: skipsp(s)
1.7 millert 339: register char *s;
1.1 etheisen 340: {
341: while (*s == ' ' || *s == '\t')
342: s++;
343: return (s);
344: }
345:
1.11 shadchin 346: #if GNU_OPTIONS
1.1 etheisen 347: /*
1.7 millert 348: * See how many characters of two strings are identical.
349: * If uppercase is true, the first string must begin with an uppercase
350: * character; the remainder of the first string may be either case.
351: */
352: public int
353: sprefix(ps, s, uppercase)
354: char *ps;
355: char *s;
356: int uppercase;
357: {
358: register int c;
359: register int sc;
360: register int len = 0;
361:
362: for ( ; *s != '\0'; s++, ps++)
363: {
364: c = *ps;
365: if (uppercase)
366: {
1.11 shadchin 367: if (len == 0 && ASCII_IS_LOWER(c))
1.7 millert 368: return (-1);
1.11 shadchin 369: if (ASCII_IS_UPPER(c))
370: c = ASCII_TO_LOWER(c);
1.7 millert 371: }
372: sc = *s;
1.11 shadchin 373: if (len > 0 && ASCII_IS_UPPER(sc))
374: sc = ASCII_TO_LOWER(sc);
1.7 millert 375: if (c != sc)
376: break;
377: len++;
378: }
379: return (len);
380: }
1.11 shadchin 381: #endif /* GNU_OPTIONS */
1.7 millert 382:
383: /*
1.1 etheisen 384: * Exit the program.
385: */
386: public void
387: quit(status)
388: int status;
389: {
390: static int save_status;
391:
392: /*
393: * Put cursor at bottom left corner, clear the line,
394: * reset the terminal modes, and exit.
395: */
396: if (status < 0)
397: status = save_status;
398: else
399: save_status = status;
400: quitting = 1;
401: edit((char*)NULL);
1.11 shadchin 402: save_cmdhist();
1.7 millert 403: if (any_display && is_tty)
1.1 etheisen 404: clear_bot();
405: deinit();
406: flush();
407: raw_mode(0);
1.7 millert 408: #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
1.1 etheisen 409: /*
410: * If we don't close 2, we get some garbage from
411: * 2's buffer when it flushes automatically.
412: * I cannot track this one down RB
413: * The same bug shows up if we use ^C^C to abort.
414: */
415: close(2);
416: #endif
1.11 shadchin 417: #ifdef WIN32
1.7 millert 418: SetConsoleTitle(consoleTitle);
419: #endif
420: close_getchr();
1.1 etheisen 421: exit(status);
422: }