/************************************************************************
 * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is	*
 * provided to you without charge, and with no warranty.  You may give	*
 * away copies of JOVE, including sources, provided that this notice is *
 * included in all the files.						*
 ************************************************************************/

/* Contains the main loop initializations.
   [TRH] moved the system dependent things to new file "tty.c" since this file
   was getting too big for my compiler (yes I should get a better compiler:-).
 */
#define NO_PROCDECL		/* kludge for teensy pdp11 compiler */

#define Extern
#include "jove.h"

RCS("$Id: jove.c,v 14.32.0.12 1994/06/24 17:55:02 tom Exp tom $")

#include "ctype.h"
#include "io.h"
#include "process.h"
#ifndef NO_PROCDECL
#include "rec.h"
#include "screen.h"
#else
#   ifdef TERMCAP
#	undef TERMCAP
#	define TERMCAP -1	/* throw out most declarations from termcap.h */
#   endif
#endif
#include "termcap.h"

#ifndef RESHAPING
#   undef SIGWINCH			/* To simplify conditional code. */
#endif

time_t		time0;			/* when jove started up */
time_t		now;			/* (about) now; updated by updmode(). */

int		errormsg ZERO;
const char	NullStr[1] ZERO;

/* Handle signals, or exit regulaurly if `code' is zero. */

sig_tp
finish(code)
register int	code;
{
	static int	Crashing ZERO,
			KeepTmps ZERO;		/* Usually we delete them. */

#ifdef LSRHS
	if (code != 0 && code != SIGHUP)
		setdump(1);
#endif
#if unix || vms
#   ifdef TERMIOS
	if (code == SIGQUIT)
		code = SIGINT;
#   endif
	if (code == SIGINT) {
		char	c;
#   ifndef kbd
		register int state = kbd(OFF);
#   endif

#   ifdef RESIGNAL
		signal(code, finish);
#   endif
		f_mess("A)bort or I)nterrupt ? ");
		read_one_char(&c);
		message(NullStr);
#   ifndef kbd
		kbd(state);
#   endif
		switch (toupper(c)) {
		case 'A':
		case 'Y':	/* for old habits' sake */
			break;
		case 'I':
			error((char *)0);
		default:
			redisplay();
			return;
		}
	}
#endif
#ifdef IPROCS
#   ifdef SIGCHLD
	signal(SIGCHLD, SIG_DFL);
#   endif
	KillProcs();
#   ifdef PIPEPROCS
	kbd_kill();
#   endif
#endif
#ifdef VARTERM
	set_tdim(0, 0);
#   ifdef SIGWINCH
	signal(SIGWINCH, SIG_DFL);
#   endif
	ttsize();		/* to let system restore default size. */
#endif
	UnsetTerm((char *)0);
	if (code != 0) {
		if (!Crashing++) {
		    /*-	lsave(); -*/	/* SyncRec() now lsave()s */
			SyncRec();
			printf("\7%s\nJOVE CRASH!! (code %d)\n", mesgbuf, code);
			if (ModBufs(1)) {
				KeepTmps++;	/* Don't delete anymore. */
				printf("\
Your buffers have been saved.\n\
Use \"jove_recover\" or \"jove -r\"\n\
to have a look at them.\n");
			} else
				printf("You didn't lose any work.\n");
		} else
			printf("\r\nYou may have lost your work!\n");
	}
	if (!KeepTmps) {
		tmpclose();
		recclose();
	}
#if !unix
	ttexit();
#endif
	flusho();
	if (code != 0) {
#if unix || vms
		if (code > 0) {
			/* Re-send ourselves the signal to die as we should. */
			signal(code, SIG_DFL);
			kill(getpid(), code);
#   ifdef HOLD_SIGS
			sigrelse(code);
#   endif
		}
#else /* !(unix || vms) */
		if (
#   ifdef SIGHUP
		    code != SIGHUP ||
#   endif
		    code != SIGTERM)
#endif /* (unix || vms) */
			abort();
	}
#ifdef PROFILING
	exit(EXIT_SUCCESS);
#else
	_exit(EXIT_SUCCESS);
#endif
}

/* Handle window change signal. */
#ifdef SIGWINCH
private int	winch_pending ZERO;

