xref: /csrg-svn/usr.bin/more/main.c (revision 62559)
135209Sbostic /*
235209Sbostic  * Copyright (c) 1988 Mark Nudleman
362558Sbostic  * Copyright (c) 1988, 1993
462558Sbostic  *	Regents of the University of California.  All rights reserved.
535209Sbostic  *
642742Sbostic  * %sccs.include.redist.c%
735209Sbostic  */
835209Sbostic 
935209Sbostic #ifndef lint
1035209Sbostic char copyright[] =
1135209Sbostic "@(#) Copyright (c) 1988 Mark Nudleman.\n\
1262558Sbostic @(#) Copyright (c) 1988, 1993
1362558Sbostic 	Regents of the University of California.  All rights reserved.\n";
1435209Sbostic #endif /* not lint */
1535209Sbostic 
1635209Sbostic #ifndef lint
17*62559Sbostic static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 06/07/93";
1835209Sbostic #endif /* not lint */
1935209Sbostic 
2035209Sbostic /*
2135209Sbostic  * Entry point, initialization, miscellaneous routines.
2235209Sbostic  */
2335209Sbostic 
2436251Sbostic #include <sys/types.h>
2536251Sbostic #include <sys/file.h>
2636251Sbostic #include <stdio.h>
2736251Sbostic #include <less.h>
2835209Sbostic 
2936251Sbostic int	ispipe;
3036251Sbostic int	new_file;
3136251Sbostic int	is_tty;
3236272Sbostic char	*current_file, *previous_file, *current_name, *next_name;
3336251Sbostic off_t	prev_pos;
3436251Sbostic int	any_display;
3536251Sbostic int	scroll;
3636251Sbostic int	ac;
3736251Sbostic char	**av;
3836251Sbostic int	curr_ac;
3936251Sbostic int	quitting;
4035209Sbostic 
4135209Sbostic extern int	file;
4235209Sbostic extern int	cbufs;
4335209Sbostic extern int	errmsgs;
4435209Sbostic 
4536251Sbostic extern char	*tagfile;
4635209Sbostic extern int	tagoption;
4735209Sbostic 
4835209Sbostic /*
4935209Sbostic  * Edit a new file.
5035209Sbostic  * Filename "-" means standard input.
5135209Sbostic  * No filename means the "current" file, from the command line.
5235209Sbostic  */
edit(filename)5335209Sbostic edit(filename)
5435209Sbostic 	register char *filename;
5535209Sbostic {
5636251Sbostic 	extern int errno;
5735209Sbostic 	register int f;
5835209Sbostic 	register char *m;
5936251Sbostic 	off_t initial_pos, position();
6035209Sbostic 	static int didpipe;
6136251Sbostic 	char message[100], *p;
6236251Sbostic 	char *rindex(), *strerror(), *save(), *bad_file();
6335209Sbostic 
6435209Sbostic 	initial_pos = NULL_POSITION;
6536251Sbostic 	if (filename == NULL || *filename == '\0') {
6636251Sbostic 		if (curr_ac >= ac) {
6735209Sbostic 			error("No current file");
6836251Sbostic 			return(0);
6935209Sbostic 		}
7035209Sbostic 		filename = save(av[curr_ac]);
7136251Sbostic 	}
7236251Sbostic 	else if (strcmp(filename, "#") == 0) {
7336251Sbostic 		if (*previous_file == '\0') {
7435209Sbostic 			error("no previous file");
7536251Sbostic 			return(0);
7635209Sbostic 		}
7735209Sbostic 		filename = save(previous_file);
7835209Sbostic 		initial_pos = prev_pos;
7935209Sbostic 	} else
8035209Sbostic 		filename = save(filename);
8135209Sbostic 
8236251Sbostic 	/* use standard input. */
8336251Sbostic 	if (!strcmp(filename, "-")) {
8436251Sbostic 		if (didpipe) {
8535209Sbostic 			error("Can view standard input only once");
8636251Sbostic 			return(0);
8735209Sbostic 		}
8835209Sbostic 		f = 0;
8936251Sbostic 	}
9036251Sbostic 	else if ((m = bad_file(filename, message, sizeof(message))) != NULL) {
9135209Sbostic 		error(m);
9235209Sbostic 		free(filename);
9336251Sbostic 		return(0);
9436251Sbostic 	}
9536251Sbostic 	else if ((f = open(filename, O_RDONLY, 0)) < 0) {
9636251Sbostic 		(void)sprintf(message, "%s: %s", filename, strerror(errno));
9736251Sbostic 		error(message);
9835209Sbostic 		free(filename);
9936251Sbostic 		return(0);
10035209Sbostic 	}
10135209Sbostic 
10236251Sbostic 	if (isatty(f)) {
10335209Sbostic 		/*
10435209Sbostic 		 * Not really necessary to call this an error,
10535209Sbostic 		 * but if the control terminal (for commands)
10635209Sbostic 		 * and the input file (for data) are the same,
10735209Sbostic 		 * we get weird results at best.
10835209Sbostic 		 */
10935209Sbostic 		error("Can't take input from a terminal");
11035209Sbostic 		if (f > 0)
11136251Sbostic 			(void)close(f);
11236251Sbostic 		(void)free(filename);
11336251Sbostic 		return(0);
11435209Sbostic 	}
11535209Sbostic 
11635209Sbostic 	/*
11735209Sbostic 	 * We are now committed to using the new file.
11835209Sbostic 	 * Close the current input file and set up to use the new one.
11935209Sbostic 	 */
12035209Sbostic 	if (file > 0)
12136251Sbostic 		(void)close(file);
12235209Sbostic 	new_file = 1;
12335209Sbostic 	if (previous_file != NULL)
12435209Sbostic 		free(previous_file);
12535209Sbostic 	previous_file = current_file;
12635209Sbostic 	current_file = filename;
12740239Sdonn 	pos_clear();
12835209Sbostic 	prev_pos = position(TOP);
12935209Sbostic 	ispipe = (f == 0);
13036251Sbostic 	if (ispipe) {
13135209Sbostic 		didpipe = 1;
13236251Sbostic 		current_name = "stdin";
13336251Sbostic 	} else
13436251Sbostic 		current_name = (p = rindex(filename, '/')) ? p + 1 : filename;
13536272Sbostic 	if (curr_ac >= ac)
13636272Sbostic 		next_name = NULL;
13736272Sbostic 	else
13836272Sbostic 		next_name = av[curr_ac + 1];
13935209Sbostic 	file = f;
14035209Sbostic 	ch_init(cbufs, 0);
14135209Sbostic 	init_mark();
14235209Sbostic 
14336251Sbostic 	if (is_tty) {
14435209Sbostic 		int no_display = !any_display;
14535209Sbostic 		any_display = 1;
14636251Sbostic 		if (no_display && errmsgs > 0) {
14735209Sbostic 			/*
14835209Sbostic 			 * We displayed some messages on error output
14935209Sbostic 			 * (file descriptor 2; see error() function).
15035209Sbostic 			 * Before erasing the screen contents,
15135209Sbostic 			 * display the file name and wait for a keystroke.
15235209Sbostic 			 */
15335209Sbostic 			error(filename);
15435209Sbostic 		}
15535209Sbostic 		/*
15635209Sbostic 		 * Indicate there is nothing displayed yet.
15735209Sbostic 		 */
15835209Sbostic 		if (initial_pos != NULL_POSITION)
15935209Sbostic 			jump_loc(initial_pos);
16035209Sbostic 		clr_linenum();
16135209Sbostic 	}
16236251Sbostic 	return(1);
16335209Sbostic }
16435209Sbostic 
16535209Sbostic /*
16635209Sbostic  * Edit the next file in the command line list.
16735209Sbostic  */
next_file(n)16835209Sbostic next_file(n)
16935209Sbostic 	int n;
17035209Sbostic {
17136251Sbostic 	extern int quit_at_eof;
17236251Sbostic 	off_t position();
17336251Sbostic 
17436251Sbostic 	if (curr_ac + n >= ac) {
17536251Sbostic 		if (quit_at_eof || position(TOP) == NULL_POSITION)
17635209Sbostic 			quit();
17735209Sbostic 		error("No (N-th) next file");
17836251Sbostic 	}
17936251Sbostic 	else
18036251Sbostic 		(void)edit(av[curr_ac += n]);
18135209Sbostic }
18235209Sbostic 
18335209Sbostic /*
18435209Sbostic  * Edit the previous file in the command line list.
18535209Sbostic  */
prev_file(n)18635209Sbostic prev_file(n)
18735209Sbostic 	int n;
18835209Sbostic {
18935209Sbostic 	if (curr_ac - n < 0)
19035209Sbostic 		error("No (N-th) previous file");
19135209Sbostic 	else
19236251Sbostic 		(void)edit(av[curr_ac -= n]);
19335209Sbostic }
19435209Sbostic 
19535209Sbostic /*
19636267Sbostic  * copy a file directly to standard output; used if stdout is not a tty.
19736267Sbostic  * the only processing is to squeeze multiple blank input lines.
19835209Sbostic  */
19936251Sbostic static
cat_file()20035209Sbostic cat_file()
20135209Sbostic {
20236267Sbostic 	extern int squeeze;
20336267Sbostic 	register int c, empty;
20435209Sbostic 
20536267Sbostic 	if (squeeze) {
20636267Sbostic 		empty = 0;
20736267Sbostic 		while ((c = ch_forw_get()) != EOI)
20836267Sbostic 			if (c != '\n') {
20936267Sbostic 				putchr(c);
21036267Sbostic 				empty = 0;
21136267Sbostic 			}
21236267Sbostic 			else if (empty < 2) {
21336267Sbostic 				putchr(c);
21436267Sbostic 				++empty;
21536267Sbostic 			}
21636267Sbostic 	}
21736267Sbostic 	else while ((c = ch_forw_get()) != EOI)
21835209Sbostic 		putchr(c);
21935209Sbostic 	flush();
22035209Sbostic }
22135209Sbostic 
main(argc,argv)22235209Sbostic main(argc, argv)
22335209Sbostic 	int argc;
22436251Sbostic 	char **argv;
22535209Sbostic {
22636251Sbostic 	int envargc, argcnt;
22736251Sbostic 	char *envargv[2], *getenv();
22835209Sbostic 
22935209Sbostic 	/*
23036251Sbostic 	 * Process command line arguments and MORE environment arguments.
23135209Sbostic 	 * Command line arguments override environment arguments.
23235209Sbostic 	 */
23336251Sbostic 	if (envargv[1] = getenv("MORE")) {
23436251Sbostic 		envargc = 2;
23536251Sbostic 		envargv[0] = "more";
23636251Sbostic 		envargv[2] = NULL;
23736251Sbostic 		(void)option(envargc, envargv);
23836251Sbostic 	}
23936251Sbostic 	argcnt = option(argc, argv);
24036251Sbostic 	argv += argcnt;
24136251Sbostic 	argc -= argcnt;
24235209Sbostic 
24335209Sbostic 	/*
24435209Sbostic 	 * Set up list of files to be examined.
24535209Sbostic 	 */
24635209Sbostic 	ac = argc;
24735209Sbostic 	av = argv;
24835209Sbostic 	curr_ac = 0;
24935209Sbostic 
25035209Sbostic 	/*
25135209Sbostic 	 * Set up terminal, etc.
25235209Sbostic 	 */
25335209Sbostic 	is_tty = isatty(1);
25436251Sbostic 	if (!is_tty) {
25535209Sbostic 		/*
25635209Sbostic 		 * Output is not a tty.
25735209Sbostic 		 * Just copy the input file(s) to output.
25835209Sbostic 		 */
25936251Sbostic 		if (ac < 1) {
26036251Sbostic 			(void)edit("-");
26135209Sbostic 			cat_file();
26236251Sbostic 		} else {
26336251Sbostic 			do {
26436251Sbostic 				(void)edit((char *)NULL);
26535209Sbostic 				if (file >= 0)
26635209Sbostic 					cat_file();
26735209Sbostic 			} while (++curr_ac < ac);
26835209Sbostic 		}
26935209Sbostic 		exit(0);
27035209Sbostic 	}
27135209Sbostic 
27235209Sbostic 	raw_mode(1);
27335209Sbostic 	get_term();
27435209Sbostic 	open_getchr();
27535209Sbostic 	init();
27635209Sbostic 	init_signals(1);
27735209Sbostic 
27836251Sbostic 	/* select the first file to examine. */
27936251Sbostic 	if (tagoption) {
28035209Sbostic 		/*
28136251Sbostic 		 * A -t option was given; edit the file selected by the
28236251Sbostic 		 * "tags" search, and search for the proper line in the file.
28335209Sbostic 		 */
28436251Sbostic 		if (!tagfile || !edit(tagfile) || tagsearch())
28535209Sbostic 			quit();
28636251Sbostic 	}
28736251Sbostic 	else if (ac < 1)
28836251Sbostic 		(void)edit("-");	/* Standard input */
28936251Sbostic 	else {
29035209Sbostic 		/*
29135209Sbostic 		 * Try all the files named as command arguments.
29235209Sbostic 		 * We are simply looking for one which can be
29335209Sbostic 		 * opened without error.
29435209Sbostic 		 */
29536251Sbostic 		do {
29636251Sbostic 			(void)edit((char *)NULL);
29735209Sbostic 		} while (file < 0 && ++curr_ac < ac);
29835209Sbostic 	}
29935209Sbostic 
30035209Sbostic 	if (file >= 0)
30135209Sbostic 		commands();
30235209Sbostic 	quit();
30335209Sbostic 	/*NOTREACHED*/
30435209Sbostic }
30535209Sbostic 
30635209Sbostic /*
30735209Sbostic  * Copy a string to a "safe" place
30835245Sbostic  * (that is, to a buffer allocated by malloc).
30935209Sbostic  */
31036251Sbostic char *
save(s)31135209Sbostic save(s)
31235209Sbostic 	char *s;
31335209Sbostic {
31435245Sbostic 	char *p, *strcpy(), *malloc();
31535209Sbostic 
31635245Sbostic 	p = malloc((u_int)strlen(s)+1);
31735209Sbostic 	if (p == NULL)
31835209Sbostic 	{
31935209Sbostic 		error("cannot allocate memory");
32035209Sbostic 		quit();
32135209Sbostic 	}
32235245Sbostic 	return(strcpy(p, s));
32335209Sbostic }
32435209Sbostic 
32535209Sbostic /*
32635209Sbostic  * Exit the program.
32735209Sbostic  */
quit()32835209Sbostic quit()
32935209Sbostic {
33035209Sbostic 	/*
33135209Sbostic 	 * Put cursor at bottom left corner, clear the line,
33235209Sbostic 	 * reset the terminal modes, and exit.
33335209Sbostic 	 */
33435209Sbostic 	quitting = 1;
33535209Sbostic 	lower_left();
33635209Sbostic 	clear_eol();
33735209Sbostic 	deinit();
33835209Sbostic 	flush();
33935209Sbostic 	raw_mode(0);
34035209Sbostic 	exit(0);
34135209Sbostic }
342