about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2005-04-01 10:30:08 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2005-04-01 10:30:08 +0000
commite43b2acd67a7b06d4653ff910af1b4b51aedcdfe (patch)
tree53cea44589504314c83f32d92dd9073851d79b92 /Src
parent6f8b647733e27a702957f3345044cc46b8f26288 (diff)
downloadzsh-e43b2acd67a7b06d4653ff910af1b4b51aedcdfe.tar.gz
zsh-e43b2acd67a7b06d4653ff910af1b4b51aedcdfe.tar.xz
zsh-e43b2acd67a7b06d4653ff910af1b4b51aedcdfe.zip
21078: parse errors didn't cause non-zero exit status
Diffstat (limited to 'Src')
-rw-r--r--Src/init.c407
1 files changed, 312 insertions, 95 deletions
diff --git a/Src/init.c b/Src/init.c
index e7dec681e..4fdf38de7 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -34,6 +34,8 @@
 
 #include "init.pro"
 
+#include "version.h"
+
 /**/
 int noexitct = 0;
 
@@ -105,7 +107,8 @@ loop(int toplevel, int justonce)
     pushheap();
     for (;;) {
 	freeheap();
-	errflag = 0;
+	if (stophist == 3)	/* re-entry via preprompt() */
+	    hend(NULL);
 	hbegin(1);		/* init history mech        */
 	if (isset(SHINSTDIN)) {
 	    setblock_stdin();
@@ -113,43 +116,55 @@ loop(int toplevel, int justonce)
 	        int hstop = stophist;
 		stophist = 3;
 		preprompt();
-		stophist = hstop;
+		if (stophist != 3)
+		    hbegin(1);
+		else
+		    stophist = hstop;
+		errflag = 0;
 	    }
 	}
 	intr();			/* interrupts on            */
 	lexinit();              /* initialize lexical state */
 	if (!(prog = parse_event())) {	/* if we couldn't parse a list */
-	    hend();
+	    hend(NULL);
 	    if ((tok == ENDINPUT && !errflag) ||
 		(tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) ||
 		justonce)
 		break;
+	    if (tok == LEXERR && !lastval)
+		lastval = 1;
 	    continue;
 	}