private sig_tp	winch __(( int _(sig) ));
private sig_tp
winch(sig)
{
#   ifdef RESIGNAL
	signal(sig, winch);
#   endif
	/* Since `win_reshape' reallocates, and `malloc' is generally
	   non-reentrant, so defer reshaping if we're not reading input.
	   {{TODO: sync with process input handling.}}
	   
	   Also avoid reshaping if we get a nested SIGWINCH (this cannot
	   happen anyway on BSD/Posix-style signalled systems where the
	   signal is blocked while it is handled.) */

	if (!winch_pending++) {
		if (inIOread) {
			win_reshape();
			winch_pending = NO;
		}
	}
}
#endif

#if __POSIX__
/* Strict Posix does NOT support signal(), so we have to emulate it. */
sig_tp
(*signal(sig, handler))()
int	sig;
sig_tp	(*handler)__(( int ));
{
	struct sigaction s, o;

	s.sa_handler = handler;
	sigemptyset(&s.sa_mask);
	s.sa_flags = 0;
	if(sigaction(sig, &s, &o) < 0)
		return SIG_ERR;
	return o.sa_handler;
}
#endif /* __POSIX__ */

#if unix || vms
/* A common set of signals */

Signal	SigIntQuit[] = {
	SIGINT,		SIG_IGN,
	SIGQUIT,	SIG_IGN
};

/* set a bunch of signals */

void
SetSigs(sigs, num)
register const Signal	*sigs;
register int		num;
{
	do {
		signal(sigs->sig, sigs->proc);
		sigs++;
	} while (--num);
}

/* set a bunch of signals to SIG_IGN, storing their original values */

void
GetSigs(sigs, num)
register Signal	*sigs;
register int	num;
{
	do {
		sigs->proc = signal(sigs->sig, SIG_IGN);
		sigs++;
	} while (--num);
}

#endif /* unix || vms */

#ifndef NOPROCS
DEF_STR( "i-shell", IShell, 40, V_FILENAME ) _IF(ndef NOPROCS) ZERO;
DEF_STR( "i-shell-flags", IShFlags, 16, V_STRING ) _IF(ndef NOPROCS) = "-i";
#endif

#if unix
#   ifdef JOB_CONTROL
DEF_CMD( "pause-jove", PauseJove, NO );  _IF(def JOB_CONTROL)
DEF_CMD( "suspend-jove", PauseJove, NO ) _IF(def JOB_CONTROL)
{
#ifdef IPROCS
#   ifdef PIPEPROCS
	register int state = kbd(OFF);
#   else
	sighold(SIGCHLD);
#   endif
#endif
	SyncRec();	/* just in case we decide to logout... */
	UnsetTerm(ModBufs(0) ? "[There are modified buffers]" : (char *)0);
	kill(0, SIGTSTP);
	ResetTerm();
	ClAndRedraw();
#ifdef RESHAPING
	/*
	 * We don't seem to get any SIGWINCH signals while we're stopped,
	 * (since we're taken off the current terminal's process group?),
	 * so explicitly check for any window size changes.
	 */
	win_reshape();
#endif
#ifdef IPROCS
#   ifdef PIPEPROCS
	kbd(state);
#   else
	sigrelse(SIGCHLD);
#   endif
#endif
}
#   endif

