summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorBart Schaefer <barts@users.sourceforge.net>2000-05-02 15:52:43 +0000
committerBart Schaefer <barts@users.sourceforge.net>2000-05-02 15:52:43 +0000
commit966eca4ad87436d03e380eef1ca55f49d0aeedb4 (patch)
tree5fb1ac19c1b33e2d7eed8f4add48e7125c521192 /Src
parent5db44fff033a0f1426928aa514b5dbe4dcc5482c (diff)
downloadzsh-966eca4ad87436d03e380eef1ca55f49d0aeedb4.tar.gz
zsh-966eca4ad87436d03e380eef1ca55f49d0aeedb4.tar.xz
zsh-966eca4ad87436d03e380eef1ca55f49d0aeedb4.zip
11036, 11063, 11077: Always write the "read -q" prompt to shout; eliminate
some redundant close() calls; relocate a misplaced redirection.
Diffstat (limited to 'Src')
-rw-r--r--Src/Zle/zle_main.c558
-rw-r--r--Src/builtin.c10
2 files changed, 394 insertions, 174 deletions
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 338cdef41..178133fae 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -30,6 +30,27 @@
 #include "zle.mdh"
 #include "zle_main.pro"
 
+/* != 0 if in a shell function called from completion, such that read -[cl]  *
+ * will work (i.e., the line is metafied, and the above word arrays are OK). */
+
+/**/
+mod_export int incompctlfunc;
+
+/* != 0 if we are in a new style completion function */
+
+/**/
+mod_export int incompfunc;
+
+/* != 0 if completion module is loaded */
+
+/**/
+mod_export int hascompmod;
+
+/* ZLRF_* flags passed to zleread() */
+
+/**/
+int zlereadflags;
+
 /* != 0 if we're done editing */
 
 /**/
@@ -45,10 +66,10 @@ int mark;
 /**/
 int c;
 
-/* the binding for this key */
+/* the bindings for the previous and for this key */
 
 /**/
-Thingy bindk;
+mod_export Thingy lbindk, bindk;
 
 /* insert mode/overwrite mode flag */
 
@@ -67,7 +88,10 @@ static int baud;
 /* flags associated with last command */
 
 /**/
-int lastcmd;
+mod_export int lastcmd;
+
+/**/
+mod_export Widget compwidget;
 
 /* the status line, and its length */
 
@@ -90,7 +114,7 @@ int undoing;
 /* current modifier status */
 
 /**/
-struct modifier zmod;
+mod_export struct modifier zmod;
 
 /* Current command prefix status.  This is normally 0.  Prefixes set *
  * this to 1.  Each time round the main loop, this is checked: if it *
@@ -103,25 +127,49 @@ struct modifier zmod;
 /**/
 int prefixflag;
 
-/* != 0 if there is a pending beep (usually indicating an error) */
+/* Number of characters waiting to be read by the ungetkeys mechanism */
+/**/
+int kungetct;
 
 /**/
-int feepflag;
+mod_export char *zlenoargs[1] = { NULL };
+
+#ifdef FIONREAD
+static int delayzsetterm;
+#endif
 
 /* set up terminal */
 
 /**/
-void
-setterm(void)
+mod_export void
+zsetterm(void)
 {
     struct ttyinfo ti;
 
-#if defined(CLOBBERS_TYPEAHEAD) && defined(FIONREAD)
+#if defined(FIONREAD)
     int val;
 
     ioctl(SHTTY, FIONREAD, (char *)&val);
-    if (val)
+    if (val) {
+	/*
+	 * Problems can occur on some systems when switching from
+	 * canonical to non-canonical input.  The former is usually
+	 * set while running programmes, but the latter is necessary
+	 * for zle.  If there is input in canonical mode, then we
+	 * need to read it without setting up the terminal.  Furthermore,
+	 * while that input gets processed there may be more input
+	 * being typed (i.e. further typeahead).  This means that
+	 * we can't set up the terminal for zle *at all* until
+	 * we are sure there is no more typeahead to come.  So
+	 * if there is typeahead, we set the flag delayzsetterm.
+	 * Then getkey() performs another FIONREAD call; if that is
+	 * 0, we have finally used up all the typeahead, and it is
+	 * safe to alter the terminal, which we do at that point.
+	 */
+	delayzsetterm = 1;
 	return;
+    } else
+	delayzsetterm = 0;
 #endif
 
 /* sanitize the tty */
@@ -151,10 +199,14 @@ setterm(void)
 #  ifdef OXTABS
     ti.tio.c_oflag &= ~OXTABS;
 #  else
+#   ifdef XTABS
     ti.tio.c_oflag &= ~XTABS;
+#   endif
 #  endif
 # endif
+#ifdef ONLCR
     ti.tio.c_oflag |= ONLCR;
+#endif
     ti.tio.c_cc[VQUIT] =
 # ifdef VDISCARD
 	ti.tio.c_cc[VDISCARD] =
@@ -233,7 +285,7 @@ setterm(void)
 }
 
 static char *kungetbuf;
