Annotation of src/usr.bin/less/main.c, Revision 1.6
1.6 ! deraadt 1: /* $OpenBSD: main.c,v 1.5 2001/11/19 19:02:14 mpech Exp $ */
1.4 niklas 2:
1.1 etheisen 3: /*
4: * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice in the documentation and/or other materials provided with
14: * the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
17: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29:
30: /*
31: * Entry point, initialization, miscellaneous routines.
32: */
33:
34: #include "less.h"
35: #include "position.h"
36:
37: public char * every_first_cmd = NULL;
38: public int new_file;
39: public int is_tty;
40: public IFILE curr_ifile = NULL_IFILE;
41: public IFILE old_ifile = NULL_IFILE;
42: public struct scrpos initial_scrpos;
43: public int any_display = FALSE;
44: public int wscroll;
45: public char * progname;
46: public int quitting;
1.2 etheisen 47: public int more_mode = 0;
1.1 etheisen 48:
49: extern int quit_at_eof;
50: extern int cbufs;
51: extern int errmsgs;
52: extern int screen_trashed;
53: extern int force_open;
54:
55: #if LOGFILE
56: public int logfile = -1;
57: public int force_logfile = FALSE;
58: public char * namelogfile = NULL;
59: #endif
60:
61: #if EDITOR
62: public char * editor;
63: public char * editproto;
64: #endif
65:
66: #if TAGS
67: extern char * tagfile;
68: extern char * tagoption;
69: extern int jump_sline;
70: #endif
71:
72:
73:
74: /*
75: * Entry point.
76: */
77: int
78: main(argc, argv)
79: int argc;
80: char *argv[];
81: {
82: IFILE ifile;
1.2 etheisen 83: extern char *__progname;
1.1 etheisen 84:
85: #ifdef __EMX__
86: _response(&argc, &argv);
87: _wildcard(&argc, &argv);
88: #endif
89:
90: progname = *argv++;
91:
92: /*
93: * Process command line arguments and LESS environment arguments.
94: * Command line arguments override environment arguments.
95: */
1.2 etheisen 96: if (strcmp(__progname, "more") == 0)
97: more_mode = 1;
98:
1.1 etheisen 99: get_term();
100: init_cmds();
101: init_prompt();
102: init_charset();
103: init_option();
1.2 etheisen 104:
105: if (more_mode) {
106: scan_option("-E");
107: scan_option("-m");
108: scan_option("-G");
109: scan_option(getenv("MORE"));
110: } else
111: scan_option(getenv("LESS"));
1.1 etheisen 112:
113: #if GNU_OPTIONS
114: /*
115: * Special case for "less --help" and "less --version".
116: */
117: if (argc == 2)
118: {
119: if (strcmp(argv[0], "--help") == 0)
120: scan_option("-?");
121: if (strcmp(argv[0], "--version") == 0)
122: scan_option("-V");
123: }
124: #endif
125: #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
1.3 deraadt 126: while (--argc > 0 && (isoptstring(argv[0]) || isoptpending())) {
127: if (strcmp(argv[0], "--") == 0) {
128: argv++;
129: argc--;
130: break;
131: }
1.1 etheisen 132: scan_option(*argv++);
1.3 deraadt 133: }
1.1 etheisen 134: #undef isoptstring
135:
136: if (isoptpending())
137: {
138: /*
139: * Last command line option was a flag requiring a
140: * following string, but there was no following string.
141: */
142: nopendopt();
143: quit(QUIT_OK);
144: }
145:
146: #if EDITOR
147: editor = getenv("VISUAL");
148: if (editor == NULL || *editor == '\0')
149: {
150: editor = getenv("EDITOR");
151: if (editor == NULL || *editor == '\0')
152: editor = EDIT_PGM;
153: }
154: editproto = getenv("LESSEDIT");
155: if (editproto == NULL || *editproto == '\0')
156: editproto = "%E ?lm+%lm. %f";
157: #endif
158:
159: /*
160: * Call get_ifile with all the command line filenames
161: * to "register" them with the ifile system.
162: */
163: ifile = NULL_IFILE;
164: while (--argc >= 0)
165: {
166: #if MSOFTC || OS2
167: /*
168: * Because the "shell" doesn't expand filename patterns,
169: * treat each argument as a filename pattern rather than
170: * a single filename.
171: * Expand the pattern and iterate over the expanded list.
172: */
173: struct textlist tlist;
174: char *gfilename;
175: char *filename;
176:
177: gfilename = glob(*argv++);
178: init_textlist(&tlist, gfilename);
179: filename = NULL;
180: while ((filename = forw_textlist(&tlist, filename)) != NULL)
181: ifile = get_ifile(filename, ifile);
182: free(gfilename);
183: #else
184: ifile = get_ifile(*argv++, ifile);
185: #endif
186: }
187: /*
188: * Set up terminal, etc.
189: */
190: is_tty = isatty(1);
191: if (!is_tty)
192: {
193: /*
194: * Output is not a tty.
195: * Just copy the input file(s) to output.
196: */
197: if (nifile() == 0)
198: {
199: if (edit_stdin() == 0)
200: cat_file();
201: } else if (edit_first() == 0)
202: {
203: do {
204: cat_file();
205: } while (edit_next(1) == 0);
206: }
207: quit(QUIT_OK);
208: }
209:
210: init_mark();
211: raw_mode(1);
212: open_getchr();
213: init_signals(1);
214:
215: /*
216: * Select the first file to examine.
217: */
218: #if TAGS
219: if (tagoption != NULL)
220: {
221: /*
222: * A -t option was given.
223: * Verify that no filenames were also given.
224: * Edit the file selected by the "tags" search,
225: * and search for the proper line in the file.
226: */
227: if (nifile() > 0)
228: {
229: error("No filenames allowed with -t option", NULL_PARG);
230: quit(QUIT_ERROR);
231: }
232: findtag(tagoption);
233: if (tagfile == NULL)
234: quit(QUIT_ERROR);
235: if (edit(tagfile)) /* Edit file which contains the tag */
236: quit(QUIT_ERROR);
237: /*
238: * Search for the line which contains the tag.
239: * Set up initial_scrpos so we display that line.
240: */
241: initial_scrpos.pos = tagsearch();
242: if (initial_scrpos.pos == NULL_POSITION)
243: quit(QUIT_ERROR);
244: initial_scrpos.ln = jump_sline;
245: } else
246: #endif
247: if (nifile() == 0)
248: {
249: if (edit_stdin()) /* Edit standard input */
250: quit(QUIT_ERROR);
251: } else
252: {
253: if (edit_first()) /* Edit first valid file in cmd line */
254: quit(QUIT_ERROR);
255: }
256:
257: init();
258: commands();
259: quit(QUIT_OK);
260: /*NOTREACHED*/
261: }
262:
263: /*
264: * Copy a string, truncating to the specified length if necessary.
265: * Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
266: */
267: public void
268: strtcpy(to, from, len)
269: char *to;
270: char *from;
271: unsigned int len;
272: {
273: strncpy(to, from, len);
274: to[len-1] = '\0';
275: }
276:
277: /*
278: * Copy a string to a "safe" place
279: * (that is, to a buffer allocated by calloc).
280: */
281: public char *
282: save(s)
283: char *s;
284: {
1.5 mpech 285: char *p;
1.6 ! deraadt 286: size_t len;
1.1 etheisen 287:
1.6 ! deraadt 288: len = strlen(s)+1;
! 289: p = (char *) ecalloc(len, sizeof(char));
! 290: strlcpy(p, s, len);
1.1 etheisen 291: return (p);
292: }
293:
294: /*
295: * Allocate memory.
296: * Like calloc(), but never returns an error (NULL).
297: */
298: public VOID_POINTER
299: ecalloc(count, size)
300: int count;
301: unsigned int size;
302: {
1.5 mpech 303: VOID_POINTER p;
1.1 etheisen 304:
305: p = (VOID_POINTER) calloc(count, size);
306: if (p != NULL)
307: return (p);
308: error("Cannot allocate memory", NULL_PARG);
309: quit(QUIT_ERROR);
310: /*NOTREACHED*/
311: }
312:
313: /*
314: * Skip leading spaces in a string.
315: */
316: public char *
317: skipsp(s)
1.5 mpech 318: char *s;
1.1 etheisen 319: {
320: while (*s == ' ' || *s == '\t')
321: s++;
322: return (s);
323: }
324:
325: /*
326: * Exit the program.
327: */
328: public void
329: quit(status)
330: int status;
331: {
332: static int save_status;
333:
334: /*
335: * Put cursor at bottom left corner, clear the line,
336: * reset the terminal modes, and exit.
337: */
338: if (status < 0)
339: status = save_status;
340: else
341: save_status = status;
342: quitting = 1;
343: edit((char*)NULL);
1.2 etheisen 344: if (is_tty && any_display)
1.1 etheisen 345: clear_bot();
346: deinit();
347: flush();
348: raw_mode(0);
349: #if MSOFTC
350: /*
351: * If we don't close 2, we get some garbage from
352: * 2's buffer when it flushes automatically.
353: * I cannot track this one down RB
354: * The same bug shows up if we use ^C^C to abort.
355: */
356: close(2);
357: #endif
358: exit(status);
359: }