DEF_CMD( "pause-jove", Push, NO ); _IF(ndef NOPROCS)_IF(ndef JOB_CONTROL)_IF(!vms)
DEF_CMD( "push-shell", Push, NO )  _IF(ndef NOPROCS)
{
	register const char *shell;
	register int	pid;
#ifdef IPROCS
#   ifdef PIPEPROCS
	register int state = kbd(OFF);
#   else
	sighold(SIGCHLD);
#   endif
#endif
#ifdef SIGWINCH
#   ifdef HOLD_SIGS
	sighold(SIGWINCH);
#   else
	signal(SIGWINCH, SIG_DFL);
#   endif
#endif
	if ((shell = IShell) == NULL)
		shell = Shell;

	GetSigs(SigIntQuit, sizeof SigIntQuit / sizeof SigIntQuit[0]);

	if ((pid = vfork()) <= 0) {
		static const Signal sigs[] = {
			SIGTERM,	SIG_DFL,
			SIGINT, 	SIG_DFL,
			SIGQUIT,	SIG_DFL
		};
#ifdef IPROCS				/* Necessary??? */
#   ifndef PIPEPROCS
		sigrelse(SIGCHLD);
#   endif
#endif
#ifdef SIGWINCH				/* Necessary??? */
#   ifdef HOLD_SIGS
		sigrelse(SIGWINCH);
#   endif
#endif
		if (pid < 0)
#ifdef IPROCS
#   ifdef PIPEPROCS
			kbd(state),
#   endif
#endif
			complain("[Fork failed]");

		UnsetTerm(ModBufs(0) ? "[There are modified buffers]" : (char *)0);
		SetSigs(sigs, sizeof sigs / sizeof sigs[0]);
		execl(shell, basename(shell), IShFlags, (char *)0);
		exec_fail(Shell);
	}
	dowait(pid);
#ifdef IPROCS
#   ifdef PIPEPROCS
	kbd(state);
#   else
	sigrelse(SIGCHLD);
#   endif
#endif
#ifdef SIGWINCH
#   ifdef HOLD_SIGS
	sigrelse(SIGWINCH);
#   else
	signal(SIGWINCH, winch);
#   endif
#endif
	ResetTerm();
	ClAndRedraw();
	SetSigs(SigIntQuit, sizeof SigIntQuit / sizeof SigIntQuit[0]);
}
#endif /* unix */

int	this_cmd,
	last_cmd;

int	LastKeyStruck;

DEF_INT( "meta-key", MetaKey, V_CHAR|V_TTY_RESET ) ZERO;

int	InputPending ZERO;
char	*Inputp ZERO;

private int	peekbuf[10],
		*peekp = peekbuf;

#define IsPeekc()	(peekp > peekbuf)
#define GetPeekc()	(*--peekp)

Peekc()
{
	return (IsPeekc() ? GetPeekc() : -1);
}

void
Ungetc(c)
{
	if (peekp == &peekbuf[(sizeof peekbuf) - 1])
		return; 	/* Sorry, can't oblige you ... */
	*peekp++ = c;
}

int
getch()
{
	register int	c;
	extern int	ModCount;

	/*
	 * Are there any ungetc'd chars?
	 * [TRH] moved this in front to facilitate handling of
	 * 8-bit characters from .joverc. (use the macros for efficiency)
	 */
	if (IsPeekc())
		return LastKeyStruck = GetPeekc();

	/*
	 * string input?  (e.g. from .joverc)
	 */
	if (Inputp) {
		if ((c = *Inputp) != 0) {
			Inputp++;
#if (BPC == 8)
			if (c & 0200) {	/* prepend 8-bit char with QuoteChar. */
				Ungetc(c);
				return LastKeyStruck = QuoteChar;
			}
#endif
			return LastKeyStruck = _UC_(c);
		}
		Inputp = NULL;

		if (InJoverc)		/* implied newline in .joverc */
			return LastKeyStruck = '\n';
	}

	if (InJoverc)
		return EOF;	/* somethings wrong if Inputp runs out while
				   we're reading a .joverc file. */

	if (ModCount >= SyncFreq && SyncFreq) {
		ModCount = 0;
		SyncRec();
	}
	/*
	 * If we're not interactive and we're not executing a macro,
	 * we read from the terminal (i.e., getchar()).
	 * And characters only get put in macros from inside this if.
	 */
	if (Interactive || ((c = mac_getc()) < 0)) {
		/*
		 * So messages that aren't error messages don't
		 * hang around forever. Don't erase if we are asking.
		 */
		if (mesgbuf[0] && !UpdMesg && !Asking && !errormsg)
			message(NullStr);

		redisplay();

		inIOread = YES;
#ifdef SIGWINCH
		/*
		 * Handle a pending window change.
		 */
		if (winch_pending) {
			win_reshape();
			winch_pending = NO;
		}
#endif
		c = getchar();
		inIOread = NO;

#if (HIGHLIGHT)
		WUnHighLight(curwind);
#endif
		if (Defining && !Interactive)
			mac_putc(c);
	}

	add_stroke(c);
	return LastKeyStruck = c;
}

#ifndef INT_MAX
#   define INT_MAX	((int)((1<<(sizeof(int)*8-1)) - 1))
#endif

#ifndef NOPROCS
/* [TRH 4/89] this is setup by main when JOVE is used in a pipe. */
private	int	pipe_fd ZERO;
#endif

