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