main.c revision 161478
11556Srgrimes/* $FreeBSD: head/contrib/less/main.c 161478 2006-08-20 15:50:51Z delphij $ */
21556Srgrimes/*
31556Srgrimes * Copyright (C) 1984-2004  Mark Nudelman
41556Srgrimes *
51556Srgrimes * You may distribute under the terms of either the GNU General Public
61556Srgrimes * License or the Less License, as specified in the README file.
71556Srgrimes *
81556Srgrimes * For more information about less, or for information on how to
91556Srgrimes * contact the author, see the README file.
101556Srgrimes */
111556Srgrimes
121556Srgrimes
131556Srgrimes/*
141556Srgrimes * Entry point, initialization, miscellaneous routines.
151556Srgrimes */
161556Srgrimes
171556Srgrimes#include "less.h"
181556Srgrimes#if MSDOS_COMPILER==WIN32C
191556Srgrimes#include <windows.h>
201556Srgrimes#endif
211556Srgrimes
221556Srgrimespublic char *	every_first_cmd = NULL;
231556Srgrimespublic int	new_file;
241556Srgrimespublic int	is_tty;
251556Srgrimespublic IFILE	curr_ifile = NULL_IFILE;
261556Srgrimespublic IFILE	old_ifile = NULL_IFILE;
271556Srgrimespublic struct scrpos initial_scrpos;
281556Srgrimespublic int	any_display = FALSE;
291556Srgrimespublic POSITION	start_attnpos = NULL_POSITION;
301556Srgrimespublic POSITION	end_attnpos = NULL_POSITION;
311556Srgrimespublic int	wscroll;
321556Srgrimespublic char *	progname;
331556Srgrimespublic int	quitting;
3420425Sstevepublic int	secure;
351556Srgrimespublic int	dohelp;
361556Srgrimespublic int	more_mode = 0;
371556Srgrimes
381556Srgrimes#if LOGFILE
391556Srgrimespublic int	logfile = -1;
4036150Scharnierpublic int	force_logfile = FALSE;
4136150Scharnierpublic char *	namelogfile = NULL;
4236150Scharnier#endif
431556Srgrimes
4499110Sobrien#if EDITOR
4599110Sobrienpublic char *	editor;
461556Srgrimespublic char *	editproto;
4717987Speter#endif
481556Srgrimes
4917987Speter#if TAGS
5017987Speterextern char *	tags;
511556Srgrimesextern char *	tagoption;
5217525Sacheextern int	jump_sline;
5359214Simp#endif
5417525Sache
551556Srgrimes#ifdef WIN32
561556Srgrimesstatic char consoleTitle[256];
571556Srgrimes#endif
581556Srgrimes
591556Srgrimesextern int	missing_cap;
601556Srgrimesextern int	know_dumb;
611556Srgrimes
6217987Speter
631556Srgrimes/*
641556Srgrimes * Entry point.
651556Srgrimes */
661556Srgrimesint
671556Srgrimesmain(argc, argv)
6817987Speter	int argc;
691556Srgrimes	char *argv[];
701556Srgrimes{
711556Srgrimes	IFILE ifile;
721556Srgrimes	char *s;
7317987Speter	extern char *__progname;
7420425Ssteve
751556Srgrimes#ifdef __EMX__
761556Srgrimes	_response(&argc, &argv);
771556Srgrimes	_wildcard(&argc, &argv);
78200998Sjilles#endif
79221669Sjilles
801556Srgrimes	progname = *argv++;
81213811Sobrien	argc--;
82213811Sobrien
831556Srgrimes	secure = 0;
841556Srgrimes	s = lgetenv("LESSSECURE");
851556Srgrimes	if (s != NULL && *s != '\0')
861556Srgrimes		secure = 1;
871556Srgrimes
881556Srgrimes#ifdef WIN32
891556Srgrimes	if (getenv("HOME") == NULL)
901556Srgrimes	{
911556Srgrimes		/*
9217987Speter		 * If there is no HOME environment variable,
9390111Simp		 * try the concatenation of HOMEDRIVE + HOMEPATH.
9417987Speter		 */
951556Srgrimes		char *drive = getenv("HOMEDRIVE");
961556Srgrimes		char *path  = getenv("HOMEPATH");
971556Srgrimes		if (drive != NULL && path != NULL)
981556Srgrimes		{
9917525Sache			char *env = (char *) ecalloc(strlen(drive) +
100221669Sjilles					strlen(path) + 6, sizeof(char));
1011556Srgrimes			strcpy(env, "HOME=");
102200998Sjilles			strcat(env, drive);
10320425Ssteve			strcat(env, path);
10420425Ssteve			putenv(env);
10520425Ssteve		}
10620425Ssteve	}
10720425Ssteve	GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char));
10820425Ssteve#endif /* WIN32 */
10920425Ssteve
11020425Ssteve	/*
11120425Ssteve	 * Process command line arguments and LESS environment arguments.
11220425Ssteve	 * Command line arguments override environment arguments.
11320425Ssteve	 */
11420425Ssteve	if (strcmp(__progname, "more") == 0)
11520425Ssteve		more_mode = 1;
116220978Sjilles
117220978Sjilles	is_tty = isatty(1);
118218306Sjilles	get_term();
1191556Srgrimes	init_cmds();
120215567Sjilles	init_prompt();
121215567Sjilles	init_charset();
1221556Srgrimes	init_line();
1231556Srgrimes	init_cmdhist();
1241556Srgrimes	init_option();
1251556Srgrimes
1261556Srgrimes	if (more_mode) {
1271556Srgrimes		scan_option("-E");
1281556Srgrimes		scan_option("-m");
1291556Srgrimes		scan_option("-G");
1301556Srgrimes		scan_option("-f");
1311556Srgrimes		s = lgetenv("MORE");
1321556Srgrimes	} else {
133200998Sjilles		s = lgetenv("LESS");
1341556Srgrimes	}
1351556Srgrimes	if (s != NULL)
1361556Srgrimes		scan_option(save(s));
1371556Srgrimes
1381556Srgrimes#define	isoptstring(s)	(((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
1391556Srgrimes	while (argc > 0 && (isoptstring(*argv) || isoptpending()))
1401556Srgrimes	{
1411556Srgrimes		s = *argv++;
1421556Srgrimes		argc--;
143206759Sjilles		if (strcmp(s, "--") == 0)
144203576Sjilles			break;
145203576Sjilles		scan_option(s);
1461556Srgrimes	}
1471556Srgrimes#undef isoptstring
1481556Srgrimes
1491556Srgrimes	if (isoptpending())
1501556Srgrimes	{
15119240Ssteve		/*
15219240Ssteve		 * Last command line option was a flag requiring a
15319240Ssteve		 * following string, but there was no following string.
15419240Ssteve		 */
1558855Srgrimes		nopendopt();
1561556Srgrimes		quit(QUIT_OK);
1571556Srgrimes	}
15825471Ssteve
15917987Speter#if EDITOR
16017987Speter	editor = lgetenv("VISUAL");
16117987Speter	if (editor == NULL || *editor == '\0')
16217987Speter	{
1631556Srgrimes		editor = lgetenv("EDITOR");
1641556Srgrimes		if (editor == NULL || *editor == '\0')
1651556Srgrimes			editor = EDIT_PGM;
1661556Srgrimes	}
167194128Sjilles	editproto = lgetenv("LESSEDIT");
1681556Srgrimes	if (editproto == NULL || *editproto == '\0')
1691556Srgrimes		editproto = "%E ?lm+%lm. %f";
1701556Srgrimes#endif
1711556Srgrimes
1721556Srgrimes	/*
1731556Srgrimes	 * Call get_ifile with all the command line filenames
17417987Speter	 * to "register" them with the ifile system.
17517987Speter	 */
1761556Srgrimes	ifile = NULL_IFILE;
1771556Srgrimes	if (dohelp)
1781556Srgrimes		ifile = get_ifile(FAKE_HELPFILE, ifile);
1791556Srgrimes	while (argc-- > 0)
1801556Srgrimes	{
1811556Srgrimes		char *filename;
1821556Srgrimes#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC)
1831556Srgrimes		/*
1841556Srgrimes		 * Because the "shell" doesn't expand filename patterns,
18590111Simp		 * treat each argument as a filename pattern rather than
18617987Speter		 * a single filename.
1871556Srgrimes		 * Expand the pattern and iterate over the expanded list.
1881556Srgrimes		 */
1891556Srgrimes		struct textlist tlist;
1901556Srgrimes		char *gfilename;
1911556Srgrimes
1921556Srgrimes		gfilename = lglob(*argv++);
1931556Srgrimes		init_textlist(&tlist, gfilename);
1941556Srgrimes		filename = NULL;
1951556Srgrimes		while ((filename = forw_textlist(&tlist, filename)) != NULL)
1961556Srgrimes		{
1971556Srgrimes			(void) get_ifile(filename, ifile);
1981556Srgrimes			ifile = prev_ifile(NULL_IFILE);
1991556Srgrimes		}
200163085Sstefanf		free(gfilename);
2011556Srgrimes#else
2021556Srgrimes		filename = shell_quote(*argv);
2031556Srgrimes		if (filename == NULL)
2041556Srgrimes			filename = *argv;
2051556Srgrimes		argv++;
2061556Srgrimes		(void) get_ifile(filename, ifile);
2071556Srgrimes		ifile = prev_ifile(NULL_IFILE);
2081556Srgrimes#endif
2091556Srgrimes	}
2101556Srgrimes	/*
2111556Srgrimes	 * Set up terminal, etc.
212199629Sjilles	 */
2131556Srgrimes	if (!is_tty)
2141556Srgrimes	{
2151556Srgrimes		/*
2161556Srgrimes		 * Output is not a tty.
2171556Srgrimes		 * Just copy the input file(s) to output.
2181556Srgrimes		 */
2191556Srgrimes		SET_BINARY(1);
2201556Srgrimes		if (nifile() == 0)
22164702Scracauer		{
222211349Sjilles			if (edit_stdin() == 0)
223211349Sjilles				cat_file();
224211349Sjilles		} else if (edit_first() == 0)
22520425Ssteve		{
22620425Ssteve			do {
2271556Srgrimes				cat_file();
22864702Scracauer			} while (edit_next(1) == 0);
2291556Srgrimes		}
2301556Srgrimes		quit(QUIT_OK);
2311556Srgrimes	}
2321556Srgrimes
2331556Srgrimes	if (missing_cap && !know_dumb && !more_mode)
2341556Srgrimes		error("WARNING: terminal is not fully functional", NULL_PARG);
2351556Srgrimes	init_mark();
2361556Srgrimes	open_getchr();
237213811Sobrien	raw_mode(1);
238201053Sjilles	init_signals(1);
23990111Simp
2401556Srgrimes	/*
2411556Srgrimes	 * Select the first file to examine.
2421556Srgrimes	 */
2431556Srgrimes#if TAGS
2441556Srgrimes	if (tagoption != NULL || strcmp(tags, "-") == 0)
2451556Srgrimes	{
2461556Srgrimes		/*
2471556Srgrimes		 * A -t option was given.
2481556Srgrimes		 * Verify that no filenames were also given.
2491556Srgrimes		 * Edit the file selected by the "tags" search,
2501556Srgrimes		 * and search for the proper line in the file.
2511556Srgrimes		 */
2521556Srgrimes		if (nifile() > 0)
2531556Srgrimes		{
2541556Srgrimes			error("No filenames allowed with -t option", NULL_PARG);
2551556Srgrimes			quit(QUIT_ERROR);
2561556Srgrimes		}
2571556Srgrimes		findtag(tagoption);
2581556Srgrimes		if (edit_tagfile())  /* Edit file which contains the tag */
259200956Sjilles			quit(QUIT_ERROR);
26017987Speter		/*
2611556Srgrimes		 * Search for the line which contains the tag.
2621556Srgrimes		 * Set up initial_scrpos so we display that line.
2631556Srgrimes		 */
2641556Srgrimes		initial_scrpos.pos = tagsearch();
2651556Srgrimes		if (initial_scrpos.pos == NULL_POSITION)
2661556Srgrimes			quit(QUIT_ERROR);
26753891Scracauer		initial_scrpos.ln = jump_sline;
2681556Srgrimes	} else
2691556Srgrimes#endif
2701556Srgrimes	if (nifile() == 0)
2711556Srgrimes	{
2721556Srgrimes		if (edit_stdin())  /* Edit standard input */
2731556Srgrimes			quit(QUIT_ERROR);
2741556Srgrimes	} else
2751556Srgrimes	{
27646684Skris		if (edit_first())  /* Edit first valid file in cmd line */
27717987Speter			quit(QUIT_ERROR);
2781556Srgrimes	}
2791556Srgrimes
28017987Speter	init();
281213811Sobrien	commands();
28290111Simp	quit(QUIT_OK);
28317987Speter	/*NOTREACHED*/
28417987Speter	return (0);
285200956Sjilles}
28617987Speter
28717987Speter/*
28817987Speter * Copy a string to a "safe" place
28917987Speter * (that is, to a buffer allocated by calloc).
29017987Speter */
29117987Speter	public char *
29217987Spetersave(s)
293222173Sjilles	char *s;
294222173Sjilles{
295222173Sjilles	register char *p;
296222173Sjilles
297222173Sjilles	p = (char *) ecalloc(strlen(s)+1, sizeof(char));
298222173Sjilles	strcpy(p, s);
299222173Sjilles	return (p);
30017987Speter}
30117987Speter
30217987Speter/*
30317987Speter * Allocate memory.
30417987Speter * Like calloc(), but never returns an error (NULL).
30517987Speter */
30690111Simp	public VOID_POINTER
30717987Speterecalloc(count, size)
308208630Sjilles	int count;
309157414Sstefanf	unsigned int size;
310157414Sstefanf{
311157414Sstefanf	register VOID_POINTER p;
312157414Sstefanf
3131556Srgrimes	p = (VOID_POINTER) calloc(count, size);
31417987Speter	if (p != NULL)
315208630Sjilles		return (p);
316208630Sjilles	error("Cannot allocate memory", NULL_PARG);
317208630Sjilles	quit(QUIT_ERROR);
318208630Sjilles	/*NOTREACHED*/
319208630Sjilles	return (NULL);
320208630Sjilles}
321208630Sjilles
322157414Sstefanf/*
323157414Sstefanf * Skip leading spaces in a string.
324157414Sstefanf */
325157414Sstefanf	public char *
3261556Srgrimesskipsp(s)
3271556Srgrimes	register char *s;
3281556Srgrimes{
3291556Srgrimes	while (*s == ' ' || *s == '\t')
33017987Speter		s++;
33190111Simp	return (s);
33217987Speter}
3331556Srgrimes
33417987Speter/*
33520425Ssteve * See how many characters of two strings are identical.
336217175Sjilles * If uppercase is true, the first string must begin with an uppercase
33720425Ssteve * character; the remainder of the first string may be either case.
338217175Sjilles */
3391556Srgrimes	public int
340sprefix(ps, s, uppercase)
341	char *ps;
342	char *s;
343	int uppercase;
344{
345	register int c;
346	register int sc;
347	register int len = 0;
348
349	for ( ;  *s != '\0';  s++, ps++)
350	{
351		c = *ps;
352		if (uppercase)
353		{
354			if (len == 0 && ASCII_IS_LOWER(c))
355				return (-1);
356			if (ASCII_IS_UPPER(c))
357				c = ASCII_TO_LOWER(c);
358		}
359		sc = *s;
360		if (len > 0 && ASCII_IS_UPPER(sc))
361			sc = ASCII_TO_LOWER(sc);
362		if (c != sc)
363			break;
364		len++;
365	}
366	return (len);
367}
368
369/*
370 * Exit the program.
371 */
372	public void
373quit(status)
374	int status;
375{
376	static int save_status;
377
378	/*
379	 * Put cursor at bottom left corner, clear the line,
380	 * reset the terminal modes, and exit.
381	 */
382	if (status < 0)
383		status = save_status;
384	else
385		save_status = status;
386	quitting = 1;
387	edit((char*)NULL);
388	save_cmdhist();
389	if (any_display && is_tty)
390		clear_bot();
391	deinit();
392	flush();
393	raw_mode(0);
394#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
395	/*
396	 * If we don't close 2, we get some garbage from
397	 * 2's buffer when it flushes automatically.
398	 * I cannot track this one down  RB
399	 * The same bug shows up if we use ^C^C to abort.
400	 */
401	close(2);
402#endif
403#if WIN32
404	SetConsoleTitle(consoleTitle);
405#endif
406	close_getchr();
407	exit(status);
408}
409