#ifdef F_COMPLETION
#   ifndef TINY
DEF_INT( "ignore-bad-file-args", IgnBadFiles, V_BOOL) _IF(def F_COMPLETION)_IF(ndef TINY) ZERO;
#   endif
#endif

private void do_cmdline __(( int _(argc), char *_(argv)[] ));
private void
do_cmdline(argc, argv)
int		argc;
register char	*argv[];
{
	register char	*arg;
	register int	nwinds = 1,
			lineno = 0,
			plus,
			view_mode = 0;
	register Buffer	*b;
#ifdef CLIOPTIONS
	int		i;
#endif

#ifndef NOPROCS
	if (pipe_fd > 0) {
		/* read piped input in Mainbuf */
		read_pipe(Mainbuf, pipe_fd, YES);
		nwinds--;
	}
#endif
	ShowVersion();
	argv++;
	while (--argc > 0) {
		arg = *argv++;

		/* [TRH] treat -x as default, +x as special (tags and errors) */

		if (!(plus = (*arg == '+')) && !(*arg == '-')) {
#ifdef ARG_EXPAND
		    for (; arg = arg_expand(arg) ; arg = NULL)
#endif
		    {
#if vms
			char	*vms2ux __(( char *_(buf), const char *_(src) ));
			char	tmp[FILESIZE];

			arg = vms2ux(tmp, arg);
#else
			FIX_FILENAME(arg);
#endif
#ifdef F_COMPLETION
#   ifndef TINY
			if (True(IgnBadFiles) && (bad_extension(arg) || isdir(arg)))
				continue;
#   endif
#endif
			minib_add(arg, nwinds|lineno);
			b = do_find(nwinds ? curwind : (Window *)0, arg, lineno);
			lineno = 0;
			if (nwinds) {
				SetABuf(curbuf);
				SetBuf(b);
				if (--nwinds)
					NextWindow();
			}
			if (view_mode) {
				b->b_minor |= View;
				view_mode--;
			}
		    }
#ifdef CLIOPTIONS
		} else if ((i = CliLookup(arg, argc, argv)) >= 0) {
			argc -= i;
			argv += i;
#endif
		} else switch (++arg, *arg++) {
		case 'd':	/* CWD handled in main() */
			--argc;
			argv++;
			break;

#ifndef CLIOPTIONS
		/* these options can be implemented using JOVEs
		   "command-line-option" command */
		case 'j':
			if (!plus)	/* "-j" Ignore .joverc in HOME */
				break;
					/* "+j <rc>" read rc file */
			if (--argc == 0)
				break;
			if (!joverc(*argv++))
				f_mess(IOerr("read", arg));
			break;

		case 'p':
			if (--argc == 0)
				break;
			FIX_FILENAME(*argv);
			SetBuf(do_find(curwind, *argv++, 0));
			exp_p = plus;
			ParseAll();
			nwinds = 0;
			break;

		case 't':	/* -t: default tagfile, +t: ask */
			--argc;
			find_tag(*argv++, plus);
			break;
#endif /* CLIOPTIONS */
		case 'v':	/* view mode, -v single +v all files */
			view_mode = (plus) ? INT_MAX : 1;
			break;

		case 'w':
			if (*arg == '\0')
				plus = 1;
			else
				plus = chr_to_int(arg, 10, NIL) - 1;
			div_wind(curwind, plus);
			nwinds += plus;
			break;

		case '\0':	/* '-': go to end of buffer */
			lineno = INT_MAX;
			/* can't use -1 since that would position to EOF-1 */
			break;

		default:
			if (isdigit(*--arg)) {
				/* +N: go to line N */
				/* -N: go to line (EOF - N) */
				lineno = chr_to_int(arg, 10, 0);
				if (!plus)
					lineno = -lineno;
			}
			else {
				rbell();
				message(NullStr);
				PutErrInBuf("*CLI errors*", --arg, 0, "[Unknown option]");
			}
			break;
		}
	}
#ifdef CLIOPTIONS
	CliDelete();
#endif
	if (lineno)
		to_line(lineno);
}

private void do_err __(( int _(error), const char *_(fmt), va_list _(ap) ));
private void
do_err(error, fmt, ap)
const char	*fmt;
va_list		ap;
{
	register const char	*f;

	if (f = fmt) {
		format(mesgbuf, sizeof mesgbuf, f, ap);
		updmesg();
	}
	va_end(ap);
	rbell();
	jump_env(error);
}

