main.c revision 1.7 1 /* $NetBSD: main.c,v 1.7 2003/08/10 08:26:38 mrg 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\n\
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.7 2003/08/10 08:26:38 mrg 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