main.c revision 128348
11541Srgrimes/* $FreeBSD: head/contrib/less/main.c 128348 2004-04-17 07:24:09Z tjr $ */
21541Srgrimes/*
31541Srgrimes * Copyright (C) 1984-2002  Mark Nudelman
41541Srgrimes *
51541Srgrimes * You may distribute under the terms of either the GNU General Public
61541Srgrimes * License or the Less License, as specified in the README file.
71541Srgrimes *
81541Srgrimes * For more information about less, or for information on how to
91541Srgrimes * contact the author, see the README file.
101541Srgrimes */
111541Srgrimes
121541Srgrimes
131541Srgrimes/*
141541Srgrimes * Entry point, initialization, miscellaneous routines.
151541Srgrimes */
161541Srgrimes
171541Srgrimes#include "less.h"
181541Srgrimes#if MSDOS_COMPILER==WIN32C
191541Srgrimes#include <windows.h>
201541Srgrimes#endif
211541Srgrimes
221541Srgrimespublic char *	every_first_cmd = NULL;
231541Srgrimespublic int	new_file;
241541Srgrimespublic int	is_tty;
251541Srgrimespublic IFILE	curr_ifile = NULL_IFILE;
261541Srgrimespublic IFILE	old_ifile = NULL_IFILE;
271541Srgrimespublic struct scrpos initial_scrpos;
281541Srgrimespublic int	any_display = FALSE;
291541Srgrimespublic POSITION	start_attnpos = NULL_POSITION;
301541Srgrimespublic POSITION	end_attnpos = NULL_POSITION;
311541Srgrimespublic int	wscroll;
321541Srgrimespublic char *	progname;
331541Srgrimespublic int	quitting;
3419622Sfennerpublic int	secure;
3518797Swollmanpublic int	dohelp;
361541Srgrimespublic int	more_mode = 0;
371541Srgrimes
3818797Swollman#if LOGFILE
3918797Swollmanpublic int	logfile = -1;
4016333Sgpalmerpublic int	force_logfile = FALSE;
4116333Sgpalmerpublic char *	namelogfile = NULL;
4219622Sfenner#endif
4319622Sfenner
441541Srgrimes#if EDITOR
451541Srgrimespublic char *	editor;
461541Srgrimespublic char *	editproto;
471541Srgrimes#endif
481541Srgrimes
491541Srgrimes#if TAGS
501541Srgrimesextern char *	tags;
511541Srgrimesextern char *	tagoption;
521541Srgrimesextern int	jump_sline;
531541Srgrimes#endif
547091Swollman
557090Sbde#ifdef WIN32
561541Srgrimesstatic char consoleTitle[256];
571541Srgrimes#endif
5819622Sfenner
591541Srgrimesextern int	missing_cap;
608426Swollmanextern int	know_dumb;
611541Srgrimes
621541Srgrimes
631541Srgrimes/*
647090Sbde * Entry point.
651541Srgrimes */
661541Srgrimesint
671541Srgrimesmain(argc, argv)
681541Srgrimes	int argc;
691541Srgrimes	char *argv[];
7018797Swollman{
711541Srgrimes	IFILE ifile;
722531Swollman	char *s;
7315680Sgpalmer	extern char *__progname;
7415680Sgpalmer
7515680Sgpalmer#ifdef __EMX__
7615680Sgpalmer	_response(&argc, &argv);
7715680Sgpalmer	_wildcard(&argc, &argv);
789209Swollman#endif
7912820Sphk
802531Swollman	progname = *argv++;
812531Swollman	argc--;
8213266Swollman
8312296Sphk	secure = 0;
8412296Sphk	s = lgetenv("LESSSECURE");
8512296Sphk	if (s != NULL && *s != '\0')
8613266Swollman		secure = 1;
8712296Sphk
8812296Sphk#ifdef WIN32
8912296Sphk	if (getenv("HOME") == NULL)
901541Srgrimes	{
9112296Sphk		/*
9212296Sphk		 * If there is no HOME environment variable,
9312296Sphk		 * try the concatenation of HOMEDRIVE + HOMEPATH.
9412296Sphk		 */
9512296Sphk		char *drive = getenv("HOMEDRIVE");
9612296Sphk		char *path  = getenv("HOMEPATH");
971541Srgrimes		if (drive != NULL && path != NULL)
9812296Sphk		{
991541Srgrimes			char *env = (char *) ecalloc(strlen(drive) +
1001541Srgrimes					strlen(path) + 6, sizeof(char));
1011541Srgrimes			strcpy(env, "HOME=");
1021541Srgrimes			strcat(env, drive);
1031541Srgrimes			strcat(env, path);
10412296Sphk			putenv(env);
1051541Srgrimes		}
1061541Srgrimes	}
10712296Sphk	GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char));
10812296Sphk#endif /* WIN32 */
10912296Sphk
11012296Sphk	/*
1111541Srgrimes	 * Process command line arguments and LESS environment arguments.
1122112Swollman	 * Command line arguments override environment arguments.
11312820Sphk	 */
1142112Swollman	if (strcmp(__progname, "more") == 0)
11512296Sphk		more_mode = 1;
11612296Sphk
11712296Sphk	is_tty = isatty(1);
11812296Sphk	get_term();
11912296Sphk	init_cmds();
12018797Swollman	init_prompt();
12118797Swollman	init_charset();
12218797Swollman	init_line();
12318797Swollman	init_option();
12418797Swollman
12518797Swollman	if (more_mode) {
12618797Swollman		scan_option("-E");
12718797Swollman		scan_option("-m");
12815026Sphk		scan_option("-G");
12915026Sphk		scan_option("-f");
13015026Sphk		s = lgetenv("MORE");
13114209Sphk	} else {
13217758Ssos		s = lgetenv("LESS");
13317758Ssos	}
13417758Ssos	if (s != NULL)
13518797Swollman		scan_option(save(s));
13617758Ssos
13714209Sphk#define	isoptstring(s)	(((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
1381541Srgrimes	while (argc > 0 && (isoptstring(*argv) || isoptpending()))
1391541Srgrimes	{
1401541Srgrimes		s = *argv++;
1411541Srgrimes		argc--;
1421541Srgrimes		if (strcmp(s, "--") == 0)
1431541Srgrimes			break;
14412296Sphk		scan_option(s);
1451541Srgrimes	}
1461541Srgrimes#undef isoptstring
1471541Srgrimes
1481541Srgrimes	if (isoptpending())
1491541Srgrimes	{
1501541Srgrimes		/*
1511541Srgrimes		 * Last command line option was a flag requiring a
15217072Sjulian		 * following string, but there was no following string.
15317072Sjulian		 */
15417072Sjulian		nopendopt();
15517072Sjulian		quit(QUIT_OK);
15617072Sjulian	}
15717072Sjulian
15817072Sjulian#if EDITOR
15917072Sjulian	editor = lgetenv("VISUAL");
16017072Sjulian	if (editor == NULL || *editor == '\0')
1611541Srgrimes	{
16212296Sphk		editor = lgetenv("EDITOR");
16312296Sphk		if (editor == NULL || *editor == '\0')
16412296Sphk			editor = EDIT_PGM;
16512296Sphk	}
16612296Sphk	editproto = lgetenv("LESSEDIT");
16712296Sphk	if (editproto == NULL || *editproto == '\0')
16812296Sphk		editproto = "%E ?lm+%lm. %f";
16912296Sphk#endif
17012296Sphk
17118797Swollman	/*
1721541Srgrimes	 * Call get_ifile with all the command line filenames
1731541Srgrimes	 * to "register" them with the ifile system.
1741541Srgrimes	 */
1751541Srgrimes	ifile = NULL_IFILE;
1761541Srgrimes	if (dohelp)
1771541Srgrimes		ifile = get_ifile(FAKE_HELPFILE, ifile);
1781541Srgrimes	while (argc-- > 0)
1791541Srgrimes	{
1801541Srgrimes		char *filename;
1811541Srgrimes#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC)
1821541Srgrimes		/*
1831541Srgrimes		 * Because the "shell" doesn't expand filename patterns,
1841541Srgrimes		 * treat each argument as a filename pattern rather than
1851541Srgrimes		 * a single filename.
1861541Srgrimes		 * Expand the pattern and iterate over the expanded list.
1871541Srgrimes		 */
1881541Srgrimes		struct textlist tlist;
1891541Srgrimes		char *gfilename;
1901541Srgrimes
1911541Srgrimes		gfilename = lglob(*argv++);
1921541Srgrimes		init_textlist(&tlist, gfilename);
1931541Srgrimes		filename = NULL;
1941541Srgrimes		while ((filename = forw_textlist(&tlist, filename)) != NULL)
19514230Sphk		{
19614230Sphk			(void) get_ifile(filename, ifile);
19714230Sphk			ifile = prev_ifile(NULL_IFILE);
19817758Ssos		}
19917758Ssos		free(gfilename);
20017758Ssos#else
20117758Ssos		filename = shell_quote(*argv);
2021541Srgrimes		if (filename == NULL)
2031541Srgrimes			filename = *argv;
20412296Sphk		argv++;
20512820Sphk		(void) get_ifile(filename, ifile);
2061541Srgrimes		ifile = prev_ifile(NULL_IFILE);
2071541Srgrimes#endif
2081541Srgrimes	}
2091541Srgrimes	/*
2101541Srgrimes	 * Set up terminal, etc.
21113929Swollman	 */
21213929Swollman	if (!is_tty)
2131541Srgrimes	{
21415026Sphk		/*
21515026Sphk		 * Output is not a tty.
21615026Sphk		 * Just copy the input file(s) to output.
21714232Sphk		 */
2181541Srgrimes		SET_BINARY(1);
2191541Srgrimes		if (nifile() == 0)
2201541Srgrimes		{
22118797Swollman			if (edit_stdin() == 0)
2221541Srgrimes				cat_file();
2231541Srgrimes		} else if (edit_first() == 0)
2241541Srgrimes		{
2251541Srgrimes			do {
2261541Srgrimes				cat_file();
2271541Srgrimes			} while (edit_next(1) == 0);
2281541Srgrimes		}
2291541Srgrimes		quit(QUIT_OK);
23018797Swollman	}
23118797Swollman
23218797Swollman	if (missing_cap && !know_dumb && !more_mode)
23318797Swollman		error("WARNING: terminal is not fully functional", NULL_PARG);
23418797Swollman	init_mark();
23518797Swollman	open_getchr();
23618797Swollman	raw_mode(1);
23718797Swollman	init_signals(1);
23818797Swollman
2391541Srgrimes	/*
2401541Srgrimes	 * Select the first file to examine.
2411541Srgrimes	 */
24213929Swollman#if TAGS
2431541Srgrimes	if (tagoption != NULL || strcmp(tags, "-") == 0)
2441541Srgrimes	{
24518797Swollman		/*
24618797Swollman		 * A -t option was given.
2471541Srgrimes		 * Verify that no filenames were also given.
2481541Srgrimes		 * Edit the file selected by the "tags" search,
2491541Srgrimes		 * and search for the proper line in the file.
25018797Swollman		 */
25118797Swollman		if (nifile() > 0)
2521541Srgrimes		{
2531541Srgrimes			error("No filenames allowed with -t option", NULL_PARG);
2541541Srgrimes			quit(QUIT_ERROR);
2551541Srgrimes		}
2561541Srgrimes		findtag(tagoption);
2571541Srgrimes		if (edit_tagfile())  /* Edit file which contains the tag */
2581541Srgrimes			quit(QUIT_ERROR);
25913929Swollman		/*
2601541Srgrimes		 * Search for the line which contains the tag.
2611541Srgrimes		 * Set up initial_scrpos so we display that line.
2621541Srgrimes		 */
26318797Swollman		initial_scrpos.pos = tagsearch();
26418797Swollman		if (initial_scrpos.pos == NULL_POSITION)
26518797Swollman			quit(QUIT_ERROR);
26618797Swollman		initial_scrpos.ln = jump_sline;
26718797Swollman	} else
2683311Sphk#endif
2691541Srgrimes	if (nifile() == 0)
2701541Srgrimes	{
2711541Srgrimes		if (edit_stdin())  /* Edit standard input */
2721541Srgrimes			quit(QUIT_ERROR);
2731541Srgrimes	} else
2741541Srgrimes	{
2751541Srgrimes		if (edit_first())  /* Edit first valid file in cmd line */
2761541Srgrimes			quit(QUIT_ERROR);
2771541Srgrimes	}
2781541Srgrimes
2791541Srgrimes	init();
2801541Srgrimes	commands();
2811541Srgrimes	quit(QUIT_OK);
2821541Srgrimes	/*NOTREACHED*/
2831541Srgrimes	return (0);
2841541Srgrimes}
2851541Srgrimes
2861541Srgrimes/*
2871541Srgrimes * Copy a string to a "safe" place
2881541Srgrimes * (that is, to a buffer allocated by calloc).
2891541Srgrimes */
2901541Srgrimes	public char *
29118797Swollmansave(s)
2921541Srgrimes	char *s;
2931541Srgrimes{
2941541Srgrimes	register char *p;
2951541Srgrimes
2961541Srgrimes	p = (char *) ecalloc(strlen(s)+1, sizeof(char));
2971541Srgrimes	strcpy(p, s);
2981541Srgrimes	return (p);
2991541Srgrimes}
3001541Srgrimes
3011541Srgrimes/*
3025543Sugen * Allocate memory.
3035543Sugen * Like calloc(), but never returns an error (NULL).
3045543Sugen */
3055543Sugen	public VOID_POINTER
3065543Sugenecalloc(count, size)
30717072Sjulian	int count;
30817758Ssos	unsigned int size;
3095543Sugen{
3105543Sugen	register VOID_POINTER p;
3115543Sugen
3121541Srgrimes	p = (VOID_POINTER) calloc(count, size);
31318797Swollman	if (p != NULL)
31417072Sjulian		return (p);
31517072Sjulian	error("Cannot allocate memory", NULL_PARG);
3163969Sjkh	quit(QUIT_ERROR);
31717072Sjulian	/*NOTREACHED*/
31817072Sjulian	return (NULL);
31917072Sjulian}
32017072Sjulian
32117072Sjulian/*
32217072Sjulian * Skip leading spaces in a string.
32317072Sjulian */
32417072Sjulian	public char *
32517072Sjulianskipsp(s)
32617072Sjulian	register char *s;
32717072Sjulian{
32817072Sjulian	while (*s == ' ' || *s == '\t')
32917072Sjulian		s++;
33017072Sjulian	return (s);
33117072Sjulian}
33217072Sjulian
33317072Sjulian/*
33417072Sjulian * See how many characters of two strings are identical.
33519113Ssos * If uppercase is true, the first string must begin with an uppercase
33617758Ssos * character; the remainder of the first string may be either case.
33718797Swollman */
33817758Ssos	public int
3391541Srgrimessprefix(ps, s, uppercase)
3401541Srgrimes	char *ps;
3411541Srgrimes	char *s;
3421541Srgrimes	int uppercase;
3431541Srgrimes{
3441541Srgrimes	register int c;
3451541Srgrimes	register int sc;
3461541Srgrimes	register int len = 0;
34713929Swollman
3481541Srgrimes	for ( ;  *s != '\0';  s++, ps++)
3492531Swollman	{
3509209Swollman		c = *ps;
3512531Swollman		if (uppercase)
3522531Swollman		{
3532531Swollman			if (len == 0 && SIMPLE_IS_LOWER(c))
3542531Swollman				return (-1);
3559209Swollman			if (SIMPLE_IS_UPPER(c))
3562531Swollman				c = SIMPLE_TO_LOWER(c);
3572531Swollman		}
3581541Srgrimes		sc = *s;
3591541Srgrimes		if (len > 0 && SIMPLE_IS_UPPER(sc))
3601541Srgrimes			sc = SIMPLE_TO_LOWER(sc);
3611541Srgrimes		if (c != sc)
3621541Srgrimes			break;
3631541Srgrimes		len++;
3641541Srgrimes	}
3651541Srgrimes	return (len);
36614817Sphk}
3671541Srgrimes
3681541Srgrimes/*
3691541Srgrimes * Exit the program.
3701541Srgrimes */
3711541Srgrimes	public void
3721541Srgrimesquit(status)
3731541Srgrimes	int status;
3741541Srgrimes{
3751541Srgrimes	static int save_status;
3761541Srgrimes
3771541Srgrimes	/*
3781541Srgrimes	 * Put cursor at bottom left corner, clear the line,
3791541Srgrimes	 * reset the terminal modes, and exit.
3801541Srgrimes	 */
3811541Srgrimes	if (status < 0)
3821541Srgrimes		status = save_status;
3831541Srgrimes	else
3841541Srgrimes		save_status = status;
3851541Srgrimes	quitting = 1;
3861541Srgrimes	edit((char*)NULL);
3871541Srgrimes	if (any_display && is_tty)
3881541Srgrimes		clear_bot();
3891541Srgrimes	deinit();
3902531Swollman	flush();
3911541Srgrimes	raw_mode(0);
3921541Srgrimes#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
39313929Swollman	/*
3941541Srgrimes	 * If we don't close 2, we get some garbage from
3951541Srgrimes	 * 2's buffer when it flushes automatically.
3961541Srgrimes	 * I cannot track this one down  RB
3971541Srgrimes	 * The same bug shows up if we use ^C^C to abort.
3981541Srgrimes	 */
3991541Srgrimes	close(2);
4001541Srgrimes#endif
4011541Srgrimes#if WIN32
4021541Srgrimes	SetConsoleTitle(consoleTitle);
4031541Srgrimes#endif
4041541Srgrimes	close_getchr();
4051541Srgrimes	exit(status);
4061541Srgrimes}
4071541Srgrimes