/* VARARGS1 */
void
DEFVARG(error, (const char *fmt, ...),
	       (fmt, va_alist)
	const char	*fmt;)
{
	va_register va_list	ap;

	va_begin(ap, fmt);
	do_err(ERROR, fmt, ap);
}

/* VARARGS1 */
void
DEFVARG(complain, (const char *fmt, ...),
		  (fmt, va_alist)
	const char	*fmt;)
{
	va_register va_list	ap;

	va_begin(ap, fmt);
	do_err(COMPLAIN, fmt, ap);
}

/* VARARGS1 */

void
DEFVARG(confirm, (const char *fmt, ...),
		 (fmt, va_alist)
	const char	*fmt;)
{
	va_register va_list	ap;
	VA_INIT_PROPAGATE

	rbell();
	va_begin(ap, fmt);
	if (yes_or_no_p('N', VA_PROPAGATE(fmt, ap)) == NO) {
		va_end(ap);
		jump_env(COMPLAIN);
	}
	va_end(ap);
}

private void check_mods __(( void ));
private void
check_mods()
{
	register const char
		*leave_anyway = "Some %s haven't been saved; leave anyway? ";

	if (ModMacs())
		confirm(leave_anyway, "MACROS");
	if (ModBufs(0))
		confirm(leave_anyway, "buffers");
}

DEF_CMD( "quick-exit", QuickExit, NO )
{
	put_bufs((exp_p & YES), YES);
	/* Kludge. Avoid update of mode line (that clobbers the file name
	   list) when asking to leave or to kill i-processes. */
	UpdModLine = NO;
	check_mods();
	finish(0);
}

DEF_CMD( "exit-jove", Leave, NO )
{
	jump_env(QUIT);
}

private jmp_buf	first_env;
jmp_buf *mainjmp = &first_env;

private int	iniargc;	/* main sets these for DoKeys() */
private char	**iniargv;

private void DoKeys __(( void ));
private void
DoKeys()
{
	register int	c;
	Savejmp		savejmp;

	switch (push_env(savejmp)) {
	case 0:
		if (c = iniargc) {
			iniargc = 0;
			do_cmdline(c, iniargv);
		}
		break;

	case QUIT:
		if (RecDepth == 0)
			check_mods();
		pop_env(savejmp);
		return;

	case ERROR:
		getDOT();	/* God knows what state linebuf was in */

	case COMPLAIN:
		gc_openfiles(); /* close any files we left open */
		fix_macros();
		errormsg++;
		Asking = 0;
		if (!in_macro()) {	/* don't redisplay if we catch error */
			curwind->w_bufp = curbuf;
			redisplay();
		}
		break;
	}

	this_cmd = last_cmd = 0;

	for (;;) {
		if (this_cmd != ARG_CMD) {
			exp = 1;
			exp_p = NO;
			last_cmd = this_cmd;
			init_strokes();
		}
		if ((c = getch()) >= 0)
			dispatch(c);
	}
}

int	RecDepth ZERO;

DEF_CMD( "recursive-edit", Recur, NO )
{
	register Buffer	*cb = curwind->w_bufp;
	register Mark	*m;
	register char	*bname;
	register int	o_Interactive = Interactive;

	SetBuf(cb);		/* if Asking, curbuf != curwind->w_bufp */
	Asking = NO;

	bname = copystr(cb->b_name);
	m = MakeMark(cb->b_dot, cb->b_char, FLOATER);

	if (exp_p)
		Interactive++;	/* Force interactive mode */
	RecDepth++;
	updmodline();
	DoKeys();
	RecDepth--;
	updmodline();
	Interactive = o_Interactive;
	if (!buf_exists(bname))		/* [TRH] if buffer is deleted, */
		m = NULL;		/* this mark is gone too... */
	SetBuf(do_select(curwind, bname));
	free(bname);
	if (m) {
		if (exp_p == NO)
			ToMark(m);
		DelMark(m);
	}
}

