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