Home | History | Annotate | Line # | Download | only in more
main.c revision 1.6
      1 /*	$NetBSD: main.c,v 1.6 2003/08/07 09:28:00 agc Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1993
      5  *	Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1988 Mark Nudleman
     34  *
     35  * Redistribution and use in source and binary forms, with or without
     36  * modification, are permitted provided that the following conditions
     37  * are met:
     38  * 1. Redistributions of source code must retain the above copyright
     39  *    notice, this list of conditions and the following disclaimer.
     40  * 2. Redistributions in binary form must reproduce the above copyright
     41  *    notice, this list of conditions and the following disclaimer in the
     42  *    documentation and/or other materials provided with the distribution.
     43  * 3. All advertising materials mentioning features or use of this software
     44  *    must display the following acknowledgement:
     45  *	This product includes software developed by the University of
     46  *	California, Berkeley and its contributors.
     47  * 4. Neither the name of the University nor the names of its contributors
     48  *    may be used to endorse or promote products derived from this software
     49  *    without specific prior written permission.
     50  *
     51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     61  * SUCH DAMAGE.
     62  */
     63 
     64 #include <sys/cdefs.h>
     65 #ifndef lint
     66 __COPYRIGHT(
     67 "@(#) Copyright (c) 1988 Mark Nudleman.\n\
     68 @(#) Copyright (c) 1988, 1993
     69 	Regents of the University of California.  All rights reserved.\n");
     70 #endif /* not lint */
     71 
     72 #ifndef lint
     73 #if 0
     74 static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/7/93";
     75 #else
     76 __RCSID("$NetBSD: main.c,v 1.6 2003/08/07 09:28:00 agc Exp $");
     77 #endif
     78 #endif /* not lint */
     79 
     80 /*
     81  * Entry point, initialization, miscellaneous routines.
     82  */
     83 
     84 #include <sys/types.h>
     85 #include <sys/file.h>
     86 #include <stdio.h>
     87 #include <string.h>
     88 #include <errno.h>
     89 #include <stdlib.h>
     90 #include <unistd.h>
     91 
     92 #include "less.h"
     93 #include "extern.h"
     94 
     95 int	ispipe;
     96 int	new_file;
     97 int	is_tty;
     98 char	*current_file, *previous_file, *current_name, *next_name;
     99 off_t	prev_pos;
    100 int	any_display;
    101 int	scroll;
    102 int	ac;
    103 char	**av;
    104 int	curr_ac;
    105 int	quitting;
    106 
    107 static void cat_file __P((void));
    108 /*
    109  * Edit a new file.
    110  * Filename "-" means standard input.
    111  * No filename means the "current" file, from the command line.
    112  */
    113 int
    114 edit(filename)
    115 	char *filename;
    116 {
    117 	int f;
    118 	char *m;
    119 	off_t initial_pos;
    120 	static int didpipe;
    121 	char message[100], *p;
    122 
    123 	initial_pos = NULL_POSITION;
    124 	if (filename == NULL || *filename == '\0') {
    125 		if (curr_ac >= ac) {
    126 			error("No current file");
    127 			return(0);
    128 		}
    129 		filename = save(av[curr_ac]);
    130 	}
    131 	else if (strcmp(filename, "#") == 0) {
    132 		if (*previous_file == '\0') {
    133 			error("no previous file");
    134 			return(0);
    135 		}
    136 		filename = save(previous_file);
    137 		initial_pos = prev_pos;
    138 	} else
    139 		filename = save(filename);
    140 
    141 	/* use standard input. */
    142 	if (!strcmp(filename, "-")) {
    143 		if (didpipe) {
    144 			error("Can view standard input only once");
    145 			return(0);
    146 		}
    147 		f = 0;
    148 	}
    149 	else if ((m = bad_file(filename, message, sizeof(message))) != NULL) {
    150 		error(m);
    151 		free(filename);
    152 		return(0);
    153 	}
    154 	else if ((f = open(filename, O_RDONLY, 0)) < 0) {
    155 		(void)snprintf(message, sizeof(message), "%s: %s", filename,
    156 		    strerror(errno));
    157 		error(message);
    158 		free(filename);
    159 		return(0);
    160 	}
    161 
    162 	if (isatty(f)) {
    163 		/*
    164 		 * Not really necessary to call this an error,
    165 		 * but if the control terminal (for commands)
    166 		 * and the input file (for data) are the same,
    167 		 * we get weird results at best.
    168 		 */
    169 		error("Can't take input from a terminal");
    170 		if (f > 0)
    171 			(void)close(f);
    172 		(void)free(filename);
    173 		return(0);
    174 	}
    175 
    176 	/*
    177 	 * We are now committed to using the new file.
    178 	 * Close the current input file and set up to use the new one.
    179 	 */
    180 	if (file > 0)
    181 		(void)close(file);
    182 	new_file = 1;
    183 	if (previous_file != NULL)
    184 		free(previous_file);
    185 	previous_file = current_file;
    186 	current_file = filename;
    187 	pos_clear();
    188 	prev_pos = position(TOP);
    189 	ispipe = (f == 0);
    190 	if (ispipe) {
    191 		didpipe = 1;
    192 		current_name = "stdin";
    193 	} else
    194 		current_name = (p = rindex(filename, '/')) ? p + 1 : filename;
    195 	if (curr_ac >= ac)
    196 		next_name = NULL;
    197 	else
    198 		next_name = av[curr_ac + 1];
    199 	file = f;
    200 	ch_init(cbufs, 0);
    201 	init_mark();
    202 
    203 	if (is_tty) {
    204 		int no_display = !any_display;
    205 		any_display = 1;
    206 		if (no_display && errmsgs > 0) {
    207 			/*
    208 			 * We displayed some messages on error output
    209 			 * (file descriptor 2; see error() function).
    210 			 * Before erasing the screen contents,
    211 			 * display the file name and wait for a keystroke.
    212 			 */
    213 			error(filename);
    214 		}
    215 		/*
    216 		 * Indicate there is nothing displayed yet.
    217 		 */
    218 		if (initial_pos != NULL_POSITION)
    219 			jump_loc(initial_pos);
    220 		clr_linenum();
    221 	}
    222 	return(1);
    223 }
    224 
    225 /*
    226  * Edit the next file in the command line list.
    227  */
    228 void
    229 next_file(n)
    230 	int n;
    231 {
    232 	if (curr_ac + n >= ac) {
    233 		if (quit_at_eof || position(TOP) == NULL_POSITION)
    234 			quit();
    235 		error("No (N-th) next file");
    236 	}
    237 	else
    238 		(void)edit(av[curr_ac += n]);
    239 }
    240 
    241 /*
    242  * Edit the previous file in the command line list.
    243  */
    244 void
    245 prev_file(n)
    246 	int n;
    247 {
    248 	if (curr_ac - n < 0)
    249 		error("No (N-th) previous file");
    250 	else
    251 		(void)edit(av[curr_ac -= n]);
    252 }
    253 
    254 /*
    255  * copy a file directly to standard output; used if stdout is not a tty.
    256  * the only processing is to squeeze multiple blank input lines.
    257  */
    258 static void
    259 cat_file()
    260 {
    261 	int c, empty;
    262 
    263 	if (squeeze) {
    264 		empty = 0;
    265 		while ((c = ch_forw_get()) != EOI)
    266 			if (c != '\n') {
    267 				putchr(c);
    268 				empty = 0;
    269 			}
    270 			else if (empty < 2) {
    271 				putchr(c);
    272 				++empty;
    273 			}
    274 	}
    275 	else while ((c = ch_forw_get()) != EOI)
    276 		putchr(c);
    277 	flush();
    278 }
    279 
    280 int
    281 main(argc, argv)
    282 	int argc;
    283 	char **argv;
    284 {
    285 	int envargc, argcnt;
    286 	char *envargv[2];
    287 
    288 	/*
    289 	 * Process command line arguments and MORE environment arguments.
    290 	 * Command line arguments override environment arguments.
    291 	 */
    292 	if ((envargv[1] = getenv("MORE")) != NULL) {
    293 		envargc = 2;
    294 		envargv[0] = "more";
    295 		envargv[2] = NULL;
    296 		(void)option(envargc, envargv);
    297 	}
    298 	argcnt = option(argc, argv);
    299 	argv += argcnt;
    300 	argc -= argcnt;
    301 
    302 	/*
    303 	 * Set up list of files to be examined.
    304 	 */
    305 	ac = argc;
    306 	av = argv;
    307 	curr_ac = 0;
    308 
    309 	/*
    310 	 * Set up terminal, etc.
    311 	 */
    312 	is_tty = isatty(1);
    313 	if (!is_tty) {
    314 		/*
    315 		 * Output is not a tty.
    316 		 * Just copy the input file(s) to output.
    317 		 */
    318 		if (ac < 1) {
    319 			(void)edit("-");
    320 			cat_file();
    321 		} else {
    322 			do {
    323 				(void)edit((char *)NULL);
    324 				if (file >= 0)
    325 					cat_file();
    326 			} while (++curr_ac < ac);
    327 		}
    328 		exit(0);
    329 	}
    330 
    331 	raw_mode(1);
    332 	get_term();
    333 	open_getchr();
    334 	init();
    335 	init_signals(1);
    336 
    337 	/* select the first file to examine. */
    338 	if (ac < 1)
    339 		(void)edit("-");	/* Standard input */
    340 	else {
    341 		/*
    342 		 * Try all the files named as command arguments.
    343 		 * We are simply looking for one which can be
    344 		 * opened without error.
    345 		 */
    346 		do {
    347 			(void)edit((char *)NULL);
    348 		} while (file < 0 && ++curr_ac < ac);
    349 	}
    350 
    351 	if (file >= 0)
    352 		commands();
    353 	quit();
    354 }
    355 
    356 /*
    357  * Copy a string to a "safe" place
    358  * (that is, to a buffer allocated by malloc).
    359  */
    360 char *
    361 save(s)
    362 	char *s;
    363 {
    364 	char *p;
    365 
    366 	p = strdup(s);
    367 	if (p == NULL)
    368 	{
    369 		error("cannot allocate memory");
    370 		quit();
    371 	}
    372 	return(p);
    373 }
    374 
    375 /*
    376  * Exit the program.
    377  */
    378 void
    379 quit()
    380 {
    381 	/*
    382 	 * Put cursor at bottom left corner, clear the line,
    383 	 * reset the terminal modes, and exit.
    384 	 */
    385 	quitting = 1;
    386 	lower_left();
    387 	clear_eol();
    388 	deinit();
    389 	flush();
    390 	raw_mode(0);
    391 	exit(0);
    392 }
    393