-static int kungetct, kungetsz;
+static int kungetsz;
 
 /**/
 void
@@ -269,14 +321,14 @@ breakread(int fd, char *buf, int n)
 #endif
 
 /**/
-int
+mod_export int
 getkey(int keytmout)
 {
     char cc;
     unsigned int ret;
     long exp100ths;
     int die = 0, r, icnt = 0;
-    int old_errno = errno;
+    int old_errno = errno, obreaks = breaks;
 
 #ifdef HAVE_SELECT
     fd_set foofd;
@@ -291,7 +343,19 @@ getkey(int keytmout)
     if (kungetct)
 	ret = STOUC(kungetbuf[--kungetct]);
     else {
-	if (keytmout) {
+#ifdef FIONREAD
+	if (delayzsetterm) {
+	    int val;
+	    ioctl(SHTTY, FIONREAD, (char *)&val);
+	    if (!val)
+		zsetterm();
+	}
+#endif
+	if (keytmout
+#ifdef FIONREAD
+	    && ! delayzsetterm
+#endif
+	    ) {
 	    if (keytimeout > 500)
 		exp100ths = 500;
 	    else if (keytimeout > 0)
@@ -354,6 +418,7 @@ getkey(int keytmout)
 		if (!errflag && !retflag && !breaks)
 		    continue;
 		errflag = 0;
+		breaks = obreaks;
 		errno = old_errno;
 		return EOF;
 	    } else if (errno == EWOULDBLOCK) {
@@ -362,7 +427,7 @@ getkey(int keytmout)
 		ret = opts[MONITOR];
 		opts[MONITOR] = 1;
 		attachtty(mypgrp);
-		refresh();	/* kludge! */
+		zrefresh();	/* kludge! */
 		opts[MONITOR] = ret;
 		die = 1;
 	    } else if (errno != 0) {
@@ -372,7 +437,7 @@ getkey(int keytmout)
 	    }
 	}
 	if (cc == '\r')		/* undo the exchange of \n and \r determined by */
-	    cc = '\n';		/* setterm() */
+	    cc = '\n';		/* zsetterm() */
 	else if (cc == '\n')
 	    cc = '\r';
 
@@ -391,7 +456,7 @@ getkey(int keytmout)
 
 /**/
 unsigned char *
-zleread(char *lp, char *rp, int ha)
+zleread(char *lp, char *rp, int flags)
 {
     unsigned char *s;
     int old_errno = errno;
@@ -404,7 +469,6 @@ zleread(char *lp, char *rp, int ha)
 
     baud = getiparam("BAUD");
     costmult = (baud) ? 3840000L / baud : 0;
-    tv.tv_sec = 0;
 #endif
 
     /* ZLE doesn't currently work recursively.  This is needed in case a *
@@ -440,98 +504,98 @@ zleread(char *lp, char *rp, int ha)
     insmode = unset(OVERSTRIKE);
     eofsent = 0;
     resetneeded = 0;
-    lpptbuf = promptexpand(lp, 1, NULL, NULL);
+    lpromptbuf = promptexpand(lp, 1, NULL, NULL);
     pmpt_attr = txtchange;
-    rpptbuf = promptexpand(rp, 1, NULL, NULL);
+    rpromptbuf = promptexpand(rp, 1, NULL, NULL);
     rpmpt_attr = txtchange;
-    histallowed = ha;
-    PERMALLOC {
-	histline = curhist;
+
+    zlereadflags = flags;
+    histline = curhist;
 #ifdef HAVE_SELECT
-	FD_ZERO(&foofd);
+    FD_ZERO(&foofd);
 #endif
-	undoing = 1;
-	line = (unsigned char *)zalloc((linesz = 256) + 2);
-	virangeflag = lastcmd = done = cs = ll = mark = 0;
-	curhistline = NULL;
-	vichgflag = 0;
-	viinsbegin = 0;
+    undoing = 1;
+    line = (unsigned char *)zalloc((linesz = 256) + 2);
+    virangeflag = lastcmd = done = cs = ll = mark = 0;
+    vichgflag = 0;
+    viinsbegin = 0;
+    statusline = NULL;
+    selectkeymap("main", 1);
+    selectlocalmap(NULL);
+    fixsuffix();
+    if ((s = (unsigned char *)getlinknode(bufstack))) {
+	setline((char *)s);
+	zsfree((char *)s);
+	if (stackcs != -1) {
+	    cs = stackcs;
+	    stackcs = -1;
+	    if (cs > ll)
+		cs = ll;
+	}
+	if (stackhist != -1) {
+	    histline = stackhist;
+	    stackhist = -1;
+	}
+    }
+    initundo();
+    if (isset(PROMPTCR))
+	putc('\r', shout);
+    if (tmout)
+	alarm(tmout);
+    zleactive = 1;
+    resetneeded = 1;
+    errflag = retflag = 0;
+    lastcol = -1;
+    initmodifier(&zmod);
+    prefixflag = 0;
+    zrefresh();
+    while (!done && !errflag) {
+
 	statusline = NULL;
-	selectkeymap("main", 1);
-	fixsuffix();
-	if ((s = (unsigned char *)getlinknode(bufstack))) {
-	    setline((char *)s);
-	    zsfree((char *)s);
-	    if (stackcs != -1) {
-		cs = stackcs;
-		stackcs = -1;
-		if (cs > ll)
-		    cs = ll;
-	    }
-	    if (stackhist != -1) {
-		histline = stackhist;
-		stackhist = -1;
-	    }
+	vilinerange = 0;
+	reselectkeymap();
+	selectlocalmap(NULL);
+	bindk = getkeycmd();
+	if (!ll && isfirstln && c == eofchar) {
+	    eofsent = 1;
+	    break;
+	}
+	if (bindk) {
+	    if (execzlefunc(bindk, zlenoargs))
+		handlefeep(zlenoargs);
+	    handleprefixes();
+	    /* for vi mode, make sure the cursor isn't somewhere illegal */
+	    if (invicmdmode() && cs > findbol() &&
+		(cs == ll || line[cs] == '\n'))
+		cs--;
+	    if (undoing)
+		handleundo();
+	} else {
+	    errflag = 1;
+	    break;
 	}
-	initundo();
-	if (isset(PROMPTCR))
-	    putc('\r', shout);
-	if (tmout)
-	    alarm(tmout);
-	zleactive = 1;
-	resetneeded = 1;
-	errflag = retflag = 0;
-	lastcol = -1;
-	initmodifier(&zmod);
-	prefixflag = 0;
-	feepflag = 0;
-	refresh();
-	while (!done && !errflag) {
-
-	    statusline = NULL;
-	    vilinerange = 0;
-	    reselectkeymap();
-	    bindk = getkeycmd();
-	    if (!ll && isfirstln && c == eofchar) {
-		eofsent = 1;
-		break;
-	    }
-	    if (bindk) {
-		execzlefunc(bindk);
-		handleprefixes();
-		/* for vi mode, make sure the cursor isn't somewhere illegal */
-		if (invicmdmode() && cs > findbol() &&
-		    (cs == ll || line[cs] == '\n'))
-		    cs--;
-		if (undoing)
-		    handleundo();
-	    } else {
-		errflag = 1;
-		break;
-	    }
 #ifdef HAVE_SELECT
-	    if (baud && !(lastcmd & ZLE_MENUCMP)) {
-		FD_SET(SHTTY, &foofd);
-		if ((tv.tv_usec = cost * costmult) > 500000)
-		    tv.tv_usec = 500000;
-		if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
-					NULL, NULL, &tv) <= 0)
-		    refresh();
-	    } else
+	if (baud && !(lastcmd & ZLE_MENUCMP)) {
+	    FD_SET(SHTTY, &foofd);
+	    tv.tv_sec = 0;
+	    if ((tv.tv_usec = cost * costmult) > 500000)
+		tv.tv_usec = 500000;
+	    if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
+				    NULL, NULL, &tv) <= 0)
+		zrefresh();
+	} else
 #endif
