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