1*ad436ff6Sjoerg /* $NetBSD: main.c,v 1.13 2013/07/10 08:00:29 joerg Exp $ */
274b7d6e9Sagc
374b7d6e9Sagc /*
461470ee0Sagc * Copyright (c) 1988 Mark Nudelman
574b7d6e9Sagc * Copyright (c) 1988, 1993
674b7d6e9Sagc * Regents of the University of California. All rights reserved.
774b7d6e9Sagc *
874b7d6e9Sagc * Redistribution and use in source and binary forms, with or without
974b7d6e9Sagc * modification, are permitted provided that the following conditions
1074b7d6e9Sagc * are met:
1174b7d6e9Sagc * 1. Redistributions of source code must retain the above copyright
1274b7d6e9Sagc * notice, this list of conditions and the following disclaimer.
1374b7d6e9Sagc * 2. Redistributions in binary form must reproduce the above copyright
1474b7d6e9Sagc * notice, this list of conditions and the following disclaimer in the
1574b7d6e9Sagc * documentation and/or other materials provided with the distribution.
1674b7d6e9Sagc * 3. Neither the name of the University nor the names of its contributors
1774b7d6e9Sagc * may be used to endorse or promote products derived from this software
1874b7d6e9Sagc * without specific prior written permission.
1974b7d6e9Sagc *
2074b7d6e9Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2174b7d6e9Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2274b7d6e9Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2374b7d6e9Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2474b7d6e9Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2574b7d6e9Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2674b7d6e9Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2774b7d6e9Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2874b7d6e9Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2974b7d6e9Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3074b7d6e9Sagc * SUCH DAMAGE.
3174b7d6e9Sagc */
323fe138c1Sperry
33e3fbe7d2Schristos #include <sys/cdefs.h>
34963d5659Scjs #ifndef lint
35cf364a01Smatt __COPYRIGHT("@(#) Copyright (c) 1988 Mark Nudelman.");
36cf364a01Smatt __COPYRIGHT("@(#) Copyright (c) 1988, 1993 "
37741c872fSmatt "Regents of the University of California. All rights reserved.");
38963d5659Scjs #endif /* not lint */
39963d5659Scjs
40963d5659Scjs #ifndef lint
41e3fbe7d2Schristos #if 0
42963d5659Scjs static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/7/93";
43e3fbe7d2Schristos #else
44*ad436ff6Sjoerg __RCSID("$NetBSD: main.c,v 1.13 2013/07/10 08:00:29 joerg Exp $");
45e3fbe7d2Schristos #endif
46963d5659Scjs #endif /* not lint */
47963d5659Scjs
48963d5659Scjs /*
49963d5659Scjs * Entry point, initialization, miscellaneous routines.
50963d5659Scjs */
51963d5659Scjs
52963d5659Scjs #include <sys/types.h>
53963d5659Scjs #include <sys/file.h>
54963d5659Scjs #include <stdio.h>
556a623f72Scjs #include <string.h>
56e3fbe7d2Schristos #include <errno.h>
57e3fbe7d2Schristos #include <stdlib.h>
58e3fbe7d2Schristos #include <unistd.h>
59e3fbe7d2Schristos
60e3fbe7d2Schristos #include "less.h"
61e3fbe7d2Schristos #include "extern.h"
62963d5659Scjs
63963d5659Scjs int ispipe;
64963d5659Scjs int new_file;
65963d5659Scjs int is_tty;
66963d5659Scjs char *current_file, *previous_file, *current_name, *next_name;
67963d5659Scjs off_t prev_pos;
68963d5659Scjs int any_display;
69c2472e10Schs int scroll_lines;
70963d5659Scjs int ac;
71963d5659Scjs char **av;
72963d5659Scjs int curr_ac;
73963d5659Scjs int quitting;
74963d5659Scjs
75e3fbe7d2Schristos static void cat_file __P((void));
76963d5659Scjs /*
77963d5659Scjs * Edit a new file.
78963d5659Scjs * Filename "-" means standard input.
79963d5659Scjs * No filename means the "current" file, from the command line.
80963d5659Scjs */
81e3fbe7d2Schristos int
edit(filename)82963d5659Scjs edit(filename)
83e3fbe7d2Schristos char *filename;
84963d5659Scjs {
85e3fbe7d2Schristos int f;
86e3fbe7d2Schristos char *m;
87e3fbe7d2Schristos off_t initial_pos;
88963d5659Scjs static int didpipe;
89963d5659Scjs char message[100], *p;
90963d5659Scjs
91963d5659Scjs initial_pos = NULL_POSITION;
92963d5659Scjs if (filename == NULL || *filename == '\0') {
93963d5659Scjs if (curr_ac >= ac) {
94963d5659Scjs error("No current file");
95963d5659Scjs return(0);
96963d5659Scjs }
97963d5659Scjs filename = save(av[curr_ac]);
98963d5659Scjs }
99963d5659Scjs else if (strcmp(filename, "#") == 0) {
100963d5659Scjs if (*previous_file == '\0') {
101963d5659Scjs error("no previous file");
102963d5659Scjs return(0);
103963d5659Scjs }
104963d5659Scjs filename = save(previous_file);
105963d5659Scjs initial_pos = prev_pos;
106963d5659Scjs } else
107963d5659Scjs filename = save(filename);
108963d5659Scjs
109963d5659Scjs /* use standard input. */
110963d5659Scjs if (!strcmp(filename, "-")) {
111963d5659Scjs if (didpipe) {
112963d5659Scjs error("Can view standard input only once");
113963d5659Scjs return(0);
114963d5659Scjs }
115963d5659Scjs f = 0;
116963d5659Scjs }
117963d5659Scjs else if ((m = bad_file(filename, message, sizeof(message))) != NULL) {
118963d5659Scjs error(m);
119963d5659Scjs free(filename);
120963d5659Scjs return(0);
121963d5659Scjs }
122963d5659Scjs else if ((f = open(filename, O_RDONLY, 0)) < 0) {
123cad152eeSitojun (void)snprintf(message, sizeof(message), "%s: %s", filename,
124cad152eeSitojun strerror(errno));
125963d5659Scjs error(message);
126963d5659Scjs free(filename);
127963d5659Scjs return(0);
128963d5659Scjs }
129963d5659Scjs
130963d5659Scjs if (isatty(f)) {
131963d5659Scjs /*
132963d5659Scjs * Not really necessary to call this an error,
133963d5659Scjs * but if the control terminal (for commands)
134963d5659Scjs * and the input file (for data) are the same,
135963d5659Scjs * we get weird results at best.
136963d5659Scjs */
137963d5659Scjs error("Can't take input from a terminal");
138963d5659Scjs if (f > 0)
139963d5659Scjs (void)close(f);
140963d5659Scjs (void)free(filename);
141963d5659Scjs return(0);
142963d5659Scjs }
143963d5659Scjs
144963d5659Scjs /*
145963d5659Scjs * We are now committed to using the new file.
146963d5659Scjs * Close the current input file and set up to use the new one.
147963d5659Scjs */
148963d5659Scjs if (file > 0)
149963d5659Scjs (void)close(file);
150963d5659Scjs new_file = 1;
151963d5659Scjs if (previous_file != NULL)
152963d5659Scjs free(previous_file);
153963d5659Scjs previous_file = current_file;
154963d5659Scjs current_file = filename;
155963d5659Scjs pos_clear();
156963d5659Scjs prev_pos = position(TOP);
157963d5659Scjs ispipe = (f == 0);
158963d5659Scjs if (ispipe) {
159963d5659Scjs didpipe = 1;
160963d5659Scjs current_name = "stdin";
161963d5659Scjs } else
162963d5659Scjs current_name = (p = rindex(filename, '/')) ? p + 1 : filename;
163963d5659Scjs if (curr_ac >= ac)
164963d5659Scjs next_name = NULL;
165963d5659Scjs else
166963d5659Scjs next_name = av[curr_ac + 1];
167963d5659Scjs file = f;
168963d5659Scjs ch_init(cbufs, 0);
169963d5659Scjs init_mark();
170963d5659Scjs
171963d5659Scjs if (is_tty) {
172963d5659Scjs int no_display = !any_display;
173963d5659Scjs any_display = 1;
174963d5659Scjs if (no_display && errmsgs > 0) {
175963d5659Scjs /*
176963d5659Scjs * We displayed some messages on error output
177963d5659Scjs * (file descriptor 2; see error() function).
178963d5659Scjs * Before erasing the screen contents,
179963d5659Scjs * display the file name and wait for a keystroke.
180963d5659Scjs */
181963d5659Scjs error(filename);
182963d5659Scjs }
183963d5659Scjs /*
184963d5659Scjs * Indicate there is nothing displayed yet.
185963d5659Scjs */
186963d5659Scjs if (initial_pos != NULL_POSITION)
187963d5659Scjs jump_loc(initial_pos);
188963d5659Scjs clr_linenum();
189963d5659Scjs }
190963d5659Scjs return(1);
191963d5659Scjs }
192963d5659Scjs
193963d5659Scjs /*
194963d5659Scjs * Edit the next file in the command line list.
195963d5659Scjs */
196e3fbe7d2Schristos void
next_file(n)197963d5659Scjs next_file(n)
198963d5659Scjs int n;
199963d5659Scjs {
200963d5659Scjs if (curr_ac + n >= ac) {
201963d5659Scjs if (quit_at_eof || position(TOP) == NULL_POSITION)
202963d5659Scjs quit();
203963d5659Scjs error("No (N-th) next file");
204963d5659Scjs }
205963d5659Scjs else
206963d5659Scjs (void)edit(av[curr_ac += n]);
207963d5659Scjs }
208963d5659Scjs
209963d5659Scjs /*
210963d5659Scjs * Edit the previous file in the command line list.
211963d5659Scjs */
212e3fbe7d2Schristos void
prev_file(n)213963d5659Scjs prev_file(n)
214963d5659Scjs int n;
215963d5659Scjs {
216963d5659Scjs if (curr_ac - n < 0)
217963d5659Scjs error("No (N-th) previous file");
218963d5659Scjs else
219963d5659Scjs (void)edit(av[curr_ac -= n]);
220963d5659Scjs }
221963d5659Scjs
222963d5659Scjs /*
223963d5659Scjs * copy a file directly to standard output; used if stdout is not a tty.
224963d5659Scjs * the only processing is to squeeze multiple blank input lines.
225963d5659Scjs */
226e3fbe7d2Schristos static void
cat_file()227963d5659Scjs cat_file()
228963d5659Scjs {
229e3fbe7d2Schristos int c, empty;
230963d5659Scjs
231963d5659Scjs if (squeeze) {
232963d5659Scjs empty = 0;
233963d5659Scjs while ((c = ch_forw_get()) != EOI)
234963d5659Scjs if (c != '\n') {
235963d5659Scjs putchr(c);
236963d5659Scjs empty = 0;
237963d5659Scjs }
238963d5659Scjs else if (empty < 2) {
239963d5659Scjs putchr(c);
240963d5659Scjs ++empty;
241963d5659Scjs }
242963d5659Scjs }
243963d5659Scjs else while ((c = ch_forw_get()) != EOI)
244963d5659Scjs putchr(c);
245963d5659Scjs flush();
246963d5659Scjs }
247963d5659Scjs
248e3fbe7d2Schristos int
main(argc,argv)249963d5659Scjs main(argc, argv)
250963d5659Scjs int argc;
251963d5659Scjs char **argv;
252963d5659Scjs {
253963d5659Scjs int envargc, argcnt;
254*ad436ff6Sjoerg char *envargv[3];
255963d5659Scjs
256963d5659Scjs /*
257963d5659Scjs * Process command line arguments and MORE environment arguments.
258963d5659Scjs * Command line arguments override environment arguments.
259963d5659Scjs */
260e3fbe7d2Schristos if ((envargv[1] = getenv("MORE")) != NULL) {
261963d5659Scjs envargc = 2;
262963d5659Scjs envargv[0] = "more";
263963d5659Scjs envargv[2] = NULL;
264963d5659Scjs (void)option(envargc, envargv);
265963d5659Scjs }
266963d5659Scjs argcnt = option(argc, argv);
267963d5659Scjs argv += argcnt;
268963d5659Scjs argc -= argcnt;
269963d5659Scjs
270963d5659Scjs /*
271963d5659Scjs * Set up list of files to be examined.
272963d5659Scjs */
273963d5659Scjs ac = argc;
274963d5659Scjs av = argv;
275963d5659Scjs curr_ac = 0;
276963d5659Scjs
277963d5659Scjs /*
278963d5659Scjs * Set up terminal, etc.
279963d5659Scjs */
280963d5659Scjs is_tty = isatty(1);
281963d5659Scjs if (!is_tty) {
282963d5659Scjs /*
283963d5659Scjs * Output is not a tty.
284963d5659Scjs * Just copy the input file(s) to output.
285963d5659Scjs */
286963d5659Scjs if (ac < 1) {
287963d5659Scjs (void)edit("-");
288963d5659Scjs cat_file();
289963d5659Scjs } else {
290963d5659Scjs do {
291963d5659Scjs (void)edit((char *)NULL);
292963d5659Scjs if (file >= 0)
293963d5659Scjs cat_file();
294963d5659Scjs } while (++curr_ac < ac);
295963d5659Scjs }
296963d5659Scjs exit(0);
297963d5659Scjs }
298963d5659Scjs
299963d5659Scjs raw_mode(1);
300963d5659Scjs get_term();
301963d5659Scjs open_getchr();
302963d5659Scjs init();
303963d5659Scjs init_signals(1);
304963d5659Scjs
305963d5659Scjs /* select the first file to examine. */
3066a623f72Scjs if (ac < 1)
307963d5659Scjs (void)edit("-"); /* Standard input */
308963d5659Scjs else {
309963d5659Scjs /*
310963d5659Scjs * Try all the files named as command arguments.
311963d5659Scjs * We are simply looking for one which can be
312963d5659Scjs * opened without error.
313963d5659Scjs */
314963d5659Scjs do {
315963d5659Scjs (void)edit((char *)NULL);
316963d5659Scjs } while (file < 0 && ++curr_ac < ac);
317963d5659Scjs }
318963d5659Scjs
319963d5659Scjs if (file >= 0)
320963d5659Scjs commands();
321963d5659Scjs quit();
322963d5659Scjs }
323963d5659Scjs
324963d5659Scjs /*
325963d5659Scjs * Copy a string to a "safe" place
326963d5659Scjs * (that is, to a buffer allocated by malloc).
327963d5659Scjs */
328963d5659Scjs char *
save(s)329963d5659Scjs save(s)
330963d5659Scjs char *s;
331963d5659Scjs {
332e3fbe7d2Schristos char *p;
333963d5659Scjs
334cad152eeSitojun p = strdup(s);
335963d5659Scjs if (p == NULL)
336963d5659Scjs {
337963d5659Scjs error("cannot allocate memory");
338963d5659Scjs quit();
339963d5659Scjs }
340cad152eeSitojun return(p);
341963d5659Scjs }
342963d5659Scjs
343963d5659Scjs /*
344963d5659Scjs * Exit the program.
345963d5659Scjs */
346e3fbe7d2Schristos void
quit()347963d5659Scjs quit()
348963d5659Scjs {
349963d5659Scjs /*
350963d5659Scjs * Put cursor at bottom left corner, clear the line,
351963d5659Scjs * reset the terminal modes, and exit.
352963d5659Scjs */
353963d5659Scjs quitting = 1;
354963d5659Scjs lower_left();
355963d5659Scjs clear_eol();
356963d5659Scjs deinit();
357963d5659Scjs flush();
358963d5659Scjs raw_mode(0);
359963d5659Scjs exit(0);
360963d5659Scjs }
361