-		if (!kungetct)
-		    refresh();
-	    handlefeep();
-	}
-	statusline = NULL;
-	invalidatelist();
-	trashzle();
-	free(lpptbuf);
-	free(rpptbuf);
-	zleactive = 0;
-	alarm(0);
-    } LASTALLOC;
-    zsfree(curhistline);
+	    if (!kungetct)
+		zrefresh();
+    }
+    statusline = NULL;
+    invalidatelist();
+    trashzle();
+    free(lpromptbuf);
+    free(rpromptbuf);
+    zleactive = zlereadflags = lastlistlen = 0;
+    alarm(0);
+
     freeundo();
     if (eofsent) {
 	free(line);
@@ -548,9 +612,10 @@ zleread(char *lp, char *rp, int ha)
 /* execute a widget */
 
 /**/
-void
-execzlefunc(Thingy func)
+int
+execzlefunc(Thingy func, char **args)
 {
+    int r = 0, ret = 0;
     Widget w;
 
     if(func->flags & DISABLED) {
@@ -561,8 +626,8 @@ execzlefunc(Thingy func)
 	zsfree(nm);
 	showmsg(msg);
 	zsfree(msg);
-	feep();
-    } else if((w = func->widget)->flags & WIDGET_INT) {
+	ret = 1;
+    } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) {
 	int wflags = w->flags;
 
 	if(!(wflags & ZLE_KEEPSUFFIX))
@@ -575,12 +640,18 @@ execzlefunc(Thingy func)
 	    vilinerange = 1;
 	if(!(wflags & ZLE_LASTCOL))
 	    lastcol = -1;
-	w->u.fn();
-	lastcmd = wflags;
+	if (wflags & WIDGET_NCOMP) {
+	    compwidget = w;
+	    ret = completecall(args);
+	} else
+	    ret = w->u.fn(args);
+	if (!(wflags & ZLE_NOTCOMMAND))
+	    lastcmd = wflags;
+	r = 1;
     } else {
-	List l = getshfunc(w->u.fnnam);
+	Eprog prog = getshfunc(w->u.fnnam);
 
-	if(l == &dummy_list) {
+	if(prog == &dummy_eprog) {
 	    /* the shell function doesn't exist */
 	    char *nm = niceztrdup(w->u.fnnam);
 	    char *msg = tricat("No such shell function `", nm, "'");
@@ -588,15 +659,36 @@ execzlefunc(Thingy func)
 	    zsfree(nm);
 	    showmsg(msg);
 	    zsfree(msg);
-	    feep();
+	    ret = 1;
 	} else {
-	  startparamscope();
-	  makezleparams();
-	  doshfunc(l, NULL, 0, 1);
-	  endparamscope();
-	  lastcmd = 0;
+	    int osc = sfcontext, osi = movefd(0), olv = lastval;
+	    LinkList largs = NULL;
+
+	    if (*args) {
+		largs = newlinklist();
+		addlinknode(largs, dupstring(w->u.fnnam));
+		while (*args)
+		    addlinknode(largs, dupstring(*args++));
+	    }
+	    startparamscope();
+	    makezleparams(0);
+	    sfcontext = SFC_WIDGET;
+	    doshfunc(w->u.fnnam, prog, largs, 0, 0);
+	    ret = lastval;
+	    lastval = olv;
+	    sfcontext = osc;
+	    endparamscope();
+	    lastcmd = 0;
+	    r = 1;
+	    redup(osi, 0);
 	}
     }
+    if (r) {
+	unrefthingy(lbindk);
+	refthingy(func);
+	lbindk = func;
+    }
+    return ret;
 }
 
 /* initialise command modifiers */
@@ -628,17 +720,30 @@ handleprefixes(void)
 	initmodifier(&zmod);
 }
 
