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