135209Sbostic /*
235209Sbostic * Copyright (c) 1988 Mark Nudleman
362558Sbostic * Copyright (c) 1988, 1993
462558Sbostic * Regents of the University of California. All rights reserved.
535209Sbostic *
642742Sbostic * %sccs.include.redist.c%
735209Sbostic */
835209Sbostic
935209Sbostic #ifndef lint
1035209Sbostic char copyright[] =
1135209Sbostic "@(#) Copyright (c) 1988 Mark Nudleman.\n\
1262558Sbostic @(#) Copyright (c) 1988, 1993
1362558Sbostic Regents of the University of California. All rights reserved.\n";
1435209Sbostic #endif /* not lint */
1535209Sbostic
1635209Sbostic #ifndef lint
17*62559Sbostic static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/07/93";
1835209Sbostic #endif /* not lint */
1935209Sbostic
2035209Sbostic /*
2135209Sbostic * Entry point, initialization, miscellaneous routines.
2235209Sbostic */
2335209Sbostic
2436251Sbostic #include <sys/types.h>
2536251Sbostic #include <sys/file.h>
2636251Sbostic #include <stdio.h>
2736251Sbostic #include <less.h>
2835209Sbostic
2936251Sbostic int ispipe;
3036251Sbostic int new_file;
3136251Sbostic int is_tty;
3236272Sbostic char *current_file, *previous_file, *current_name, *next_name;
3336251Sbostic off_t prev_pos;
3436251Sbostic int any_display;
3536251Sbostic int scroll;
3636251Sbostic int ac;
3736251Sbostic char **av;
3836251Sbostic int curr_ac;
3936251Sbostic int quitting;
4035209Sbostic
4135209Sbostic extern int file;
4235209Sbostic extern int cbufs;
4335209Sbostic extern int errmsgs;
4435209Sbostic
4536251Sbostic extern char *tagfile;
4635209Sbostic extern int tagoption;
4735209Sbostic
4835209Sbostic /*
4935209Sbostic * Edit a new file.
5035209Sbostic * Filename "-" means standard input.
5135209Sbostic * No filename means the "current" file, from the command line.
5235209Sbostic */
edit(filename)5335209Sbostic edit(filename)
5435209Sbostic register char *filename;
5535209Sbostic {
5636251Sbostic extern int errno;
5735209Sbostic register int f;
5835209Sbostic register char *m;
5936251Sbostic off_t initial_pos, position();
6035209Sbostic static int didpipe;
6136251Sbostic char message[100], *p;
6236251Sbostic char *rindex(), *strerror(), *save(), *bad_file();
6335209Sbostic
6435209Sbostic initial_pos = NULL_POSITION;
6536251Sbostic if (filename == NULL || *filename == '\0') {
6636251Sbostic if (curr_ac >= ac) {
6735209Sbostic error("No current file");
6836251Sbostic return(0);
6935209Sbostic }
7035209Sbostic filename = save(av[curr_ac]);
7136251Sbostic }
7236251Sbostic else if (strcmp(filename, "#") == 0) {
7336251Sbostic if (*previous_file == '\0') {
7435209Sbostic error("no previous file");
7536251Sbostic return(0);
7635209Sbostic }
7735209Sbostic filename = save(previous_file);
7835209Sbostic initial_pos = prev_pos;
7935209Sbostic } else
8035209Sbostic filename = save(filename);
8135209Sbostic
8236251Sbostic /* use standard input. */
8336251Sbostic if (!strcmp(filename, "-")) {
8436251Sbostic if (didpipe) {
8535209Sbostic error("Can view standard input only once");
8636251Sbostic return(0);
8735209Sbostic }
8835209Sbostic f = 0;
8936251Sbostic }
9036251Sbostic else if ((m = bad_file(filename, message, sizeof(message))) != NULL) {
9135209Sbostic error(m);
9235209Sbostic free(filename);
9336251Sbostic return(0);
9436251Sbostic }
9536251Sbostic else if ((f = open(filename, O_RDONLY, 0)) < 0) {
9636251Sbostic (void)sprintf(message, "%s: %s", filename, strerror(errno));
9736251Sbostic error(message);
9835209Sbostic free(filename);
9936251Sbostic return(0);
10035209Sbostic }
10135209Sbostic
10236251Sbostic if (isatty(f)) {
10335209Sbostic /*
10435209Sbostic * Not really necessary to call this an error,
10535209Sbostic * but if the control terminal (for commands)
10635209Sbostic * and the input file (for data) are the same,
10735209Sbostic * we get weird results at best.
10835209Sbostic */
10935209Sbostic error("Can't take input from a terminal");
11035209Sbostic if (f > 0)
11136251Sbostic (void)close(f);
11236251Sbostic (void)free(filename);
11336251Sbostic return(0);
11435209Sbostic }
11535209Sbostic
11635209Sbostic /*
11735209Sbostic * We are now committed to using the new file.
11835209Sbostic * Close the current input file and set up to use the new one.
11935209Sbostic */
12035209Sbostic if (file > 0)
12136251Sbostic (void)close(file);
12235209Sbostic new_file = 1;
12335209Sbostic if (previous_file != NULL)
12435209Sbostic free(previous_file);
12535209Sbostic previous_file = current_file;
12635209Sbostic current_file = filename;
12740239Sdonn pos_clear();
12835209Sbostic prev_pos = position(TOP);
12935209Sbostic ispipe = (f == 0);
13036251Sbostic if (ispipe) {
13135209Sbostic didpipe = 1;
13236251Sbostic current_name = "stdin";
13336251Sbostic } else
13436251Sbostic current_name = (p = rindex(filename, '/')) ? p + 1 : filename;
13536272Sbostic if (curr_ac >= ac)
13636272Sbostic next_name = NULL;
13736272Sbostic else
13836272Sbostic next_name = av[curr_ac + 1];
13935209Sbostic file = f;
14035209Sbostic ch_init(cbufs, 0);
14135209Sbostic init_mark();
14235209Sbostic
14336251Sbostic if (is_tty) {
14435209Sbostic int no_display = !any_display;
14535209Sbostic any_display = 1;
14636251Sbostic if (no_display && errmsgs > 0) {
14735209Sbostic /*
14835209Sbostic * We displayed some messages on error output
14935209Sbostic * (file descriptor 2; see error() function).
15035209Sbostic * Before erasing the screen contents,
15135209Sbostic * display the file name and wait for a keystroke.
15235209Sbostic */
15335209Sbostic error(filename);
15435209Sbostic }
15535209Sbostic /*
15635209Sbostic * Indicate there is nothing displayed yet.
15735209Sbostic */
15835209Sbostic if (initial_pos != NULL_POSITION)
15935209Sbostic jump_loc(initial_pos);
16035209Sbostic clr_linenum();
16135209Sbostic }
16236251Sbostic return(1);
16335209Sbostic }
16435209Sbostic
16535209Sbostic /*
16635209Sbostic * Edit the next file in the command line list.
16735209Sbostic */
next_file(n)16835209Sbostic next_file(n)
16935209Sbostic int n;
17035209Sbostic {
17136251Sbostic extern int quit_at_eof;
17236251Sbostic off_t position();
17336251Sbostic
17436251Sbostic if (curr_ac + n >= ac) {
17536251Sbostic if (quit_at_eof || position(TOP) == NULL_POSITION)
17635209Sbostic quit();
17735209Sbostic error("No (N-th) next file");
17836251Sbostic }
17936251Sbostic else
18036251Sbostic (void)edit(av[curr_ac += n]);
18135209Sbostic }
18235209Sbostic
18335209Sbostic /*
18435209Sbostic * Edit the previous file in the command line list.
18535209Sbostic */
prev_file(n)18635209Sbostic prev_file(n)
18735209Sbostic int n;
18835209Sbostic {
18935209Sbostic if (curr_ac - n < 0)
19035209Sbostic error("No (N-th) previous file");
19135209Sbostic else
19236251Sbostic (void)edit(av[curr_ac -= n]);
19335209Sbostic }
19435209Sbostic
19535209Sbostic /*
19636267Sbostic * copy a file directly to standard output; used if stdout is not a tty.
19736267Sbostic * the only processing is to squeeze multiple blank input lines.
19835209Sbostic */
19936251Sbostic static
cat_file()20035209Sbostic cat_file()
20135209Sbostic {
20236267Sbostic extern int squeeze;
20336267Sbostic register int c, empty;
20435209Sbostic
20536267Sbostic if (squeeze) {
20636267Sbostic empty = 0;
20736267Sbostic while ((c = ch_forw_get()) != EOI)
20836267Sbostic if (c != '\n') {
20936267Sbostic putchr(c);
21036267Sbostic empty = 0;
21136267Sbostic }
21236267Sbostic else if (empty < 2) {
21336267Sbostic putchr(c);
21436267Sbostic ++empty;
21536267Sbostic }
21636267Sbostic }
21736267Sbostic else while ((c = ch_forw_get()) != EOI)
21835209Sbostic putchr(c);
21935209Sbostic flush();
22035209Sbostic }
22135209Sbostic
main(argc,argv)22235209Sbostic main(argc, argv)
22335209Sbostic int argc;
22436251Sbostic char **argv;
22535209Sbostic {
22636251Sbostic int envargc, argcnt;
22736251Sbostic char *envargv[2], *getenv();
22835209Sbostic
22935209Sbostic /*
23036251Sbostic * Process command line arguments and MORE environment arguments.
23135209Sbostic * Command line arguments override environment arguments.
23235209Sbostic */
23336251Sbostic if (envargv[1] = getenv("MORE")) {
23436251Sbostic envargc = 2;
23536251Sbostic envargv[0] = "more";
23636251Sbostic envargv[2] = NULL;
23736251Sbostic (void)option(envargc, envargv);
23836251Sbostic }
23936251Sbostic argcnt = option(argc, argv);
24036251Sbostic argv += argcnt;
24136251Sbostic argc -= argcnt;
24235209Sbostic
24335209Sbostic /*
24435209Sbostic * Set up list of files to be examined.
24535209Sbostic */
24635209Sbostic ac = argc;
24735209Sbostic av = argv;
24835209Sbostic curr_ac = 0;
24935209Sbostic
25035209Sbostic /*
25135209Sbostic * Set up terminal, etc.
25235209Sbostic */
25335209Sbostic is_tty = isatty(1);
25436251Sbostic if (!is_tty) {
25535209Sbostic /*
25635209Sbostic * Output is not a tty.
25735209Sbostic * Just copy the input file(s) to output.
25835209Sbostic */
25936251Sbostic if (ac < 1) {
26036251Sbostic (void)edit("-");
26135209Sbostic cat_file();
26236251Sbostic } else {
26336251Sbostic do {
26436251Sbostic (void)edit((char *)NULL);
26535209Sbostic if (file >= 0)
26635209Sbostic cat_file();
26735209Sbostic } while (++curr_ac < ac);
26835209Sbostic }
26935209Sbostic exit(0);
27035209Sbostic }
27135209Sbostic
27235209Sbostic raw_mode(1);
27335209Sbostic get_term();
27435209Sbostic open_getchr();
27535209Sbostic init();
27635209Sbostic init_signals(1);
27735209Sbostic
27836251Sbostic /* select the first file to examine. */
27936251Sbostic if (tagoption) {
28035209Sbostic /*
28136251Sbostic * A -t option was given; edit the file selected by the
28236251Sbostic * "tags" search, and search for the proper line in the file.
28335209Sbostic */
28436251Sbostic if (!tagfile || !edit(tagfile) || tagsearch())
28535209Sbostic quit();
28636251Sbostic }
28736251Sbostic else if (ac < 1)
28836251Sbostic (void)edit("-"); /* Standard input */
28936251Sbostic else {
29035209Sbostic /*
29135209Sbostic * Try all the files named as command arguments.
29235209Sbostic * We are simply looking for one which can be
29335209Sbostic * opened without error.
29435209Sbostic */
29536251Sbostic do {
29636251Sbostic (void)edit((char *)NULL);
29735209Sbostic } while (file < 0 && ++curr_ac < ac);
29835209Sbostic }
29935209Sbostic
30035209Sbostic if (file >= 0)
30135209Sbostic commands();
30235209Sbostic quit();
30335209Sbostic /*NOTREACHED*/
30435209Sbostic }
30535209Sbostic
30635209Sbostic /*
30735209Sbostic * Copy a string to a "safe" place
30835245Sbostic * (that is, to a buffer allocated by malloc).
30935209Sbostic */
31036251Sbostic char *
save(s)31135209Sbostic save(s)
31235209Sbostic char *s;
31335209Sbostic {
31435245Sbostic char *p, *strcpy(), *malloc();
31535209Sbostic
31635245Sbostic p = malloc((u_int)strlen(s)+1);
31735209Sbostic if (p == NULL)
31835209Sbostic {
31935209Sbostic error("cannot allocate memory");
32035209Sbostic quit();
32135209Sbostic }
32235245Sbostic return(strcpy(p, s));
32335209Sbostic }
32435209Sbostic
32535209Sbostic /*
32635209Sbostic * Exit the program.
32735209Sbostic */
quit()32835209Sbostic quit()
32935209Sbostic {
33035209Sbostic /*
33135209Sbostic * Put cursor at bottom left corner, clear the line,
33235209Sbostic * reset the terminal modes, and exit.
33335209Sbostic */
33435209Sbostic quitting = 1;
33535209Sbostic lower_left();
33635209Sbostic clear_eol();
33735209Sbostic deinit();
33835209Sbostic flush();
33935209Sbostic raw_mode(0);
34035209Sbostic exit(0);
34135209Sbostic }
342