+/* this exports the argument we are currently vared'iting if != NULL */
+
+/**/
+mod_export char *varedarg;
+
 /* vared: edit (literally) a parameter value */
 
 /**/
 static int
 bin_vared(char *name, char **args, char *ops, int func)
 {
-    char *s;
-    char *t;
-    Param pm;
-    int create = 0;
+    char *s, *t, *ova = varedarg;
+    struct value vbuf;
+    Value v;
+    Param pm = 0;
+    int create = 0, ifl;
+    int type = PM_SCALAR, obreaks = breaks, haso = 0;
     char *p1 = NULL, *p2 = NULL;
+    FILE *oshout = NULL;
+
+    if (zleactive) {
+	zwarnnam(name, "ZLE cannot be used recursively (yet)", NULL, 0);
+	return 1;
+    }
 
     /* all options are handled as arguments */
     while (*args && **args == '-') {
@@ -649,6 +754,12 @@ bin_vared(char *name, char **args, char *ops, int func)
 		yet exist */
 		create = 1;
 		break;
+	    case 'a':
+		type = PM_ARRAY;
+		break;
+	    case 'A':
+		type = PM_HASHED;
+		break;
 	    case 'p':
 		/* -p option -- set main prompt string */
 		if ((*args)[1])
@@ -677,6 +788,10 @@ bin_vared(char *name, char **args, char *ops, int func)
 		/* -h option -- enable history */
 		ops['h'] = 1;
 		break;
+	    case 'e':
+		/* -e option -- enable EOF */
+		ops['e'] = 1;
+		break;
 	    default:
 		/* unrecognised option character */
 		zwarnnam(name, "unknown option: %s", *args, 0);
@@ -684,6 +799,9 @@ bin_vared(char *name, char **args, char *ops, int func)
 	    }
 	args++;
     }