#ifndef ExecNow
void
ExecNow(cp)
register const data_obj	*cp;
{
	if ((cp->Type & TYPEMASK) == MACRO) {
		/* Immediate macro execution need some attention. */
		register int	o_InJoverc = InJoverc;
		register char	*o_Inputp = Inputp;
		char		o_mesgbuf[sizeof mesgbuf];

		strcpy(o_mesgbuf, mesgbuf);
		InJoverc = 0;
		Inputp = NULL;
		((Macro *) cp)->Type |= IMMEDIATE;
		do_macro((Macro *) cp);
		RecDepth++;
		DoKeys();
		RecDepth--;
		InJoverc = o_InJoverc;
		Inputp = o_Inputp;
		strcpy(mesgbuf, o_mesgbuf);
	}
	else
		ExecCmd(cp);
}
#endif /* ExecNow */

private char **scanvec __(( char **_(args), const char *_(str) ));
private char **
scanvec(args, str)
register char		**args;
register const char	*str;
{
	while (*args) {
		if (strcmp(str, *args) == 0)
			return args;
		args++;
	}
	return NULL;
}

/* chkmail() returns nonzero if there is new mail since the
   last time we checked. */

#ifdef MAIL

DEF_INT( "mail-check-frequency", MailInt, V_BASE10 ) _IF(def MAIL) = 60;
	/* check no more often than 60 seconds */
# if unix
#   ifndef MAILBOX_FMT
#	if hpux
#	    define MAILBOX_FMT	"/usr/mail/%s"
#	else
#	    define MAILBOX_FMT	"/usr/spool/mail/%s"
#	endif
#   endif
#   ifndef LOGIN_NAME
#	ifdef SYSV
#	    define LOGIN_NAME	"LOGNAME"
#	else
#	    define LOGIN_NAME	"USER"
#	endif
#   endif

DEF_STR( "mailbox", Mailbox,  128, V_FILENAME ) _IF(def MAIL)_IF( unix)_IF(def PRIVATE) ZERO;
	/* initialized in main */

int
chkmail(force)
{
	static time_t	last_chk ZERO;
	static int	last_val ZERO;
	static off_t	last_size ZERO;

	if (force || (now >= last_chk + MailInt)) {
		struct stat	stbuf;
		register int	old_val = last_val;
		register off_t	old_size = last_size;

		last_chk = now;
		last_val = FALSE;
		last_size = 0;
		if (stat(Mailbox, &stbuf) == 0) {
			if ((stbuf.st_mtime > time0) &&
			    (stbuf.st_size > old_size) &&
			    (stbuf.st_mtime + 5 > stbuf.st_atime)) {
				last_val++;
				if (!old_val)
					dobell(3);
			}
			last_size = stbuf.st_size;
		}
	}
	return last_val;
}
# endif /* unix */
#endif /* MAIL */

DEF_INT( "update-time-frequency", UpdFreq, V_BASE10|V_MODELINE ) = 30;

int	inIOread ZERO;

sig_tp
updmode()
{
	register unsigned	freq;
#ifdef RESIGNAL
	signal(SIGALRM, (sig_tp (*)__((int))) updmode);
#endif
	updmodline();
	if (freq = UpdFreq)
		freq -= (unsigned)(time(&now) % freq);
	/* NOTE: `now' should be updated BEFORE redisplay().
	   Also note that this assumes that `time_t' is a type that we can
	   do arithmetic with, AND that it is an integral number of seconds.
	   These assumptions hold on all Unix systems I know of (and vms, and
	   DOS/Tos), and are guaranteed by Posix.1 (but NOT by ANSI C.) */
	if (inIOread)
		redisplay();
	/* {In order to be completely accurate, we should re-call time() and
	    calculate `freq' AFTER the redisplay since that could in principle
	    take a long time.  In practice, however, most of the time it only
	    has to update the current time in the modeline, which is fast
	    enough.  (all this to save a single time() system call...) */
	alarm(freq);
}

