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