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