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