void
main(argc, argv)
register char	*argv[];
{
	extern int		ModCount;
	register const char	*cp;
	char			ttbuf[TTBUFSIZ];

#ifndef BIG
	char	s_iobuff[BLKSIZ],
		s_genbuf[LBSIZE];

	/* The way I look at it, there ain't no way I is gonna run
	   out of stack space UNLESS I have some kind of infinite
	   recursive bug.  So why use up some valuable memory, when
	   there is plenty of space on the stack?  (This only matters
	   on wimpy pdp11's, of course.) */

	iobuff = s_iobuff;
	genbuf = s_genbuf;
#endif
	printf("\r[Setting up...] ");	/* reassurance */

	iniargc = argc;
	iniargv = argv;

	signal(SIGALRM, SIG_IGN);	/* for now... */

	if (setjmp(*mainjmp)) {
		printf("\rAck! I can't deal with error \"%s\" now.\r\n", mesgbuf);
		finish(0);
	}
#ifdef FLAGS_LOWERCASE
	{
		/*
		 * some shells (esp. Atari ST 1.0 desktop) convert arguments to
		 * upper case, so we convert it back.  Options are handled here
		 * (for scanvec), file names are handled in UNIXcmd_line.  We
		 * cannot do it all here since for instance "-t tag" should not
		 * be modified.  {{Note that the lowercase conversion of file
		 * names is independent of this compile-time option since (on
		 * DOS) file names are case insignificant.}}
		 */
		register char	**argp = argv;

		while (*argp) {
			if (**argp == '-' || **argp == '+')
				FIX_FILENAME(*argp);
			argp++;
		}
	}
#endif
#ifndef NOPROCS
	/* [TRH] handle piped input */
	if (!isatty(0)) {
		pipe_fd = dup(0);
		close(0);
#   ifdef ATARIST
		dup2(-1, 0);	/* sigh... */
#   else
		open(DevTty, O_RDONLY);
#   endif
	}
#endif
	d_cache_init(); 	/* initialize the disk buffer cache */
	do_sgtty();		/* [TRH] need ospeed for setup decisions */
	getTERM();		/* Get terminal. */
	ttsize();
	make_scr();
	winit();		/* Initialize Window */
	SetBuf(do_select(curwind, Mainbuf));

	if ((HomeDir = getenv("HOME")) == NULL)
#if unix
		HomeDir = Root;
#else
		HomeDir = Home;
#endif
	HomeLen = strlen(HomeDir);
#if !unix
	dfollow(HomeDir, ttbuf);	/* normalize dir.sep. */
	if (ttbuf[HomeLen-1] == SLASH)
		ttbuf[--HomeLen] = '\0';
	strcpy(HomeDir, ttbuf);
#   if !vms
	if ((cp = getenv("TMP")) || (cp = getenv("TMPDIR")))
		PathParse(cp, TmpFilePath);

	if ((cp = getenv("JOVEDIR")) && *cp) {	/* patch libdir */
#		define REPLACE_DIR(d,f) \
			PathParse(make_filename(ttbuf, d, basename(f)), f)
		REPLACE_DIR(cp, SystemRc);
		REPLACE_DIR(cp, CmdDb);
		REPLACE_DIR(cp, Recover);
	}
#	ifdef ATARIST
	if ((cp = getenv("PATH")) == NULL || strlen(cp) < 4) {
		/* supply a more meaningful PATH than the desktop does. */
		extern char Path[]; /* from tune.c */
		putenv(Path);
	}
#	endif /* ATARIST */
#   endif /* !vms */
#endif /* !unix */

	settout(ttbuf);		/* buffered stdout */

#ifdef CHDIR
	{
		register char	**argp;

		if ((((argp = scanvec(argv, "-d")) == NULL ||
		      (cp = argp[1], chdir(cp) != 0))
#   if unix
#	ifndef cmp_ino
		     && (((cp = getenv("CWD")) == NULL &&
			  (cp = getenv("PWD")) == NULL) ||
			 !cmp_ino(cp, "."))
#	endif
#   endif
		     ) || (!ISABSPATH(cp)))
			cp = getwd(genbuf);
		setCWD(cp);
	}
#endif
	if (getenv("METAKEY"))
		MetaKey = ESC;
#ifndef NOPROCS
	if (cp = getenv("SHELL"))
		Shell = (char *) cp;
	IShell = getenv("ESHELL");
	/* ESHELL instead of ISHELL for GNUemacs compatibility. */
#endif
#ifdef MAIL
#   if unix
	if ((cp = getenv("MAIL")) == NULL) {
		if ((cp = getenv(LOGIN_NAME)) == NULL)
			cp = basename(HomeDir);
		cp = copystr(sprint(MAILBOX_FMT, cp));
	}
	Mailbox = (char *) cp;
#   endif
#endif
#ifdef RESHAPING
	RMargin = CO - 2;
#endif
	joverc(SystemRc);
	if (!scanvec(argv, "-j")) {
		joverc(JoveRc);			/* in HOME dir. */
		if (!samefile(HomeDir, pwd()))	/* avoid reading it twice */
#		define CWD_JoveRc	(JoveRc + 2)	/* skip "~/" */
			joverc(CWD_JoveRc);	/* in CURRENT dir. */
	}
#ifndef FULLRECOVER
	if (scanvec(argv, "-r")) {  /* AFTER joverc is read (for temp file) */
#   if unix
		execl(Recover, "jove_recover", "-d", TmpFilePath, (char *)0);
		exec_fail(Recover);
#   else
		sprintf(genbuf, "%s -d %s", Recover, TmpFilePath);
		_exit(system(genbuf));
#   endif /* unix */
	}
#endif /* FULLRECOVER */
#ifdef CHDIR_EXT
	dirs_init();		/* AFTER joverc is read (for "dirs-unique") */
#endif

	ModCount = 0;		/* don't count modifications from .joverc */
	ResetTerm();		/* initialize terminal (after ~/.joverc) */

	/* setup signals */
#if unix || vms
    {
	static const Signal sigs[] = {
#   ifdef SIGHUP
		SIGHUP,		finish,
#   endif
		SIGINT,		finish,
#   ifdef SIGQUIT
		SIGQUIT,	finish,
#   endif
#   ifdef SIGBUS
		SIGBUS,		finish,
#   endif
#   ifdef SIGSEGV
		SIGSEGV,	finish,
#   endif
#   ifdef SIGPIPE
		SIGPIPE,	finish,
#   endif
#   ifdef SIGWINCH
		SIGWINCH,	winch,
#   endif
#   ifdef SIGALRM
		SIGALRM,	(sig_tp (*)__((int))) updmode,
#   endif
		SIGTERM,	finish
	};
	SetSigs(sigs, sizeof sigs / sizeof sigs[0]);
    }
#else /* !(unix || vms) */
	/* for Atari/MSDOS we only emulate SIGALRM and SIGINT (see atari_st.c) */
	signal(SIGINT, finish);
	signal(SIGALRM, (sig_tp (*)__((int))) updmode);
#endif /* unix */

#ifdef IPROCS
	pinit();	/* Pipes/process initialization--AFTER signal setup. */
#endif
	/* set things up to update the modeline every UpdFreq seconds */
	updmode();
	time0 = now;	/* obtained in updmode(). */

	ClAndRedraw();	/* start the redisplay process. */
	DoKeys();
	finish(0);
}

