summaryrefslogtreecommitdiff
path: root/Src/Zle/zle_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle/zle_main.c')
-rw-r--r--Src/Zle/zle_main.c907
1 files changed, 907 insertions, 0 deletions
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
new file mode 100644
index 000000000..338cdef41
--- /dev/null
+++ b/Src/Zle/zle_main.c
@@ -0,0 +1,907 @@
+/*
+ * zle_main.c - main routines for line editor
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1992-1997 Paul Falstad
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Paul Falstad or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Paul Falstad and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Paul Falstad and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Paul Falstad and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "zle.mdh"
+#include "zle_main.pro"
+
+/* != 0 if we're done editing */
+
+/**/
+int done;
+
+/* location of mark */
+
+/**/
+int mark;
+
+/* last character pressed */
+
+/**/
+int c;
+
+/* the binding for this key */
+
+/**/
+Thingy bindk;
+
+/* insert mode/overwrite mode flag */
+
+/**/
+int insmode;
+
+static int eofchar, eofsent;
+static long keytimeout;
+
+#ifdef HAVE_SELECT
+/* Terminal baud rate */
+
+static int baud;
+#endif
+
+/* flags associated with last command */
+
+/**/
+int lastcmd;
+
+/* the status line, and its length */
+
+/**/
+char *statusline;
+/**/
+int statusll;
+
+/* The current history line and cursor position for the top line *
+ * on the buffer stack. */
+
+/**/
+int stackhist, stackcs;
+
+/* != 0 if we are making undo records */
+
+/**/
+int undoing;
+
+/* current modifier status */
+
+/**/
+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 *
+ * is 0, the modifier status is reset; if it is 1, the modifier *
+ * status is left unchanged, and this flag is reset to 0. The *
+ * effect is that several prefix commands can be executed, and have *
+ * cumulative effect, but any other command execution will clear the *
+ * modifiers. */
+
+/**/
+int prefixflag;
+
+/* != 0 if there is a pending beep (usually indicating an error) */
+
+/**/
+int feepflag;
+
+/* set up terminal */
+
+/**/
+void
+setterm(void)
+{
+ struct ttyinfo ti;
+
+#if defined(CLOBBERS_TYPEAHEAD) && defined(FIONREAD)
+ int val;
+
+ ioctl(SHTTY, FIONREAD, (char *)&val);
+ if (val)
+ return;
+#endif
+
+/* sanitize the tty */
+#ifdef HAS_TIO
+ shttyinfo.tio.c_lflag |= ICANON | ECHO;
+# ifdef FLUSHO
+ shttyinfo.tio.c_lflag &= ~FLUSHO;
+# endif
+#else /* not HAS_TIO */
+ shttyinfo.sgttyb.sg_flags = (shttyinfo.sgttyb.sg_flags & ~CBREAK) | ECHO;
+ shttyinfo.lmodes &= ~LFLUSHO;
+#endif
+
+ attachtty(mypgrp);
+ ti = shttyinfo;
+#ifdef HAS_TIO
+ if (unset(FLOWCONTROL))
+ ti.tio.c_iflag &= ~IXON;
+ ti.tio.c_lflag &= ~(ICANON | ECHO
+# ifdef FLUSHO
+ | FLUSHO
+# endif
+ );
+# ifdef TAB3
+ ti.tio.c_oflag &= ~TAB3;
+# else
+# ifdef OXTABS
+ ti.tio.c_oflag &= ~OXTABS;
+# else
+ ti.tio.c_oflag &= ~XTABS;
+# endif
+# endif
+ ti.tio.c_oflag |= ONLCR;
+ ti.tio.c_cc[VQUIT] =
+# ifdef VDISCARD
+ ti.tio.c_cc[VDISCARD] =
+# endif
+# ifdef VSUSP
+ ti.tio.c_cc[VSUSP] =
+# endif
+# ifdef VDSUSP
+ ti.tio.c_cc[VDSUSP] =
+# endif
+# ifdef VSWTCH
+ ti.tio.c_cc[VSWTCH] =
+# endif
+# ifdef VLNEXT
+ ti.tio.c_cc[VLNEXT] =
+# endif
+ VDISABLEVAL;
+# if defined(VSTART) && defined(VSTOP)
+ if (unset(FLOWCONTROL))
+ ti.tio.c_cc[VSTART] = ti.tio.c_cc[VSTOP] = VDISABLEVAL;
+# endif
+ eofchar = ti.tio.c_cc[VEOF];
+ ti.tio.c_cc[VMIN] = 1;
+ ti.tio.c_cc[VTIME] = 0;
+ ti.tio.c_iflag |= (INLCR | ICRNL);
+ /* this line exchanges \n and \r; it's changed back in getkey
+ so that the net effect is no change at all inside the shell.
+ This double swap is to allow typeahead in common cases, eg.
+
+ % bindkey -s '^J' 'echo foo^M'
+ % sleep 10
+ echo foo<return> <--- typed before sleep returns
+
+ The shell sees \n instead of \r, since it was changed by the kernel
+ while zsh wasn't looking. Then in getkey() \n is changed back to \r,
+ and it sees "echo foo<accept line>", as expected. Without the double
+ swap the shell would see "echo foo\n", which is translated to
+ "echo fooecho foo<accept line>" because of the binding.
+ Note that if you type <line-feed> during the sleep the shell just sees
+ \n, which is translated to \r in getkey(), and you just get another
+ prompt. For type-ahead to work in ALL cases you have to use
+ stty inlcr.
+
+ Unfortunately it's IMPOSSIBLE to have a general solution if both
+ <return> and <line-feed> are mapped to the same character. The shell
+ could check if there is input and read it before setting it's own
+ terminal modes but if we get a \n we don't know whether to keep it or
+ change to \r :-(
+ */
+
+#else /* not HAS_TIO */
+ ti.sgttyb.sg_flags = (ti.sgttyb.sg_flags | CBREAK) & ~ECHO & ~XTABS;
+ ti.lmodes &= ~LFLUSHO;
+ eofchar = ti.tchars.t_eofc;
+ ti.tchars.t_quitc =
+ ti.ltchars.t_suspc =
+ ti.ltchars.t_flushc =
+ ti.ltchars.t_dsuspc = ti.ltchars.t_lnextc = -1;
+#endif
+
+#if defined(TTY_NEEDS_DRAINING) && defined(TIOCOUTQ) && defined(HAVE_SELECT)
+ if (baud) { /**/
+ int n = 0;
+
+ while ((ioctl(SHTTY, TIOCOUTQ, (char *)&n) >= 0) && n) {
+ struct timeval tv;
+
+ tv.tv_sec = n / baud;
+ tv.tv_usec = ((n % baud) * 1000000) / baud;
+ select(0, NULL, NULL, NULL, &tv);
+ }
+ }
+#endif
+
+ settyinfo(&ti);
+}
+
+static char *kungetbuf;
+static int kungetct, kungetsz;
+
+/**/
+void
+ungetkey(int ch)
+{
+ if (kungetct == kungetsz)
+ kungetbuf = realloc(kungetbuf, kungetsz *= 2);
+ kungetbuf[kungetct++] = ch;
+}
+
+/**/
+void
+ungetkeys(char *s, int len)
+{
+ s += len;
+ while (len--)
+ ungetkey(*--s);
+}
+
+#if defined(pyr) && defined(HAVE_SELECT)
+static int
+breakread(int fd, char *buf, int n)
+{
+ fd_set f;
+
+ FD_ZERO(&f);
+ FD_SET(fd, &f);
+ return (select(fd + 1, (SELECT_ARG_2_T) & f, NULL, NULL, NULL) == -1 ?
+ EOF : read(fd, buf, n));
+}
+
+# define read breakread
+#endif
+
+/**/
+int
+getkey(int keytmout)
+{
+ char cc;
+ unsigned int ret;
+ long exp100ths;
+ int die = 0, r, icnt = 0;
+ int old_errno = errno;
+
+#ifdef HAVE_SELECT
+ fd_set foofd;
+
+#else
+# ifdef HAS_TIO
+ struct ttyinfo ti;
+
+# endif
+#endif
+
+ if (kungetct)
+ ret = STOUC(kungetbuf[--kungetct]);
+ else {
+ if (keytmout) {
+ if (keytimeout > 500)
+ exp100ths = 500;
+ else if (keytimeout > 0)
+ exp100ths = keytimeout;
+ else
+ exp100ths = 0;
+#ifdef HAVE_SELECT
+ if (exp100ths) {
+ struct timeval expire_tv;
+
+ expire_tv.tv_sec = exp100ths / 100;
+ expire_tv.tv_usec = (exp100ths % 100) * 10000L;
+ FD_ZERO(&foofd);
+ FD_SET(SHTTY, &foofd);
+ if (select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
+ NULL, NULL, &expire_tv) <= 0)
+ return EOF;
+ }
+#else
+# ifdef HAS_TIO
+ ti = shttyinfo;
+ ti.tio.c_lflag &= ~ICANON;
+ ti.tio.c_cc[VMIN] = 0;
+ ti.tio.c_cc[VTIME] = exp100ths / 10;
+# ifdef HAVE_TERMIOS_H
+ tcsetattr(SHTTY, TCSANOW, &ti.tio);
+# else
+ ioctl(SHTTY, TCSETA, &ti.tio);
+# endif
+ r = read(SHTTY, &cc, 1);
+# ifdef HAVE_TERMIOS_H
+ tcsetattr(SHTTY, TCSANOW, &shttyinfo.tio);
+# else
+ ioctl(SHTTY, TCSETA, &shttyinfo.tio);
+# endif
+ return (r <= 0) ? EOF : cc;
+# endif
+#endif
+ }
+ while ((r = read(SHTTY, &cc, 1)) != 1) {
+ if (r == 0) {
+ /* The test for IGNOREEOF was added to make zsh ignore ^Ds
+ that were typed while commands are running. Unfortuantely
+ this caused trouble under at least one system (SunOS 4.1).
+ Here shells that lost their xterm (e.g. if it was killed
+ with -9) didn't fail to read from the terminal but instead
+ happily continued to read EOFs, so that the above read
+ returned with 0, and, with IGNOREEOF set, this caused
+ an infinite loop. The simple way around this was to add
+ the counter (icnt) so that this happens 20 times and than
+ the shell gives up (yes, this is a bit dirty...). */
+ if (isset(IGNOREEOF) && icnt++ < 20)
+ continue;
+ stopmsg = 1;
+ zexit(1, 0);
+ }
+ icnt = 0;
+ if (errno == EINTR) {
+ die = 0;
+ if (!errflag && !retflag && !breaks)
+ continue;
+ errflag = 0;
+ errno = old_errno;
+ return EOF;
+ } else if (errno == EWOULDBLOCK) {
+ fcntl(0, F_SETFL, 0);
+ } else if (errno == EIO && !die) {
+ ret = opts[MONITOR];
+ opts[MONITOR] = 1;
+ attachtty(mypgrp);
+ refresh(); /* kludge! */
+ opts[MONITOR] = ret;
+ die = 1;
+ } else if (errno != 0) {
+ zerr("error on TTY read: %e", NULL, errno);
+ stopmsg = 1;
+ zexit(1, 0);
+ }
+ }
+ if (cc == '\r') /* undo the exchange of \n and \r determined by */
+ cc = '\n'; /* setterm() */
+ else if (cc == '\n')
+ cc = '\r';
+
+ ret = STOUC(cc);
+ }
+ if (vichgflag) {
+ if (vichgbufptr == vichgbufsz)
+ vichgbuf = realloc(vichgbuf, vichgbufsz *= 2);
+ vichgbuf[vichgbufptr++] = ret;
+ }
+ errno = old_errno;
+ return ret;
+}
+
+/* Read a line. It is returned metafied. */
+
+/**/
+unsigned char *
+zleread(char *lp, char *rp, int ha)
+{
+ unsigned char *s;
+ int old_errno = errno;
+ int tmout = getiparam("TMOUT");
+
+#ifdef HAVE_SELECT
+ long costmult;
+ struct timeval tv;
+ fd_set foofd;
+
+ 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 *
+ * select loop is used in a function called from ZLE. vared handles *
+ * this differently itself. */
+ if(zleactive) {
+ char *pptbuf;
+ int pptlen;
+
+ pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen);
+ write(2, (WRITE_ARG_2_T)pptbuf, pptlen);
+ free(pptbuf);
+ return (unsigned char *)shingetline();
+ }
+
+ keytimeout = getiparam("KEYTIMEOUT");
+ if (!shout) {
+ if (SHTTY != -1)
+ init_shout();
+
+ if (!shout)
+ return NULL;
+ /* We could be smarter and default to a system read. */
+
+ /* If we just got a new shout, make sure the terminal is set up. */
+ if (termflags & TERM_UNKNOWN)
+ init_term();
+ }
+
+ fflush(shout);
+ fflush(stderr);
+ intr();
+ insmode = unset(OVERSTRIKE);
+ eofsent = 0;
+ resetneeded = 0;
+ lpptbuf = promptexpand(lp, 1, NULL, NULL);
+ pmpt_attr = txtchange;
+ rpptbuf = promptexpand(rp, 1, NULL, NULL);
+ rpmpt_attr = txtchange;
+ histallowed = ha;
+ PERMALLOC {
+ histline = curhist;
+#ifdef HAVE_SELECT
+ 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;
+ 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;
+ }
+ }
+ 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
+#endif
+ if (!kungetct)
+ refresh();
+ handlefeep();
+ }
+ statusline = NULL;
+ invalidatelist();
+ trashzle();
+ free(lpptbuf);
+ free(rpptbuf);
+ zleactive = 0;
+ alarm(0);
+ } LASTALLOC;
+ zsfree(curhistline);
+ freeundo();
+ if (eofsent) {
+ free(line);
+ line = NULL;
+ } else {
+ line[ll++] = '\n';
+ line = (unsigned char *) metafy((char *) line, ll, META_REALLOC);
+ }
+ forget_edits();
+ errno = old_errno;
+ return line;
+}
+
+/* execute a widget */
+
+/**/
+void
+execzlefunc(Thingy func)
+{
+ Widget w;
+
+ if(func->flags & DISABLED) {
+ /* this thingy is not the name of a widget */
+ char *nm = niceztrdup(func->nam);
+ char *msg = tricat("No such widget `", nm, "'");
+
+ zsfree(nm);
+ showmsg(msg);
+ zsfree(msg);
+ feep();
+ } else if((w = func->widget)->flags & WIDGET_INT) {
+ int wflags = w->flags;
+
+ if(!(wflags & ZLE_KEEPSUFFIX))
+ removesuffix();
+ if(!(wflags & ZLE_MENUCMP)) {
+ fixsuffix();
+ invalidatelist();
+ }
+ if (wflags & ZLE_LINEMOVE)
+ vilinerange = 1;
+ if(!(wflags & ZLE_LASTCOL))
+ lastcol = -1;
+ w->u.fn();
+ lastcmd = wflags;
+ } else {
+ List l = getshfunc(w->u.fnnam);
+
+ if(l == &dummy_list) {
+ /* the shell function doesn't exist */
+ char *nm = niceztrdup(w->u.fnnam);
+ char *msg = tricat("No such shell function `", nm, "'");
+
+ zsfree(nm);
+ showmsg(msg);
+ zsfree(msg);
+ feep();
+ } else {
+ startparamscope();
+ makezleparams();
+ doshfunc(l, NULL, 0, 1);
+ endparamscope();
+ lastcmd = 0;
+ }
+ }
+}
+
+/* initialise command modifiers */
+
+/**/
+static void
+initmodifier(struct modifier *mp)
+{
+ mp->flags = 0;
+ mp->mult = 1;
+ mp->tmult = 1;
+ mp->vibuf = 0;
+}
+
+/* Reset command modifiers, unless the command just executed was a prefix. *
+ * Also set zmult, if the multiplier has been amended. */
+
+/**/
+static void
+handleprefixes(void)
+{
+ if (prefixflag) {
+ prefixflag = 0;
+ if(zmod.flags & MOD_TMULT) {
+ zmod.flags |= MOD_MULT;
+ zmod.mult = zmod.tmult;
+ }
+ } else
+ initmodifier(&zmod);
+}
+
+/* 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 *p1 = NULL, *p2 = NULL;
+
+ /* all options are handled as arguments */
+ while (*args && **args == '-') {
+ while (*++(*args))
+ switch (**args) {
+ case 'c':
+ /* -c option -- allow creation of the parameter if it doesn't
+ yet exist */
+ create = 1;
+ break;
+ case 'p':
+ /* -p option -- set main prompt string */
+ if ((*args)[1])
+ p1 = *args + 1, *args = "" - 1;
+ else if (args[1])
+ p1 = *(++args), *args = "" - 1;
+ else {
+ zwarnnam(name, "prompt string expected after -%c", NULL,
+ **args);
+ return 1;
+ }
+ break;
+ case 'r':
+ /* -r option -- set right prompt string */
+ if ((*args)[1])
+ p2 = *args + 1, *args = "" - 1;
+ else if (args[1])
+ p2 = *(++args), *args = "" - 1;
+ else {
+ zwarnnam(name, "prompt string expected after -%c", NULL,
+ **args);
+ return 1;
+ }
+ break;
+ case 'h':
+ /* -h option -- enable history */
+ ops['h'] = 1;
+ break;
+ default:
+ /* unrecognised option character */
+ zwarnnam(name, "unknown option: %s", *args, 0);
+ return 1;
+ }
+ args++;
+ }
+
+ /* check we have a parameter name */
+ if (!*args) {
+ zwarnnam(name, "missing variable", NULL, 0);
+ 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);
+ return 1;
+ }
+ }
+
+ if(zleactive) {
+ zwarnnam(name, "ZLE cannot be used recursively (yet)", NULL, 0);
+ return 1;
+ }
+
+ /* edit the parameter value */
+ PERMALLOC {
+ pushnode(bufstack, ztrdup(s));
+ } LASTALLOC;
+ t = (char *) zleread(p1, p2, ops['h']);
+ if (!t || errflag) {
+ /* error in editing */
+ errflag = 0;
+ 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) {
+ char **a;
+
+ PERMALLOC {
+ a = spacesplit(t, 1);
+ } LASTALLOC;
+ setaparam(args[0], a);
+ } else
+ setsparam(args[0], t);
+ return 0;
+}
+
+/**/
+void
+describekeybriefly(void)
+{
+ char *seq, *str, *msg, *is;
+ Thingy func;
+
+ if (statusline)
+ return;
+ statusline = "Describe key briefly: _";
+ statusll = strlen(statusline);
+ refresh();
+ seq = getkeymapcmd(curkeymap, &func, &str);
+ statusline = NULL;
+ if(!*seq)
+ return;
+ msg = bindztrdup(seq);
+ msg = appstr(msg, " is ");
+ if (!func)
+ is = bindztrdup(str);
+ else
+ is = niceztrdup(func->nam);
+ msg = appstr(msg, is);
+ zsfree(is);
+ showmsg(msg);
+ zsfree(msg);
+}
+
+#define MAXFOUND 4
+
+struct findfunc {
+ Thingy func;
+ int found;
+ char *msg;
+};
+
+/**/
+static void
+scanfindfunc(char *seq, Thingy func, char *str, void *magic)
+{
+ struct findfunc *ff = magic;
+
+ if(func != ff->func)
+ return;
+ if (!ff->found++)
+ ff->msg = appstr(ff->msg, " is on");
+ if(ff->found <= MAXFOUND) {
+ char *b = bindztrdup(seq);
+
+ ff->msg = appstr(ff->msg, " ");
+ ff->msg = appstr(ff->msg, b);
+ zsfree(b);
+ }
+}
+
+/**/
+void
+whereis(void)
+{
+ struct findfunc ff;
+
+ if (!(ff.func = executenamedcommand("Where is: ")))
+ return;
+ ff.found = 0;
+ ff.msg = niceztrdup(ff.func->nam);
+ scankeymap(curkeymap, 1, scanfindfunc, &ff);
+ if (!ff.found)
+ ff.msg = appstr(ff.msg, " is not bound to any key");
+ else if(ff.found > MAXFOUND)
+ ff.msg = appstr(ff.msg, " et al");
+ showmsg(ff.msg);
+ zsfree(ff.msg);
+}
+
+/**/
+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]). */
+ int sl = showinglist;
+ showinglist = 0;
+ refresh();
+ showinglist = sl;
+ moveto(nlnct, 0);
+ if (clearflag && tccan(TCCLEAREOD)) {
+ tcout(TCCLEAREOD);
+ clearflag = 0;
+ }
+ if (postedit)
+ fprintf(shout, "%s", postedit);
+ fflush(shout);
+ resetneeded = 1;
+ settyinfo(&shttyinfo);
+ }
+ if (errflag)
+ kungetct = 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),
+};
+
+/**/
+int
+boot_zle(Module m)
+{
+ /* Set up editor entry points */
+ trashzleptr = trashzle;
+ gotwordptr = gotword;
+ refreshptr = refresh;
+ spaceinlineptr = spaceinline;
+ zlereadptr = zleread;
+
+ /* initialise the thingies */
+ init_thingies();
+
+ /* miscellaneous initialisations */
+ stackhist = stackcs = -1;
+ kungetbuf = (char *) zalloc(kungetsz = 32);
+
+ /* initialise the keymap system */
+ init_keymaps();
+
+ addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ return 0;
+}
+
+#ifdef MODULE
+
+/**/
+int
+cleanup_zle(Module m)
+{
+ int i;
+
+ if(zleactive) {
+ zerrnam(m->nam, "can't unload the zle module while zle is active",
+ NULL, 0);
+ return 1;
+ }
+
+ deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ cleanup_keymaps();
+ deletehashtable(thingytab);
+
+ zfree(vichgbuf, vichgbufsz);
+ zfree(kungetbuf, kungetsz);
+ free_isrch_spots();
+
+ zfree(cutbuf.buf, cutbuf.len);
+ for(i = KRINGCT; i--; )
+ zfree(kring[i].buf, kring[i].len);
+ for(i = 35; i--; )
+ zfree(vibuf[i].buf, vibuf[i].len);
+
+ /* editor entry points */
+ trashzleptr = noop_function;
+ gotwordptr = noop_function;
+ refreshptr = noop_function;
+ spaceinlineptr = noop_function_int;
+ zlereadptr = fallback_zleread;
+
+ return 0;
+}
+
+#endif /* MODULE */