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