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