main.c revision 170259
160812Sps/* $FreeBSD: head/contrib/less/main.c 170259 2007-06-04 01:43:11Z delphij $ */
260786Sps/*
3170259Sdelphij * Copyright (C) 1984-2007  Mark Nudelman
460786Sps *
560786Sps * You may distribute under the terms of either the GNU General Public
660786Sps * License or the Less License, as specified in the README file.
760786Sps *
860786Sps * For more information about less, or for information on how to
960786Sps * contact the author, see the README file.
1060786Sps */
1160786Sps
1260786Sps
1360786Sps/*
1460786Sps * Entry point, initialization, miscellaneous routines.
1560786Sps */
1660786Sps
1760786Sps#include "less.h"
1889022Sps#if MSDOS_COMPILER==WIN32C
1989022Sps#include <windows.h>
2089022Sps#endif
2160786Sps
2260786Spspublic char *	every_first_cmd = NULL;
2360786Spspublic int	new_file;
2460786Spspublic int	is_tty;
2560786Spspublic IFILE	curr_ifile = NULL_IFILE;
2660786Spspublic IFILE	old_ifile = NULL_IFILE;
2760786Spspublic struct scrpos initial_scrpos;
2860786Spspublic int	any_display = FALSE;
2960786Spspublic POSITION	start_attnpos = NULL_POSITION;
3060786Spspublic POSITION	end_attnpos = NULL_POSITION;
3160786Spspublic int	wscroll;
3260786Spspublic char *	progname;
3360786Spspublic int	quitting;
3460786Spspublic int	secure;
3560786Spspublic int	dohelp;
36170259Sdelphijpublic int	less_is_more;
3760786Sps
3860786Sps#if LOGFILE
3960786Spspublic int	logfile = -1;
4060786Spspublic int	force_logfile = FALSE;
4160786Spspublic char *	namelogfile = NULL;
4260786Sps#endif
4360786Sps
4460786Sps#if EDITOR
4560786Spspublic char *	editor;
4660786Spspublic char *	editproto;
4760786Sps#endif
4860786Sps
4960786Sps#if TAGS
5089022Spsextern char *	tags;
5160786Spsextern char *	tagoption;
5260786Spsextern int	jump_sline;
5360786Sps#endif
5460786Sps
5589022Sps#ifdef WIN32
5689022Spsstatic char consoleTitle[256];
5789022Sps#endif
5889022Sps
5960786Spsextern int	missing_cap;
6060786Spsextern int	know_dumb;
61170259Sdelphijextern int	quit_if_one_screen;
62170259Sdelphijextern int	pr_type;
6360786Sps
6460786Sps
6560786Sps/*
6660786Sps * Entry point.
6760786Sps */
6860786Spsint
6960786Spsmain(argc, argv)
7060786Sps	int argc;
7160786Sps	char *argv[];
7260786Sps{
7360786Sps	IFILE ifile;
7460786Sps	char *s;
7560812Sps	extern char *__progname;
7660786Sps
7760786Sps#ifdef __EMX__
7860786Sps	_response(&argc, &argv);
7960786Sps	_wildcard(&argc, &argv);
8060786Sps#endif
8160786Sps
8260786Sps	progname = *argv++;
8360786Sps	argc--;
8460786Sps
8560786Sps	secure = 0;
8660786Sps	s = lgetenv("LESSSECURE");
8760786Sps	if (s != NULL && *s != '\0')
8860786Sps		secure = 1;
8960786Sps
9060786Sps#ifdef WIN32
9160786Sps	if (getenv("HOME") == NULL)
9260786Sps	{
9360786Sps		/*
9460786Sps		 * If there is no HOME environment variable,
9560786Sps		 * try the concatenation of HOMEDRIVE + HOMEPATH.
9660786Sps		 */
9760786Sps		char *drive = getenv("HOMEDRIVE");
9860786Sps		char *path  = getenv("HOMEPATH");
9960786Sps		if (drive != NULL && path != NULL)
10060786Sps		{
10160786Sps			char *env = (char *) ecalloc(strlen(drive) +
10260786Sps					strlen(path) + 6, sizeof(char));
10360786Sps			strcpy(env, "HOME=");
10460786Sps			strcat(env, drive);
10560786Sps			strcat(env, path);
10660786Sps			putenv(env);
10760786Sps		}
10860786Sps	}
10989022Sps	GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char));
11060786Sps#endif /* WIN32 */
11160786Sps
11260786Sps	/*
11360786Sps	 * Process command line arguments and LESS environment arguments.
11460786Sps	 * Command line arguments override environment arguments.
11560786Sps	 */
11660786Sps	is_tty = isatty(1);
11760786Sps	get_term();
11860786Sps	init_cmds();
11960786Sps	init_charset();
12060786Sps	init_line();
121161478Sdelphij	init_cmdhist();
12260786Sps	init_option();
123170259Sdelphij
124170259Sdelphij	/*
125170259Sdelphij	 * If the name of the executable program is "more",
126170259Sdelphij	 * act like LESS_IS_MORE is set.
127170259Sdelphij	 */
128170259Sdelphij	for (s = progname + strlen(progname);  s > progname;  s--)
129170259Sdelphij	{
130170259Sdelphij		if (s[-1] == PATHNAME_SEP[0])
131170259Sdelphij			break;
13260812Sps	}
133170259Sdelphij	if (strcmp(s, "more") == 0)
134170259Sdelphij		less_is_more = 1;
135170259Sdelphij
136170259Sdelphij	init_prompt();
137170259Sdelphij
138170259Sdelphij	s = lgetenv(less_is_more ? "MORE" : "LESS");
13960786Sps	if (s != NULL)
14060786Sps		scan_option(save(s));
14160786Sps
14260786Sps#define	isoptstring(s)	(((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
14360786Sps	while (argc > 0 && (isoptstring(*argv) || isoptpending()))
14460786Sps	{
14560786Sps		s = *argv++;
14660786Sps		argc--;
14760786Sps		if (strcmp(s, "--") == 0)
14860786Sps			break;
14960786Sps		scan_option(s);
15060786Sps	}
15160786Sps#undef isoptstring
15260786Sps
15360786Sps	if (isoptpending())
15460786Sps	{
15560786Sps		/*
15660786Sps		 * Last command line option was a flag requiring a
15760786Sps		 * following string, but there was no following string.
15860786Sps		 */
15960786Sps		nopendopt();
16060786Sps		quit(QUIT_OK);
16160786Sps	}
16260786Sps
163170259Sdelphij	if (less_is_more && get_quit_at_eof())
164170259Sdelphij		quit_if_one_screen = TRUE;
165170259Sdelphij
16660786Sps#if EDITOR
16760786Sps	editor = lgetenv("VISUAL");
16860786Sps	if (editor == NULL || *editor == '\0')
16960786Sps	{
17060786Sps		editor = lgetenv("EDITOR");
17160786Sps		if (editor == NULL || *editor == '\0')
17260786Sps			editor = EDIT_PGM;
17360786Sps	}
17460786Sps	editproto = lgetenv("LESSEDIT");
17560786Sps	if (editproto == NULL || *editproto == '\0')
17660786Sps		editproto = "%E ?lm+%lm. %f";
17760786Sps#endif
17860786Sps
17960786Sps	/*
18060786Sps	 * Call get_ifile with all the command line filenames
18160786Sps	 * to "register" them with the ifile system.
18260786Sps	 */
18360786Sps	ifile = NULL_IFILE;
18460786Sps	if (dohelp)
18560786Sps		ifile = get_ifile(FAKE_HELPFILE, ifile);
18660786Sps	while (argc-- > 0)
18760786Sps	{
188128348Stjr		char *filename;
18989022Sps#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC)
19060786Sps		/*
19160786Sps		 * Because the "shell" doesn't expand filename patterns,
19260786Sps		 * treat each argument as a filename pattern rather than
19360786Sps		 * a single filename.
19460786Sps		 * Expand the pattern and iterate over the expanded list.
19560786Sps		 */
19660786Sps		struct textlist tlist;
19760786Sps		char *gfilename;
19860786Sps
19960786Sps		gfilename = lglob(*argv++);
20060786Sps		init_textlist(&tlist, gfilename);
20160786Sps		filename = NULL;
20260786Sps		while ((filename = forw_textlist(&tlist, filename)) != NULL)
203128348Stjr		{
204128348Stjr			(void) get_ifile(filename, ifile);
205128348Stjr			ifile = prev_ifile(NULL_IFILE);
206128348Stjr		}
20760786Sps		free(gfilename);
20860786Sps#else
209128348Stjr		filename = shell_quote(*argv);
210128348Stjr		if (filename == NULL)
211128348Stjr			filename = *argv;
212128348Stjr		argv++;
213128348Stjr		(void) get_ifile(filename, ifile);
214128348Stjr		ifile = prev_ifile(NULL_IFILE);
21560786Sps#endif
21660786Sps	}
21760786Sps	/*
21860786Sps	 * Set up terminal, etc.
21960786Sps	 */
22060786Sps	if (!is_tty)
22160786Sps	{
22260786Sps		/*
22360786Sps		 * Output is not a tty.
22460786Sps		 * Just copy the input file(s) to output.
22560786Sps		 */
22660786Sps		SET_BINARY(1);
22760786Sps		if (nifile() == 0)
22860786Sps		{
22960786Sps			if (edit_stdin() == 0)
23060786Sps				cat_file();
23160786Sps		} else if (edit_first() == 0)
23260786Sps		{
23360786Sps			do {
23460786Sps				cat_file();
23560786Sps			} while (edit_next(1) == 0);
23660786Sps		}
23760786Sps		quit(QUIT_OK);
23860786Sps	}
23960786Sps
240170259Sdelphij	if (missing_cap && !know_dumb)
24160786Sps		error("WARNING: terminal is not fully functional", NULL_PARG);
24260786Sps	init_mark();
243128348Stjr	open_getchr();
24460786Sps	raw_mode(1);
24560786Sps	init_signals(1);
24660786Sps
24760786Sps	/*
24860786Sps	 * Select the first file to examine.
24960786Sps	 */
25060786Sps#if TAGS
25189022Sps	if (tagoption != NULL || strcmp(tags, "-") == 0)
25260786Sps	{
25360786Sps		/*
25460786Sps		 * A -t option was given.
25560786Sps		 * Verify that no filenames were also given.
25660786Sps		 * Edit the file selected by the "tags" search,
25760786Sps		 * and search for the proper line in the file.
25860786Sps		 */
25960786Sps		if (nifile() > 0)
26060786Sps		{
26160786Sps			error("No filenames allowed with -t option", NULL_PARG);
26260786Sps			quit(QUIT_ERROR);
26360786Sps		}
26460786Sps		findtag(tagoption);
26560786Sps		if (edit_tagfile())  /* Edit file which contains the tag */
26660786Sps			quit(QUIT_ERROR);
26760786Sps		/*
26860786Sps		 * Search for the line which contains the tag.
26960786Sps		 * Set up initial_scrpos so we display that line.
27060786Sps		 */
27160786Sps		initial_scrpos.pos = tagsearch();
27260786Sps		if (initial_scrpos.pos == NULL_POSITION)
27360786Sps			quit(QUIT_ERROR);
27460786Sps		initial_scrpos.ln = jump_sline;
27560786Sps	} else
27660786Sps#endif
27760786Sps	if (nifile() == 0)
27860786Sps	{
27960786Sps		if (edit_stdin())  /* Edit standard input */
28060786Sps			quit(QUIT_ERROR);
28160786Sps	} else
28260786Sps	{
28360786Sps		if (edit_first())  /* Edit first valid file in cmd line */
28460786Sps			quit(QUIT_ERROR);
28560786Sps	}
28660786Sps
28760786Sps	init();
28860786Sps	commands();
28960786Sps	quit(QUIT_OK);
29060786Sps	/*NOTREACHED*/
291128348Stjr	return (0);
29260786Sps}
29360786Sps
29460786Sps/*
29560786Sps * Copy a string to a "safe" place
29660786Sps * (that is, to a buffer allocated by calloc).
29760786Sps */
29860786Sps	public char *
29960786Spssave(s)
30060786Sps	char *s;
30160786Sps{
30260786Sps	register char *p;
30360786Sps
30460786Sps	p = (char *) ecalloc(strlen(s)+1, sizeof(char));
30560786Sps	strcpy(p, s);
30660786Sps	return (p);
30760786Sps}
30860786Sps
30960786Sps/*
31060786Sps * Allocate memory.
31160786Sps * Like calloc(), but never returns an error (NULL).
31260786Sps */
31360786Sps	public VOID_POINTER
31460786Spsecalloc(count, size)
31560786Sps	int count;
31660786Sps	unsigned int size;
31760786Sps{
31860786Sps	register VOID_POINTER p;
31960786Sps
32060786Sps	p = (VOID_POINTER) calloc(count, size);
32160786Sps	if (p != NULL)
32260786Sps		return (p);
32360786Sps	error("Cannot allocate memory", NULL_PARG);
32460786Sps	quit(QUIT_ERROR);
32560786Sps	/*NOTREACHED*/
326128348Stjr	return (NULL);
32760786Sps}
32860786Sps
32960786Sps/*
33060786Sps * Skip leading spaces in a string.
33160786Sps */
33260786Sps	public char *
33360786Spsskipsp(s)
33460786Sps	register char *s;
33560786Sps{
33660786Sps	while (*s == ' ' || *s == '\t')
33760786Sps		s++;
33860786Sps	return (s);
33960786Sps}
34060786Sps
34160786Sps/*
34260786Sps * See how many characters of two strings are identical.
34360786Sps * If uppercase is true, the first string must begin with an uppercase
34460786Sps * character; the remainder of the first string may be either case.
34560786Sps */
34660786Sps	public int
34760786Spssprefix(ps, s, uppercase)
34860786Sps	char *ps;
34960786Sps	char *s;
35060786Sps	int uppercase;
35160786Sps{
35260786Sps	register int c;
35360786Sps	register int sc;
35460786Sps	register int len = 0;
35560786Sps
35660786Sps	for ( ;  *s != '\0';  s++, ps++)
35760786Sps	{
35860786Sps		c = *ps;
35960786Sps		if (uppercase)
36060786Sps		{
361161478Sdelphij			if (len == 0 && ASCII_IS_LOWER(c))
36260786Sps				return (-1);
363161478Sdelphij			if (ASCII_IS_UPPER(c))
364161478Sdelphij				c = ASCII_TO_LOWER(c);
36560786Sps		}
36660786Sps		sc = *s;
367161478Sdelphij		if (len > 0 && ASCII_IS_UPPER(sc))
368161478Sdelphij			sc = ASCII_TO_LOWER(sc);
36960786Sps		if (c != sc)
37060786Sps			break;
37160786Sps		len++;
37260786Sps	}
37360786Sps	return (len);
37460786Sps}
37560786Sps
37660786Sps/*
37760786Sps * Exit the program.
37860786Sps */
37960786Sps	public void
38060786Spsquit(status)
38160786Sps	int status;
38260786Sps{
38360786Sps	static int save_status;
38460786Sps
38560786Sps	/*
38660786Sps	 * Put cursor at bottom left corner, clear the line,
38760786Sps	 * reset the terminal modes, and exit.
38860786Sps	 */
38960786Sps	if (status < 0)
39060786Sps		status = save_status;
39160786Sps	else
39260786Sps		save_status = status;
39360786Sps	quitting = 1;
39460786Sps	edit((char*)NULL);
395161478Sdelphij	save_cmdhist();
39660786Sps	if (any_display && is_tty)
39760786Sps		clear_bot();
39860786Sps	deinit();
39960786Sps	flush();
40060786Sps	raw_mode(0);
40160786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
40260786Sps	/*
40360786Sps	 * If we don't close 2, we get some garbage from
40460786Sps	 * 2's buffer when it flushes automatically.
40560786Sps	 * I cannot track this one down  RB
40660786Sps	 * The same bug shows up if we use ^C^C to abort.
40760786Sps	 */
40860786Sps	close(2);
40960786Sps#endif
41089022Sps#if WIN32
41189022Sps	SetConsoleTitle(consoleTitle);
41289022Sps#endif
41360786Sps	close_getchr();
41460786Sps	exit(status);
41560786Sps}
416