Commit | Line | Data |
---|---|---|
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 | |
36 | char 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 | |
43 | static 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 | ||
55 | int ispipe; | |
56 | int new_file; | |
57 | int is_tty; | |
58 | char *current_file, *previous_file, *current_name, *next_name; | |
59 | off_t prev_pos; | |
60 | int any_display; | |
61 | int scroll; | |
62 | int ac; | |
63 | char **av; | |
64 | int curr_ac; | |
65 | int quitting; | |
66 | ||
67 | extern int file; | |
68 | extern int cbufs; | |
69 | extern int errmsgs; | |
70 | ||
71 | extern char *tagfile; | |
72 | extern 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 | */ | |
79 | edit(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 | */ | |
194 | next_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 | */ | |
212 | prev_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 | */ | |
225 | static | |
226 | cat_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 | ||
248 | main(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 | */ | |
336 | char * | |
337 | save(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 | */ | |
354 | quit() | |
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 | } |