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