-	if (hend()) {
+	if (hend(prog)) {
 	    int toksav = tok;
 	    Eprog preprog;
 
 	    if (toplevel && (preprog = getshfunc("preexec")) != &dummy_eprog) {
 		LinkList args;
 		int osc = sfcontext;
+		char *cmdstr;
 
 		args = znewlinklist();
 		zaddlinknode(args, "preexec");
-		if (hist_ring)
+		/* If curline got dumped from the history, we don't know
+		 * what the user typed. */
+		if (hist_ring && curline.histnum == curhist)
 		    zaddlinknode(args, hist_ring->text);
+		else
+		    zaddlinknode(args, "");
+		zaddlinknode(args, getjobtext(prog, NULL));
+		zaddlinknode(args, cmdstr = getpermtext(prog, NULL));
 
 		sfcontext = SFC_HOOK;
 		doshfunc("preexec", preprog, args, 0, 1);
 		sfcontext = osc;
+		zsfree(cmdstr);
 		freelinklist(args, (FreeFunc) NULL);
 		errflag = 0;
 	    }
 	    if (stopmsg)	/* unset 'you have stopped jobs' flag */
 		stopmsg--;
 	    execode(prog, 0, 0);
-	    if (toplevel)
-		freeeprogs();
 	    tok = toksav;
 	    if (toplevel)
 		noexitct = 0;
@@ -184,10 +199,10 @@ static int restricted;
 void
 parseargs(char **argv)
 {
+    int optionbreak = 0;
     char **x;
     int action, optno;
     LinkList paramlist;
-    int bourne = (emulation == EMULATE_KSH || emulation == EMULATE_SH);
 
     argzero = *argv++;
     SHIN = 0;
@@ -204,24 +219,47 @@ parseargs(char **argv)
     opts[SINGLECOMMAND] = 0;
 
     /* loop through command line options (begins with "-" or "+") */
-    while (*argv && (**argv == '-' || **argv == '+')) {
+    while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) {
 	char *args = *argv;
 	action = (**argv == '-');
-	if(!argv[0][1])
+	if (!argv[0][1])
 	    *argv = "--";
 	while (*++*argv) {
-	    /* The pseudo-option `--' signifies the end of options. *
-	     * `-b' does too, csh-style, unless we're emulating a   *
-	     * Bourne style shell.                                  */
-	    if (**argv == '-' || (!bourne && **argv == 'b')) {
-		argv++;
-		goto doneoptions;
+	    if (**argv == '-') {
+		if(!argv[0][1]) {
+		    /* The pseudo-option `--' signifies the end of options. */
+		    argv++;
+		    goto doneoptions;
+		}
+		if(*argv != args+1 || **argv != '-')
+		    goto badoptionstring;
+		/* GNU-style long options */
+		++*argv;
+		if (!strcmp(*argv, "version")) {
+		    printf("zsh %s (%s-%s-%s)\n",
+			    ZSH_VERSION, MACHTYPE, VENDOR, OSTYPE);
+		    exit(0);
+		}
+		if (!strcmp(*argv, "help")) {
+		    printhelp();
+		    exit(0);
+		}
+		/* `-' characters are allowed in long options */
+		for(args = *argv; *args; args++)
+		    if(*args == '-')
+			*args = '_';
+		goto longoptions;
 	    }
 
-	    if (**argv == 'c') {         /* -c command */
+	    if (unset(SHOPTIONLETTERS) && **argv == 'b') {
+		/* -b ends options at the end of this argument */
+		optionbreak = 1;
+	    } else if (**argv == 'c') {
+		/* -c command */
 		cmd = *argv;
 		opts[INTERACTIVE] &= 1;
 		opts[SHINSTDIN] = 0;
+		scriptname = ztrdup("zsh");
 	    } else if (**argv == 'o') {
 		if (!*++*argv)
 		    argv++;
@@ -229,9 +267,11 @@ parseargs(char **argv)
 		    zerr("string expected after -o", NULL, 0);
 		    exit(1);
 		}
-		if(!(optno = optlookup(*argv)))
+	    longoptions:
+		if (!(optno = optlookup(*argv))) {
 		    zerr("no such option: %s", *argv, 0);
-		else if (optno == RESTRICTED)
+		    exit(1);
+		} else if (optno == RESTRICTED)
 		    restricted = action;
 		else
 		    dosetopt(optno, action, 1);
@@ -240,6 +280,7 @@ parseargs(char **argv)
 		/* zsh's typtab not yet set, have to use ctype */
 		while (*++*argv)
 		    if (!isspace(STOUC(**argv))) {
+		    badoptionstring:
 			zerr("bad option string: `%s'", args, 0);
 			exit(1);
 		    }
@@ -284,19 +325,37 @@ parseargs(char **argv)
     if(isset(SINGLECOMMAND))
 	opts[INTERACTIVE] &= 1;
     opts[INTERACTIVE] = !!opts[INTERACTIVE];
-    pparams = x = (char **) zcalloc((countlinknodes(paramlist) + 1) * sizeof(char *));
+    pparams = x = (char **) zshcalloc((countlinknodes(paramlist) + 1) * sizeof(char *));
 
     while ((*x++ = (char *)getlinknode(paramlist)));
     free(paramlist);
     argzero = ztrdup(argzero);
 }
 
+/**/
+static void
+printhelp(void)
+{
+    printf("Usage: %s [<options>] [<argument> ...]\n", argzero);
+    printf("\nSpecial options:\n");
+    printf("  --help     show this message, then exit\n");
+    printf("  --version  show zsh version number, then exit\n");
+    if(unset(SHOPTIONLETTERS))
+	printf("  -b         end option processing, like --\n");
+    printf("  -c         take first argument as a command to execute\n");
+    printf("  -o OPTION  set an option by name (see below)\n");
+    printf("\nNormal options are named.  An option may be turned on by\n");
+    printf("`-o OPTION', `--OPTION', `+o no_OPTION' or `+-no-OPTION'.  An\n");
+    printf("option may be turned off by `-o no_OPTION', `--no-OPTION',\n");
+    printf("`+o OPTION' or `+-OPTION'.  Options are listed below only in\n");
+    printf("`--OPTION' or `--no-OPTION' form.\n");
+    printoptionlist();
+}
 
 /**/
 mod_export void
 init_io(void)
 {
-    long ttpgrp;
     static char outbuf[BUFSIZ], errbuf[BUFSIZ];
 
 #ifdef RSH_BUG_WORKAROUND
@@ -322,7 +381,13 @@ init_io(void)
 #endif
 
     if (shout) {
-	fclose(shout);
+	/*
+	 * Check if shout was set to stderr, if so don't close it.
+	 * We do this if we are interactive but don't have a
+	 * terminal.
+	 */
+	if (shout != stderr)
+	    fclose(shout);
 	shout = 0;
     }
     if (SHTTY != -1) {
@@ -391,29 +456,21 @@ init_io(void)
 
     /* We will only use zle if shell is interactive, *
      * SHTTY != -1, and shout != 0                   */
-    if (interact && SHTTY != -1) {
+    if (interact) {
 	init_shout();
-	if(!shout)
+	if(!SHTTY || !shout)
 	    opts[USEZLE] = 0;
     } else
 	opts[USEZLE] = 0;
 
 #ifdef JOB_CONTROL
-    /* If interactive, make the shell the foreground process */
+    /* If interactive, make sure the shell is in the foreground and is the
+     * process group leader.
+     */
+    mypid = (zlong)getpid();
     if (opts[MONITOR] && interact && (SHTTY != -1)) {
-	if ((mypgrp = GETPGRP()) > 0) {
-	    while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
-		sleep(1);	/* give parent time to change pgrp */
-		mypgrp = GETPGRP();
-		if (mypgrp == mypid)
-		    attachtty(mypgrp);
-		if (mypgrp == gettygrp())
-		    break;
-		killpg(mypgrp, SIGTTIN);
-		mypgrp = GETPGRP();
-	    }
-	} else
-	    opts[MONITOR] = 0;
+	origpgrp = GETPGRP();
+        acquire_pgrp(); /* might also clear opts[MONITOR] */
     } else
 	opts[MONITOR] = 0;
 #else
@@ -427,8 +484,18 @@ init_shout(void)
 {
     static char shoutbuf[BUFSIZ];
 #if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC)
-    int ldisc = NTTYDISC;
+    int ldisc;
+#endif
+
+    if (SHTTY == -1)
+    {
+	/* Since we're interative, it's nice to have somewhere to write. */
+	shout = stderr;
+	return;
+    }
 
+#if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC)
+    ldisc = NTTYDISC;
     ioctl(SHTTY, TIOCSETD, (char *)&ldisc);
 #endif
 
@@ -450,7 +517,8 @@ init_shout(void)
 static char *tccapnams[TC_COUNT] = {
     "cl", "le", "LE", "nd", "RI", "up", "UP", "do",
     "DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta",
-    "md", "so", "us", "me", "se", "ue", "ch"
+    "md", "so", "us", "me", "se", "ue", "ch",
+    "ku", "kd", "kl", "kr"
 };
 
 /* Initialise termcap */
@@ -474,13 +542,13 @@ init_term(void)
 
 #ifdef TGETENT_ACCEPTS_NULL
     /* If possible, we let tgetent allocate its own termcap buffer */
-    if (tgetent(NULL, term) != 1) {
+    if (tgetent(NULL, term) != TGETENT_SUCCESS)
 #else
-    if (tgetent(termbuf, term) != 1) {
+    if (tgetent(termbuf, term) != TGETENT_SUCCESS)
 #endif
-
+    {
 	if (isset(INTERACTIVE))
-	    zerr("can't find termcap info for %s", term, 0);
+	    zerr("can't find terminal definition for %s", term, 0);
 	errflag = 0;
 	termflags |= TERM_BAD;
 	return 0;
@@ -552,14 +620,11 @@ setupvals(void)
 #endif
     struct timezone dummy_tz;
     char *ptr;
-#ifdef HAVE_GETRLIMIT
-    int i;
-#endif
+    int i, j;
 #if defined(SITEFPATH_DIR) || defined(FPATH_DIR)
     char **fpathptr;
 # if defined(FPATH_DIR) && defined(FPATH_SUBDIRS)
     char *fpath_subdirs[] = FPATH_SUBDIRS;
-    int j;
 # endif
 # ifdef SITEFPATH_DIR
     int fpathlen = 1;
@@ -567,6 +632,47 @@ setupvals(void)
     int fpathlen = 0;
 # endif
 #endif
+    int close_fds[10], tmppipe[2];
+
+    /*
+     * Workaround a problem with NIS (in one guise or another) which
+     * grabs file descriptors and keeps them for future reference.
+     * We don't want these to be in the range where the user can
+     * open fd's, i.e. 0 to 9 inclusive.  So we make sure all
+     * fd's in that range are in use.
+     */
+    memset(close_fds, 0, 10*sizeof(int));
+    if (pipe(tmppipe) == 0) {
+	/*
+	 * Strategy:  Make sure we have at least fd 0 open (hence
+	 * the pipe).  From then on, keep dup'ing until we are
+	 * up to 9.  If we go over the top, close immediately, else
+	 * mark for later closure.
+	 */
+	i = -1;			/* max fd we have checked */
+	while (i < 9) {
+	    /* j is current fd */
+	    if (i < tmppipe[0])
+		j = tmppipe[0];
+	    else if (i < tmppipe[1])
+		j = tmppipe[1];
+	    else {
+		j = dup(0);
+		if (j == -1)
+		    break;
+	    }
+	    if (j < 10)
+		close_fds[j] = 1;
+	    else
+		close(j);
+	    if (i < j)
+		i = j;
+	}
+	if (i < tmppipe[0])
+	    close(tmppipe[0]);
+	if (i < tmppipe[1])
+	    close(tmppipe[1]);
+    }
 
     addhookdefs(argzero, zshhooks, sizeof(zshhooks)/sizeof(*zshhooks));
 
@@ -594,9 +700,6 @@ setupvals(void)
     gettimeofday(&shtimer, &dummy_tz);	/* init $SECONDS */
     srand((unsigned int)(shtimer.tv_sec + shtimer.tv_usec)); /* seed $RANDOM */
 
-    hostnam     = (char *) zalloc(256);
-    gethostname(hostnam, 256);
-
     /* Set default path */
     path    = (char **) zalloc(sizeof(*path) * 5);
     path[0] = ztrdup("/bin");
@@ -695,7 +798,8 @@ setupvals(void)
      * initialize `PWD' from `HOME'      */
     if (ispwd(home))
 	pwd = ztrdup(home);
-    else if ((ptr = zgetenv("PWD")) && ispwd(ptr))
+    else if ((ptr = zgetenv("PWD")) && (strlen(ptr) < PATH_MAX) &&
+	     (ptr = metafy(ptr, -1, META_STATIC), ispwd(ptr)))
 	pwd = ztrdup(ptr);
     else
 	pwd = metafy(zgetcwd(), -1, META_DUP);
@@ -706,12 +810,12 @@ setupvals(void)
     initlextabs();    /* initialize lexing tables    */
 
     createreswdtable();     /* create hash table for reserved words    */
-    createaliastable();     /* create hash table for aliases           */
+    createaliastables();    /* create hash tables for aliases           */
     createcmdnamtable();    /* create hash table for external commands */
     createshfunctable();    /* create hash table for shell functions   */
     createbuiltintable();   /* create hash table for builtin commands  */
     createnameddirtable();  /* create hash table for named directories */
-    createparamtable();     /* create paramater hash table             */
+    createparamtable();     /* create parameter hash table             */
 
     condtab = NULL;
     wrappers = NULL;
@@ -754,7 +858,12 @@ setupvals(void)
 #endif
     }
 
-    times(&shtms);
+    get_usage();
+
+    /* Close the file descriptors we opened to block off 0 to 9 */
+    for (i = 0; i < 10; i++)
+	if (close_fds[i])
+	    close(i);
 }
 
 /* Initialize signal handling */
@@ -763,6 +872,12 @@ setupvals(void)
 void
 init_signals(void)
 {
+    if (interact) {
+	int i;
+	signal_setmask(signal_mask(0));
+	for (i=0; i<NSIG; ++i)
+	    signal_default(i);
+    }
     sigchld_mask = signal_mask(SIGCHLD);
 
     intr();
@@ -771,7 +886,10 @@ init_signals(void)
     signal_ignore(SIGQUIT);
 #endif
 
-    install_handler(SIGHUP);
+    if (signal_ignore(SIGHUP) == SIG_IGN)
+	opts[HUP] = 0;
+    else
+	install_handler(SIGHUP);
     install_handler(SIGCHLD);
 #ifdef SIGWINCH
     install_handler(SIGWINCH);
@@ -781,28 +899,9 @@ init_signals(void)
 	signal_ignore(SIGTERM);
     }
     if (jobbing) {
-	long ttypgrp;
-
-	while ((ttypgrp = gettygrp()) != -1 && ttypgrp != mypgrp)
-	    kill(0, SIGTTIN);
-	if (ttypgrp == -1) {
-	    opts[MONITOR] = 0;
-	} else {
-	    signal_ignore(SIGTTOU);
-	    signal_ignore(SIGTSTP);
-	    signal_ignore(SIGTTIN);
-	    attachtty(mypgrp);
-	}
-    }
-    if (islogin) {
-	signal_setmask(signal_mask(0));
-    } else if (interact) {
-	sigset_t set;
-
-	sigemptyset(&set);
-	sigaddset(&set, SIGINT);
-	sigaddset(&set, SIGQUIT);
-	signal_unblock(set);
+	signal_ignore(SIGTTOU);
+	signal_ignore(SIGTSTP);
+	signal_ignore(SIGTTIN);
     }
 }
 
@@ -904,7 +1003,7 @@ source(char *s)
     int oldshst, osubsh, oloops;
     FILE *obshin;
     char *old_scriptname = scriptname, *us;
-    char *ocs;
+    unsigned char *ocs;
     int ocsp;
 
     if (!s || 
@@ -943,7 +1042,7 @@ source(char *s)
 	execode(prog, 1, 0);
 	popheap();
     } else
-	loop(0, 0);		     /* loop through the file to be sourced        */
+	loop(0, 0);		     /* loop through the file to be sourced  */
     sourcelevel--;
 
     /* restore the current shell state */
@@ -976,18 +1075,20 @@ source(char *s)
 void
 sourcehome(char *s)
 {
-    char buf[PATH_MAX];
     char *h;
 
+    queue_signals();
     if (emulation == EMULATE_SH || emulation == EMULATE_KSH ||
 	!(h = getsparam("ZDOTDIR")))
 	h = home;
-    if (strlen(h) + strlen(s) + 1 >= PATH_MAX) {
-	zerr("path too long: %s", s, 0);
-	return;
+
+    {
+	/* Let source() complain if path is too long */
+	VARARR(char, buf, strlen(h) + strlen(s) + 2);
+	sprintf(buf, "%s/%s", h, s);
+	unqueue_signals();
+	source(buf);
     }
-    sprintf(buf, "%s/%s", h, s);
-    source(buf);
 }
 
 /**/
@@ -1009,7 +1110,7 @@ noop_function(void)
 
 /**/
 mod_export void
-noop_function_int(int nothing)
+noop_function_int(UNUSED(int nothing))
 {
     /* do nothing */
 }
@@ -1024,51 +1125,63 @@ noop_function_int(int nothing)
 /**/
 mod_export ZleVoidFn trashzleptr = noop_function;
 /**/
-mod_export ZleVoidFn gotwordptr = noop_function;
-/**/
 mod_export ZleVoidFn refreshptr = noop_function;
 /**/
 mod_export ZleVoidIntFn spaceinlineptr = noop_function_int;
 /**/
 mod_export ZleReadFn zlereadptr = autoload_zleread;
+/**/
+mod_export ZleVoidIntFn zlesetkeymapptr = noop_function_int;
 
 #else /* !LINKED_XMOD_zshQszle */
 
 mod_export ZleVoidFn trashzleptr = noop_function;
-mod_export ZleVoidFn gotwordptr = noop_function;
 mod_export ZleVoidFn refreshptr = noop_function;
 mod_export ZleVoidIntFn spaceinlineptr = noop_function_int;
 # ifdef UNLINKED_XMOD_zshQszle
 mod_export ZleReadFn zlereadptr = autoload_zleread;
+mod_export ZleVoidIntFn zlesetkeymapptr = autoload_zlesetkeymap;
 # else /* !UNLINKED_XMOD_zshQszle */
 mod_export ZleReadFn zlereadptr = fallback_zleread;
+mod_export ZleVoidIntFn zlesetkeymapptr = noop_function_int;
 # endif /* !UNLINKED_XMOD_zshQszle */
 
 #endif /* !LINKED_XMOD_zshQszle */
 
 /**/
 unsigned char *
-autoload_zleread(char *lp, char *rp, int ha)
+autoload_zleread(char **lp, char **rp, int ha, int con)
 {
     zlereadptr = fallback_zleread;
     if (load_module("zsh/zle"))
 	load_module("zsh/compctl");
-    return zleread(lp, rp, ha);
+    return zleread(lp, rp, ha, con);
 }
 
 /**/
 mod_export unsigned char *
-fallback_zleread(char *lp, char *rp, int ha)
+fallback_zleread(char **lp, UNUSED(char **rp), UNUSED(int ha), UNUSED(int con))
 {
     char *pptbuf;
     int pptlen;
 
-    pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen);
+    pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL), &pptlen);
     write(2, (WRITE_ARG_2_T)pptbuf, pptlen);
     free(pptbuf);
+
     return (unsigned char *)shingetline();
 }
 
+/**/
+static void
+autoload_zlesetkeymap(int mode)
+{
+    zlesetkeymapptr = noop_function_int;
+    load_module("zsh/zle");
+    (*zlesetkeymapptr)(mode);
+}
+
+
 /* compctl entry point pointers.  Similar to the ZLE ones. */
 
 /**/
@@ -1076,9 +1189,113 @@ mod_export CompctlReadFn compctlreadptr = fallback_compctlread;
 
 /**/
 mod_export int
-fallback_compctlread(char *name, char **args, char *ops, char *reply)
+fallback_compctlread(char *name, UNUSED(char **args), UNUSED(Options ops), UNUSED(char *reply))
 {
     zwarnnam(name, "option valid only in functions called from completion",
 	    NULL, 0);
     return 1;
 }
+
+/*
+ * This is real main entry point. This has to be mod_export'ed
+ * so zsh.exe can found it on Cygwin
+ */
+
+/**/
+mod_export int
+zsh_main(UNUSED(int argc), char **argv)
+{
+    char **t;
+    int t0;
+#ifdef USE_LOCALE
+    setlocale(LC_ALL, "");
+#endif
+
+    init_jobs(argv, environ);
+
+    /*
+     * Provisionally set up the type table to allow metafication.
+     * This will be done properly when we have decided if we are
+     * interactive
+     */
+    typtab['\0'] |= IMETA;
+    typtab[STOUC(Meta)  ] |= IMETA;
+    typtab[STOUC(Marker)] |= IMETA;
+    for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Nularg); t0++)
+	typtab[t0] |= ITOK | IMETA;
+
+    for (t = argv; *t; *t = metafy(*t, -1, META_ALLOC), t++);
+
+    zsh_name = argv[0];
+    do {
+      char *arg0 = zsh_name;
+      if (!(zsh_name = strrchr(arg0, '/')))
+	  zsh_name = arg0;
+      else
+	  zsh_name++;
+      if (*zsh_name == '-')
+	  zsh_name++;
+      if (strcmp(zsh_name, "su") == 0) {
+	  char *sh = zgetenv("SHELL");
+	  if (sh && *sh && arg0 != sh)
+	      zsh_name = sh;
+	  else
+	      break;
+      } else
+	  break;
+    } while (zsh_name);
+
+    fdtable_size = zopenmax();
+    fdtable = zshcalloc(fdtable_size);
+
+    createoptiontable();
+    emulate(zsh_name, 1);   /* initialises most options */
+    opts[LOGINSHELL] = (**argv == '-');
+    opts[MONITOR] = 1;   /* may be unset in init_io() */
+    opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
+    opts[USEZLE] = 1;   /* may be unset in init_io() */
+    parseargs(argv);   /* sets INTERACTIVE, SHINSTDIN and SINGLECOMMAND */
+
+    SHTTY = -1;
+    init_io();
+    setupvals();
+    init_signals();
+    init_bltinmods();
+    run_init_scripts();
+    init_misc();
+
+    for (;;) {
+	/*
+	 * See if we can free up some of jobtab.
+	 * We only do this at top level, because if we are
+	 * executing stuff we may refer to them by job pointer.
+	 */
+	maybeshrinkjobtab();
+
+	do
+	    loop(1,0);
+	while (tok != ENDINPUT && (tok != LEXERR || isset(SHINSTDIN)));
+	if (tok == LEXERR) {
+	    /* Make sure a parse error exits with non-zero status */
+	    if (!lastval)
+		lastval = 1;
+	    stopmsg = 1;
+	    zexit(lastval, 0);
+	}
+	if (!(isset(IGNOREEOF) && interact)) {
+#if 0
+	    if (interact)
+		fputs(islogin ? "logout\n" : "exit\n", shout);
+#endif
+	    zexit(lastval, 0);
+	    continue;
+	}
+	noexitct++;
+	if (noexitct >= 10) {
+	    stopmsg = 1;
+	    zexit(lastval, 0);
+	}
+	zerrnam("zsh", (!islogin) ? "use 'exit' to exit."
+		: "use 'logout' to logout.", NULL, 0);
+    }
+}