+    if (type && !create) {
+	zwarnnam(name, "-%s ignored", type == PM_ARRAY ? "a" : "A", 0);
+    }
 
     /* check we have a parameter name */
     if (!*args) {
@@ -691,63 +809,98 @@ bin_vared(char *name, char **args, char *ops, int func)
 	return 1;
     }
     /* handle non-existent parameter */
-    if (!(s = getsparam(args[0]))) {
-	if (create)
-	    createparam(args[0], PM_SCALAR);
-	else {
-	    zwarnnam(name, "no such variable: %s", args[0], 0);
+    s = args[0];
+    v = fetchvalue(&vbuf, &s, (!create || type == PM_SCALAR),
+		   SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY);
+    if (!v && !create) {
+	zwarnnam(name, "no such variable: %s", args[0], 0);
+	return 1;
+    } else if (v) {
+	s = getstrvalue(v);
+	pm = v->pm;
+    } else if (*s) {
+	zwarnnam(name, "invalid parameter name: %s", args[0], 0);
+	return 1;
+    }
+
+    if (SHTTY == -1) {
+	/* need to open /dev/tty specially */
+	if ((SHTTY = open("/dev/tty", O_RDWR|O_NOCTTY)) == -1) {
+	    zwarnnam(name, "can't access terminal", NULL, 0);
 	    return 1;
 	}
-    }
+	oshout = shout;
+	init_shout();
 
-    if(zleactive) {
-	zwarnnam(name, "ZLE cannot be used recursively (yet)", NULL, 0);
-	return 1;
+	haso = 1;
     }
-
     /* edit the parameter value */
-    PERMALLOC {
-	pushnode(bufstack, ztrdup(s));
-    } LASTALLOC;
-    t = (char *) zleread(p1, p2, ops['h']);
+    zpushnode(bufstack, ztrdup(s));
+
+    varedarg = *args;
+    ifl = isfirstln;
+    if (ops['e'])
+	isfirstln = 1;
+    if (ops['h'])
+	hbegin(1);
+    t = (char *) zleread(p1, p2, ops['h'] ? ZLRF_HISTORY : 0);
+    if (ops['h'])
+	hend();
+    isfirstln = ifl;
+    varedarg = ova;
+    if (haso) {
+	fclose(shout);	/* close(SHTTY) */
+	shout = oshout;
+	SHTTY = -1;
+    }
     if (!t || errflag) {
 	/* error in editing */
 	errflag = 0;
+	breaks = obreaks;
 	return 1;
     }
     /* strip off trailing newline, if any */
     if (t[strlen(t) - 1] == '\n')
 	t[strlen(t) - 1] = '\0';
     /* final assignment of parameter value */
-    pm = (Param) paramtab->getnode(paramtab, args[0]);
-    if (pm && PM_TYPE(pm->flags) == PM_ARRAY) {
+    if (create && (!pm || (type && PM_TYPE(pm->flags) != type))) {
+	if (pm)
+	    unsetparam(args[0]);
+	createparam(args[0], type);
+	pm = 0;
+    }
+    if (!pm)
+	pm = (Param) paramtab->getnode(paramtab, args[0]);
+    if (pm && (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) {
 	char **a;
 
-	PERMALLOC {
-	    a = spacesplit(t, 1);
-	} LASTALLOC;
-	setaparam(args[0], a);
+	a = spacesplit(t, 1, 0);
+	if (PM_TYPE(pm->flags) == PM_ARRAY)
+	    setaparam(args[0], a);
+	else
+	    sethparam(args[0], a);
     } else
 	setsparam(args[0], t);
     return 0;
 }
 
 /**/
-void
-describekeybriefly(void)
+int
+describekeybriefly(char **args)
 {
     char *seq, *str, *msg, *is;
     Thingy func;
 
     if (statusline)
-	return;
+	return 1;
+    clearlist = 1;
     statusline = "Describe key briefly: _";
     statusll = strlen(statusline);
-    refresh();
+    zrefresh();
     seq = getkeymapcmd(curkeymap, &func, &str);
     statusline = NULL;
     if(!*seq)
-	return;
+	return 1;
     msg = bindztrdup(seq);
     msg = appstr(msg, " is ");
     if (!func)
@@ -758,6 +911,7 @@ describekeybriefly(void)
     zsfree(is);
     showmsg(msg);
     zsfree(msg);
+    return 0;
 }
 
 #define MAXFOUND 4
@@ -788,13 +942,13 @@ scanfindfunc(char *seq, Thingy func, char *str, void *magic)
 }
 
 /**/
-void
-whereis(void)
+int
+whereis(char **args)
 {
     struct findfunc ff;
 
     if (!(ff.func = executenamedcommand("Where is: ")))
-	return;
+	return 1;
     ff.found = 0;
     ff.msg = niceztrdup(ff.func->nam);
     scankeymap(curkeymap, 1, scanfindfunc, &ff);
@@ -804,56 +958,97 @@ whereis(void)
 	ff.msg = appstr(ff.msg, " et al");
     showmsg(ff.msg);
     zsfree(ff.msg);
+    return 0;
 }
 
 /**/
-void
+mod_export void
 trashzle(void)
 {
     if (zleactive) {
-	/* This refresh() is just to get the main editor display right and *
-	 * get the cursor in the right place.  For that reason, we disable *
-	 * list display (which would otherwise result in infinite          *
-	 * recursion [at least, it would if refresh() didn't have its      *
-	 * extra `inlist' check]).                                         */
+	/* This zrefresh() is just to get the main editor display right and *
+	 * get the cursor in the right place.  For that reason, we disable  *
+	 * list display (which would otherwise result in infinite           *
+	 * recursion [at least, it would if zrefresh() didn't have its      *
+	 * extra `inlist' check]).                                          */
 	int sl = showinglist;
 	showinglist = 0;
-	refresh();
+	zrefresh();
 	showinglist = sl;
 	moveto(nlnct, 0);
 	if (clearflag && tccan(TCCLEAREOD)) {
 	    tcout(TCCLEAREOD);
-	    clearflag = 0;
+	    clearflag = listshown = 0;
 	}
 	if (postedit)
 	    fprintf(shout, "%s", postedit);
 	fflush(shout);
 	resetneeded = 1;
-	settyinfo(&shttyinfo);
+	if (!(zlereadflags & ZLRF_NOSETTY))
+	  settyinfo(&shttyinfo);
     }
     if (errflag)
 	kungetct = 0;
 }
 
+/* Hook functions. Used to allow access to zle parameters if zle is
+ * active. */
+
+static int
+zlebeforetrap(Hookdef dummy, void *dat)
+{
+    if (zleactive) {
+	startparamscope();
+	makezleparams(1);
+    }
+    return 0;
+}
+
+static int
+zleaftertrap(Hookdef dummy, void *dat)
+{
+    if (zleactive)
+	endparamscope();
+
+    return 0;
+}
+
 static struct builtin bintab[] = {
     BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaMldDANmrsLR", NULL),
     BUILTIN("vared",   0, bin_vared,   1,  7, 0, NULL,             NULL),
-    BUILTIN("zle",     0, bin_zle,     0, -1, 0, "lDANL",          NULL),
+    BUILTIN("zle",     0, bin_zle,     0, -1, 0, "lDANCLmMgGcRaU", NULL),
+};
+
+/* The order of the entries in this table has to match the *HOOK
+ * macros in zle.h */
+
+/**/
+mod_export struct hookdef zlehooks[] = {
+    HOOKDEF("list_matches", NULL, 0),
+    HOOKDEF("complete", NULL, 0),
+    HOOKDEF("before_complete", NULL, 0),
+    HOOKDEF("after_complete", NULL, 0),
+    HOOKDEF("accept_completion", NULL, 0),
+    HOOKDEF("reverse_menu", NULL, 0),
+    HOOKDEF("invalidate_list", NULL, 0),
 };
 
 /**/
 int
-boot_zle(Module m)
+setup_(Module m)
 {
     /* Set up editor entry points */
     trashzleptr = trashzle;
     gotwordptr = gotword;
-    refreshptr = refresh;
+    refreshptr = zrefresh;
     spaceinlineptr = spaceinline;
     zlereadptr = zleread;
 
+    getkeyptr = getkey;
+
     /* initialise the thingies */
     init_thingies();
+    lbindk = NULL;
 
     /* miscellaneous initialisations */
     stackhist = stackcs = -1;
@@ -862,25 +1057,50 @@ boot_zle(Module m)
     /* initialise the keymap system */
     init_keymaps();
 
-    addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    varedarg = NULL;
+
+    incompfunc = incompctlfunc = hascompmod = 0;
+
+    clwords = (char **) zcalloc((clwsize = 16) * sizeof(char *));
+
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
-cleanup_zle(Module m)
+boot_(Module m)
 {
-    int i;
+    addhookfunc("before_trap", (Hookfn) zlebeforetrap);
+    addhookfunc("after_trap", (Hookfn) zleaftertrap);
+    addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    addhookdefs(m->nam, zlehooks, sizeof(zlehooks)/sizeof(*zlehooks));
+    return 0;
+}
 
+/**/
+int
+cleanup_(Module m)
+{
     if(zleactive) {
 	zerrnam(m->nam, "can't unload the zle module while zle is active",
 	    NULL, 0);
 	return 1;
     }
-
+    deletehookfunc("before_trap", (Hookfn) zlebeforetrap);
+    deletehookfunc("after_trap", (Hookfn) zleaftertrap);
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    deletehookdefs(m->nam, zlehooks, sizeof(zlehooks)/sizeof(*zlehooks));
+    return 0;
+}
+
+/**/
+int
+finish_(Module m)
+{
+    int i;
+
+    unrefthingy(lbindk);
+
     cleanup_keymaps();
     deletehashtable(thingytab);
 
@@ -901,7 +1121,9 @@ cleanup_zle(Module m)
     spaceinlineptr = noop_function_int;
     zlereadptr = fallback_zleread;
 
+    getkeyptr = NULL;
+
+    zfree(clwords, clwsize * sizeof(char *));
+
     return 0;
 }
-
-#endif /* MODULE */
diff --git a/Src/builtin.c b/Src/builtin.c
index 7e536756a..508df9a4d 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -3428,8 +3428,8 @@ bin_read(char *name, char **args, char *ops, int func)
 	     *readpmpt && *readpmpt != '?'; readpmpt++);
 	if (*readpmpt++) {
 	    if (keys || isatty(0)) {
-		zputs(readpmpt, (haso ? shout : stderr));
-		fflush(haso ? shout : stderr);
+		zputs(readpmpt, shout);
+		fflush(shout);
 	    }
 	    readpmpt[-1] = '\0';
 	}
@@ -3469,8 +3469,7 @@ bin_read(char *name, char **args, char *ops, int func)
 	    else
 		settyinfo(&shttyinfo);
 	    if (haso) {
-		close(SHTTY);
-		fclose(shout);
+		fclose(shout);	/* close(SHTTY) */
 		shout = oshout;
 		SHTTY = -1;
 	    }
@@ -3502,8 +3501,7 @@ bin_read(char *name, char **args, char *ops, int func)
 
 	    /* dispose of result appropriately, etc. */
 	    if (haso) {
-		close(SHTTY);
-		fclose(shout);
+		fclose(shout);	/* close(SHTTY) */
 		shout = oshout;
 		SHTTY = -1;
 	    }