/*======================================================================
 * $Log: jove.c,v $
 * Revision 14.32.0.12  1994/06/24  17:55:02  tom
 *  (do_cmdline): fix name of scratch buffer.
 *
 * Revision 14.32.0.10  1994/04/22  18:24:23  tom
 * (error,complain,confirm): use `va_register va_list'.
 *
 * Revision 14.32.0.9  1994/02/04  03:27:26  tom
 * (Posix signal): fix old-style prototype.
 *
 * Revision 14.32.0.6  1993/10/28  00:54:49  tom
 * do_cmdline, main: replace conditional strlwr() with FIX_FILENAME().
 *
 * Revision 14.32  1993/07/06  00:53:06  tom
 * (finish): re-signal ourselves so we die properly;
 * (winch): new SIGWINCH handler;
 * (getch): handle pending window change;
 * (main): establish handlers conditionally on existence of their signals;
 * add handler for SIGQUIT.
 *
 * Revision 14.31  1993/02/18  01:42:30  tom
 * remove (void) casts; move BIFF code to tty.c; move settout() setup to
 * before joverc() handling; reorganize updmode(); lotsa random optimizations.
 *
 * Revision 14.30  1993/01/27  01:33:20  tom
 * cleanup whitespace; add dirs_init(); update global clock `now' in updmode().
 *
 * Revision 14.28  1992/10/23  17:45:59  tom
 * convert to "port{ansi,defs}.h" conventions.
 *
 * Revision 14.27  1992/09/22  02:03:52  tom
 * replace CTL('Q') with `QuoteChar'; add some typecasts to suppress warnings.
 *
 * Revision 14.26  1992/08/26  23:56:55  tom
 * handle eventual window resize after jove has been suspended; use explicit
 * "i-shell" and "i-shell-flags" in "push-shell"; make iniarg[vc] private;
 * simplify ExecNow() due to bug fix in macro execution;
 * PRIVATE-ized some Variable defs; add RCS directives.
 *
 */
