xref: /netbsd-src/distrib/utils/more/main.c (revision eb7c1594f145c931049e1fd9eb056a5987e87e59)
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