119304Speter/*-
219304Speter * Copyright (c) 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
1319304Speterstatic const char sccsid[] = "@(#)cl_main.c	10.36 (Berkeley) 10/14/96";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
1819304Speter
1919304Speter#include <bitstring.h>
2019304Speter#include <curses.h>
2119304Speter#include <errno.h>
2219304Speter#include <fcntl.h>
2319304Speter#include <signal.h>
2419304Speter#include <stdio.h>
2519304Speter#include <stdlib.h>
2619304Speter#include <string.h>
2719304Speter#include <termios.h>
2819304Speter#include <unistd.h>
2919304Speter
3019304Speter#include "../common/common.h"
3119304Speter#ifdef RUNNING_IP
3219304Speter#include "../ip/ip.h"
3319304Speter#endif
3419304Speter#include "cl.h"
3519304Speter#include "pathnames.h"
3619304Speter
3719304SpeterGS *__global_list;				/* GLOBAL: List of screens. */
3819304Spetersigset_t __sigblockset;				/* GLOBAL: Blocked signals. */
3919304Speter
4019304Speterstatic void	   cl_func_std __P((GS *));
4119304Speterstatic CL_PRIVATE *cl_init __P((GS *));
4219304Speterstatic GS	  *gs_init __P((char *));
4319304Speterstatic void	   perr __P((char *, char *));
4419304Speterstatic int	   setsig __P((int, struct sigaction *, void (*)(int)));
4519304Speterstatic void	   sig_end __P((GS *));
4619304Speterstatic void	   term_init __P((char *, char *));
4719304Speter
4819304Speter/*
4919304Speter * main --
5019304Speter *	This is the main loop for the standalone curses editor.
5119304Speter */
5219304Speterint
5319304Spetermain(argc, argv)
5419304Speter	int argc;
5519304Speter	char *argv[];
5619304Speter{
5719304Speter	static int reenter;
5819304Speter	CL_PRIVATE *clp;
5919304Speter	GS *gp;
6019304Speter	size_t rows, cols;
6119304Speter	int rval;
6219304Speter	char *ip_arg, **p_av, **t_av, *ttype;
6319304Speter
6419304Speter	/* If loaded at 0 and jumping through a NULL pointer, stop. */
6519304Speter	if (reenter++)
6619304Speter		abort();
6719304Speter
6819304Speter	/* Create and initialize the global structure. */
6919304Speter	__global_list = gp = gs_init(argv[0]);
7019304Speter
7119304Speter	/*
7219304Speter	 * Strip out any arguments that vi isn't going to understand.  There's
7319304Speter	 * no way to portably call getopt twice, so arguments parsed here must
7419304Speter	 * be removed from the argument list.
7519304Speter	 */
7619304Speter#ifdef RUNNING_IP
7719304Speter	ip_arg = NULL;
7819304Speter	for (p_av = t_av = argv;;) {
7919304Speter		if (*t_av == NULL) {
8019304Speter			*p_av = NULL;
8119304Speter			break;
8219304Speter		}
8319304Speter		if (!strcmp(*t_av, "--")) {
8419304Speter			while ((*p_av++ = *t_av++) != NULL);
8519304Speter			break;
8619304Speter		}
8719304Speter		if (!memcmp(*t_av, "-I", sizeof("-I") - 1)) {
8819304Speter			if (t_av[0][2] != '\0') {
8919304Speter				ip_arg = t_av[0] + 2;
9019304Speter				++t_av;
9119304Speter				--argc;
9219304Speter				continue;
9319304Speter			}
9419304Speter			if (t_av[1] != NULL) {
9519304Speter				ip_arg = t_av[1];
9619304Speter				t_av += 2;
9719304Speter				argc -= 2;
9819304Speter				continue;
9919304Speter			}
10019304Speter		}
10119304Speter		*p_av++ = *t_av++;
10219304Speter	}
10319304Speter
10419304Speter	/*
10519304Speter	 * If we're being called as an editor library, we're done here, we
10619304Speter	 * get loaded with the curses screen, we don't share much code.
10719304Speter	 */
10819304Speter	if (ip_arg != NULL)
10919304Speter		exit (ip_main(argc, argv, gp, ip_arg));
11019304Speter#else
11119304Speter	ip_arg = argv[0];
11219304Speter#endif
11319304Speter
11419304Speter	/* Create and initialize the CL_PRIVATE structure. */
11519304Speter	clp = cl_init(gp);
11619304Speter
11719304Speter	/*
11819304Speter	 * Initialize the terminal information.
11919304Speter	 *
12019304Speter	 * We have to know what terminal it is from the start, since we may
12119304Speter	 * have to use termcap/terminfo to find out how big the screen is.
12219304Speter	 */
12319304Speter	if ((ttype = getenv("TERM")) == NULL)
12419304Speter		ttype = "unknown";
12519304Speter	term_init(gp->progname, ttype);
12619304Speter
12719304Speter	/* Add the terminal type to the global structure. */
12819304Speter	if ((OG_D_STR(gp, GO_TERM) =
12919304Speter	    OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL)
13019304Speter		perr(gp->progname, NULL);
13119304Speter
13219304Speter	/* Figure out how big the screen is. */
13319304Speter	if (cl_ssize(NULL, 0, &rows, &cols, NULL))
13419304Speter		exit (1);
13519304Speter
13619304Speter	/* Add the rows and columns to the global structure. */
13719304Speter	OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows;
13819304Speter	OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols;
13919304Speter
14019304Speter	/* Ex wants stdout to be buffered. */
14119304Speter	(void)setvbuf(stdout, NULL, _IOFBF, 0);
14219304Speter
14319304Speter	/* Start catching signals. */
14419304Speter	if (sig_init(gp, NULL))
14519304Speter		exit (1);
14619304Speter
14719304Speter	/* Run ex/vi. */
14819304Speter	rval = editor(gp, argc, argv);
14919304Speter
15019304Speter	/* Clean up signals. */
15119304Speter	sig_end(gp);
15219304Speter
15319304Speter	/* Clean up the terminal. */
15419304Speter	(void)cl_quit(gp);
15519304Speter
15619304Speter	/*
15719304Speter	 * XXX
15819304Speter	 * Reset the O_MESG option.
15919304Speter	 */
16019304Speter	if (clp->tgw != TGW_UNKNOWN)
16119304Speter		(void)cl_omesg(NULL, clp, clp->tgw == TGW_SET);
16219304Speter
16319304Speter	/*
16419304Speter	 * XXX
16519304Speter	 * Reset the X11 xterm icon/window name.
16619304Speter	 */
16719304Speter	if (F_ISSET(clp, CL_RENAME)) {
16819304Speter		(void)printf(XTERM_RENAME, ttype);
16919304Speter		(void)fflush(stdout);
17019304Speter	}
17119304Speter
17219304Speter	/* If a killer signal arrived, pretend we just got it. */
17319304Speter	if (clp->killersig) {
17419304Speter		(void)signal(clp->killersig, SIG_DFL);
17519304Speter		(void)kill(getpid(), clp->killersig);
17619304Speter		/* NOTREACHED */
17719304Speter	}
17819304Speter
17919304Speter	/* Free the global and CL private areas. */
18019304Speter#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
18119304Speter	free(clp);
18219304Speter	free(gp);
18319304Speter#endif
18419304Speter
18519304Speter	exit (rval);
18619304Speter}
18719304Speter
18819304Speter/*
18919304Speter * gs_init --
19019304Speter *	Create and partially initialize the GS structure.
19119304Speter */
19219304Speterstatic GS *
19319304Spetergs_init(name)
19419304Speter	char *name;
19519304Speter{
19619304Speter	CL_PRIVATE *clp;
19719304Speter	GS *gp;
19819304Speter	char *p;
19919304Speter
20019304Speter	/* Figure out what our name is. */
20119304Speter	if ((p = strrchr(name, '/')) != NULL)
20219304Speter		name = p + 1;
20319304Speter
20419304Speter	/* Allocate the global structure. */
20519304Speter	CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS));
20619304Speter	if (gp == NULL)
20719304Speter		perr(name, NULL);
20819304Speter
20919304Speter
21019304Speter	gp->progname = name;
21119304Speter	return (gp);
21219304Speter}
21319304Speter
21419304Speter/*
21519304Speter * cl_init --
21619304Speter *	Create and partially initialize the CL structure.
21719304Speter */
21819304Speterstatic CL_PRIVATE *
21919304Spetercl_init(gp)
22019304Speter	GS *gp;
22119304Speter{
22219304Speter	CL_PRIVATE *clp;
22319304Speter	int fd;
22419304Speter
22519304Speter	/* Allocate the CL private structure. */
22619304Speter	CALLOC_NOMSG(NULL, clp, CL_PRIVATE *, 1, sizeof(CL_PRIVATE));
22719304Speter	if (clp == NULL)
22819304Speter		perr(gp->progname, NULL);
22919304Speter	gp->cl_private = clp;
23019304Speter
23119304Speter	/*
23219304Speter	 * Set the CL_STDIN_TTY flag.  It's purpose is to avoid setting
23319304Speter	 * and resetting the tty if the input isn't from there.  We also
23419304Speter	 * use the same test to determine if we're running a script or
23519304Speter	 * not.
23619304Speter	 */
23719304Speter	if (isatty(STDIN_FILENO))
23819304Speter		F_SET(clp, CL_STDIN_TTY);
23919304Speter	else
24019304Speter		F_SET(gp, G_SCRIPTED);
24119304Speter
24219304Speter	/*
24319304Speter	 * We expect that if we've lost our controlling terminal that the
24419304Speter	 * open() (but not the tcgetattr()) will fail.
24519304Speter	 */
24619304Speter	if (F_ISSET(clp, CL_STDIN_TTY)) {
24719304Speter		if (tcgetattr(STDIN_FILENO, &clp->orig) == -1)
24819304Speter			goto tcfail;
24919304Speter	} else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
25019304Speter		if (tcgetattr(fd, &clp->orig) == -1) {
25119304Spetertcfail:			perr(gp->progname, "tcgetattr");
25219304Speter			exit (1);
25319304Speter		}
25419304Speter		(void)close(fd);
25519304Speter	}
25619304Speter
25719304Speter	/* Initialize the list of curses functions. */
25819304Speter	cl_func_std(gp);
25919304Speter
26019304Speter	return (clp);
26119304Speter}
26219304Speter
26319304Speter/*
26419304Speter * term_init --
26519304Speter *	Initialize terminal information.
26619304Speter */
26719304Speterstatic void
26819304Speterterm_init(name, ttype)
26919304Speter	char *name, *ttype;
27019304Speter{
27119304Speter	int err;
27219304Speter
27319304Speter	/* Set up the terminal database information. */
27419304Speter	setupterm(ttype, STDOUT_FILENO, &err);
27519304Speter	switch (err) {
27619304Speter	case -1:
27719304Speter		(void)fprintf(stderr,
27819304Speter		    "%s: No terminal database found\n", name);
27919304Speter		exit (1);
28019304Speter	case 0:
28119304Speter		(void)fprintf(stderr,
28219304Speter		    "%s: %s: unknown terminal type\n", name, ttype);
28319304Speter		exit (1);
28419304Speter	}
28519304Speter}
28619304Speter
28719304Speter#define	GLOBAL_CLP \
28819304Speter	CL_PRIVATE *clp = GCLP(__global_list);
28919304Speterstatic void
29019304Speterh_hup(signo)
29119304Speter	int signo;
29219304Speter{
29319304Speter	GLOBAL_CLP;
29419304Speter
29519304Speter	F_SET(clp, CL_SIGHUP);
29619304Speter	clp->killersig = SIGHUP;
29719304Speter}
29819304Speter
29919304Speterstatic void
30019304Speterh_int(signo)
30119304Speter	int signo;
30219304Speter{
30319304Speter	GLOBAL_CLP;
30419304Speter
30519304Speter	F_SET(clp, CL_SIGINT);
30619304Speter}
30719304Speter
30819304Speterstatic void
30919304Speterh_term(signo)
31019304Speter	int signo;
31119304Speter{
31219304Speter	GLOBAL_CLP;
31319304Speter
31419304Speter	F_SET(clp, CL_SIGTERM);
31519304Speter	clp->killersig = SIGTERM;
31619304Speter}
31719304Speter
31819304Speterstatic void
31919304Speterh_winch(signo)
32019304Speter	int signo;
32119304Speter{
32219304Speter	GLOBAL_CLP;
32319304Speter
32419304Speter	F_SET(clp, CL_SIGWINCH);
32519304Speter}
32619304Speter#undef	GLOBAL_CLP
32719304Speter
32819304Speter/*
32919304Speter * sig_init --
33019304Speter *	Initialize signals.
33119304Speter *
33219304Speter * PUBLIC: int sig_init __P((GS *, SCR *));
33319304Speter */
33419304Speterint
33519304Spetersig_init(gp, sp)
33619304Speter	GS *gp;
33719304Speter	SCR *sp;
33819304Speter{
33919304Speter	CL_PRIVATE *clp;
34019304Speter
34119304Speter	clp = GCLP(gp);
34219304Speter
34319304Speter	if (sp == NULL) {
34419304Speter		(void)sigemptyset(&__sigblockset);
34519304Speter		if (sigaddset(&__sigblockset, SIGHUP) ||
34619304Speter		    setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) ||
34719304Speter		    sigaddset(&__sigblockset, SIGINT) ||
34819304Speter		    setsig(SIGINT, &clp->oact[INDX_INT], h_int) ||
34919304Speter		    sigaddset(&__sigblockset, SIGTERM) ||
35019304Speter		    setsig(SIGTERM, &clp->oact[INDX_TERM], h_term)
35119304Speter#ifdef SIGWINCH
35219304Speter		    ||
35319304Speter		    sigaddset(&__sigblockset, SIGWINCH) ||
35419304Speter		    setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch)
35519304Speter#endif
35619304Speter		    ) {
35719304Speter			perr(gp->progname, NULL);
35819304Speter			return (1);
35919304Speter		}
36019304Speter	} else
36119304Speter		if (setsig(SIGHUP, NULL, h_hup) ||
36219304Speter		    setsig(SIGINT, NULL, h_int) ||
36319304Speter		    setsig(SIGTERM, NULL, h_term)
36419304Speter#ifdef SIGWINCH
36519304Speter		    ||
36619304Speter		    setsig(SIGWINCH, NULL, h_winch)
36719304Speter#endif
36819304Speter		    ) {
36919304Speter			msgq(sp, M_SYSERR, "signal-reset");
37019304Speter		}
37119304Speter	return (0);
37219304Speter}
37319304Speter
37419304Speter/*
37519304Speter * setsig --
37619304Speter *	Set a signal handler.
37719304Speter */
37819304Speterstatic int
37919304Spetersetsig(signo, oactp, handler)
38019304Speter	int signo;
38119304Speter	struct sigaction *oactp;
38219304Speter	void (*handler) __P((int));
38319304Speter{
38419304Speter	struct sigaction act;
38519304Speter
38619304Speter	/*
38719304Speter	 * Use sigaction(2), not signal(3), since we don't always want to
38819304Speter	 * restart system calls.  The example is when waiting for a command
38919304Speter	 * mode keystroke and SIGWINCH arrives.  Besides, you can't portably
39019304Speter	 * restart system calls (thanks, POSIX!).  On the other hand, you
39119304Speter	 * can't portably NOT restart system calls (thanks, Sun!).  SunOS
39219304Speter	 * used SA_INTERRUPT as their extension to NOT restart read calls.
39319304Speter	 * We sure hope nobody else used it for anything else.  Mom told me
39419304Speter	 * there'd be days like this.  She just never told me that there'd
39519304Speter	 * be so many.
39619304Speter	 */
39719304Speter	act.sa_handler = handler;
39819304Speter	sigemptyset(&act.sa_mask);
39919304Speter
40019304Speter#ifdef SA_INTERRUPT
40119304Speter	act.sa_flags = SA_INTERRUPT;
40219304Speter#else
40319304Speter	act.sa_flags = 0;
40419304Speter#endif
40519304Speter	return (sigaction(signo, &act, oactp));
40619304Speter}
40719304Speter
40819304Speter/*
40919304Speter * sig_end --
41019304Speter *	End signal setup.
41119304Speter */
41219304Speterstatic void
41319304Spetersig_end(gp)
41419304Speter	GS *gp;
41519304Speter{
41619304Speter	CL_PRIVATE *clp;
41719304Speter
41819304Speter	clp = GCLP(gp);
41919304Speter	(void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]);
42019304Speter	(void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]);
42119304Speter	(void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]);
42219304Speter#ifdef SIGWINCH
42319304Speter	(void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]);
42419304Speter#endif
42519304Speter}
42619304Speter
42719304Speter/*
42819304Speter * cl_func_std --
42919304Speter *	Initialize the standard curses functions.
43019304Speter */
43119304Speterstatic void
43219304Spetercl_func_std(gp)
43319304Speter	GS *gp;
43419304Speter{
43519304Speter	gp->scr_addstr = cl_addstr;
43619304Speter	gp->scr_attr = cl_attr;
43719304Speter	gp->scr_baud = cl_baud;
43819304Speter	gp->scr_bell = cl_bell;
43919304Speter	gp->scr_busy = NULL;
44019304Speter	gp->scr_clrtoeol = cl_clrtoeol;
44119304Speter	gp->scr_cursor = cl_cursor;
44219304Speter	gp->scr_deleteln = cl_deleteln;
44319304Speter	gp->scr_event = cl_event;
44419304Speter	gp->scr_ex_adjust = cl_ex_adjust;
44519304Speter	gp->scr_fmap = cl_fmap;
44619304Speter	gp->scr_insertln = cl_insertln;
44719304Speter	gp->scr_keyval = cl_keyval;
44819304Speter	gp->scr_move = cl_move;
44919304Speter	gp->scr_msg = NULL;
45019304Speter	gp->scr_optchange = cl_optchange;
45119304Speter	gp->scr_refresh = cl_refresh;
45219304Speter	gp->scr_rename = cl_rename;
45319304Speter	gp->scr_screen = cl_screen;
45419304Speter	gp->scr_suspend = cl_suspend;
45519304Speter	gp->scr_usage = cl_usage;
45619304Speter}
45719304Speter
45819304Speter/*
45919304Speter * perr --
46019304Speter *	Print system error.
46119304Speter */
46219304Speterstatic void
46319304Speterperr(name, msg)
46419304Speter	char *name, *msg;
46519304Speter{
46619304Speter	(void)fprintf(stderr, "%s:", name);
46719304Speter	if (msg != NULL)
46819304Speter		(void)fprintf(stderr, "%s:", msg);
46919304Speter	(void)fprintf(stderr, "%s\n", strerror(errno));
47019304Speter	exit(1);
47119304Speter}
472