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