summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/libedit/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 17:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 17:47:29 +0000
commit4f5791ebd03eaec1c7da0865a383175b05102712 (patch)
tree8ce7b00f7a76baa386372422adebbe64510812d4 /third_party/heimdal/lib/libedit/src
parentInitial commit. (diff)
downloadsamba-upstream.tar.xz
samba-upstream.zip
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/heimdal/lib/libedit/src')
-rw-r--r--third_party/heimdal/lib/libedit/src/Makefile.am43
-rw-r--r--third_party/heimdal/lib/libedit/src/chared.c753
-rw-r--r--third_party/heimdal/lib/libedit/src/chared.h155
-rw-r--r--third_party/heimdal/lib/libedit/src/chartype.c340
-rw-r--r--third_party/heimdal/lib/libedit/src/chartype.h114
-rw-r--r--third_party/heimdal/lib/libedit/src/common.c835
-rw-r--r--third_party/heimdal/lib/libedit/src/editline.3997
-rw-r--r--third_party/heimdal/lib/libedit/src/editline.7935
-rw-r--r--third_party/heimdal/lib/libedit/src/editrc.5317
-rw-r--r--third_party/heimdal/lib/libedit/src/el.c640
-rw-r--r--third_party/heimdal/lib/libedit/src/el.h153
-rw-r--r--third_party/heimdal/lib/libedit/src/eln.c388
-rw-r--r--third_party/heimdal/lib/libedit/src/emacs.c512
-rw-r--r--third_party/heimdal/lib/libedit/src/filecomplete.c573
-rw-r--r--third_party/heimdal/lib/libedit/src/filecomplete.h44
-rw-r--r--third_party/heimdal/lib/libedit/src/getline.c128
-rw-r--r--third_party/heimdal/lib/libedit/src/hist.c245
-rw-r--r--third_party/heimdal/lib/libedit/src/hist.h79
-rw-r--r--third_party/heimdal/lib/libedit/src/histedit.h313
-rw-r--r--third_party/heimdal/lib/libedit/src/history.c1157
-rw-r--r--third_party/heimdal/lib/libedit/src/historyn.c3
-rw-r--r--third_party/heimdal/lib/libedit/src/keymacro.c669
-rw-r--r--third_party/heimdal/lib/libedit/src/keymacro.h76
-rw-r--r--third_party/heimdal/lib/libedit/src/makelist177
-rw-r--r--third_party/heimdal/lib/libedit/src/map.c1427
-rw-r--r--third_party/heimdal/lib/libedit/src/map.h79
-rw-r--r--third_party/heimdal/lib/libedit/src/parse.c289
-rw-r--r--third_party/heimdal/lib/libedit/src/parse.h48
-rw-r--r--third_party/heimdal/lib/libedit/src/prompt.c199
-rw-r--r--third_party/heimdal/lib/libedit/src/prompt.h58
-rw-r--r--third_party/heimdal/lib/libedit/src/read.c628
-rw-r--r--third_party/heimdal/lib/libedit/src/read.h45
-rw-r--r--third_party/heimdal/lib/libedit/src/readline.c2367
-rw-r--r--third_party/heimdal/lib/libedit/src/readline/readline.h227
-rw-r--r--third_party/heimdal/lib/libedit/src/refresh.c1187
-rw-r--r--third_party/heimdal/lib/libedit/src/refresh.h57
-rw-r--r--third_party/heimdal/lib/libedit/src/search.c641
-rw-r--r--third_party/heimdal/lib/libedit/src/search.h64
-rw-r--r--third_party/heimdal/lib/libedit/src/shlib_version5
-rw-r--r--third_party/heimdal/lib/libedit/src/sig.c205
-rw-r--r--third_party/heimdal/lib/libedit/src/sig.h70
-rw-r--r--third_party/heimdal/lib/libedit/src/sys.h112
-rw-r--r--third_party/heimdal/lib/libedit/src/terminal.c1691
-rw-r--r--third_party/heimdal/lib/libedit/src/terminal.h125
-rw-r--r--third_party/heimdal/lib/libedit/src/tokenizer.c466
-rw-r--r--third_party/heimdal/lib/libedit/src/tokenizern.c3
-rw-r--r--third_party/heimdal/lib/libedit/src/tty.c1342
-rw-r--r--third_party/heimdal/lib/libedit/src/tty.h481
-rw-r--r--third_party/heimdal/lib/libedit/src/unvis.c553
-rw-r--r--third_party/heimdal/lib/libedit/src/vi.c1157
-rw-r--r--third_party/heimdal/lib/libedit/src/vis.c728
-rw-r--r--third_party/heimdal/lib/libedit/src/vis.h120
-rw-r--r--third_party/heimdal/lib/libedit/src/wcsdup.c43
53 files changed, 24063 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/libedit/src/Makefile.am b/third_party/heimdal/lib/libedit/src/Makefile.am
new file mode 100644
index 0000000..565e56e
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/Makefile.am
@@ -0,0 +1,43 @@
+
+BUILT_SOURCES = vi.h emacs.h common.h fcns.h help.h func.h
+
+AHDR= vi.h emacs.h common.h
+ASRC= $(srcdir)/vi.c $(srcdir)/emacs.c $(srcdir)/common.c
+
+vi.h: Makefile $(srcdir)/makelist $(srcdir)/vi.c
+ AWK=$(AWK) sh $(srcdir)/makelist -h $(srcdir)/vi.c > $@
+
+emacs.h: Makefile $(srcdir)/makelist $(srcdir)/emacs.c
+ AWK=$(AWK) sh $(srcdir)/makelist -h $(srcdir)/emacs.c > $@
+
+common.h: Makefile $(srcdir)/makelist $(srcdir)/common.c
+ AWK=$(AWK) sh $(srcdir)/makelist -h $(srcdir)/common.c > $@
+
+fcns.h: Makefile $(srcdir)/makelist $(AHDR)
+ AWK=$(AWK) sh $(srcdir)/makelist -fh $(AHDR) > $@
+
+func.h: Makefile $(srcdir)/makelist $(AHDR)
+ AWK=$(AWK) sh $(srcdir)/makelist -fc $(AHDR) > $@
+
+help.h: Makefile $(srcdir)/makelist $(ASRC)
+ AWK=$(AWK) sh $(srcdir)/makelist -bh $(ASRC) > $@
+
+CLEANFILES = $(BUILT_SOURCES)
+
+lib_LTLIBRARIES = libheimedit.la
+libheimedit_la_SOURCES = \
+ chared.c chartype.c common.c el.c eln.c emacs.c filecomplete.c getline.c hist.c \
+ history.c historyn.c keymacro.c map.c parse.c prompt.c read.c readline.c \
+ refresh.c search.c sig.c terminal.c tokenizer.c tokenizern.c tty.c \
+ unvis.c vi.c vis.c wcsdup.c \
+ chared.h chartype.h readline/readline.h el.h filecomplete.h \
+ histedit.h hist.h keymacro.h map.h parse.h prompt.h read.h \
+ refresh.h search.h sig.h sys.h terminal.h tty.h vis.h
+
+EXTRA_DIST = makelist shlib_version
+EXTRA_DIST += histedit.h readline/readline.h
+
+nodist_libheimedit_la_SOURCES = $(BUILT_SOURCES)
+
+libheimedit_la_LDFLAGS = -no-undefined -version-info $(LT_VERSION)
+
diff --git a/third_party/heimdal/lib/libedit/src/chared.c b/third_party/heimdal/lib/libedit/src/chared.c
new file mode 100644
index 0000000..9d46ba6
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/chared.c
@@ -0,0 +1,753 @@
+/* $NetBSD: chared.c,v 1.56 2016/05/22 19:44:26 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: chared.c,v 1.56 2016/05/22 19:44:26 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * chared.c: Character editor utilities
+ */
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "el.h"
+#include "common.h"
+#include "fcns.h"
+
+/* value to leave unused in line buffer */
+#define EL_LEAVE 2
+
+/* cv_undo():
+ * Handle state for the vi undo command
+ */
+libedit_private void
+cv_undo(EditLine *el)
+{
+ c_undo_t *vu = &el->el_chared.c_undo;
+ c_redo_t *r = &el->el_chared.c_redo;
+ size_t size;
+
+ /* Save entire line for undo */
+ size = (size_t)(el->el_line.lastchar - el->el_line.buffer);
+ vu->len = (ssize_t)size;
+ vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer);
+ (void)memcpy(vu->buf, el->el_line.buffer, size * sizeof(*vu->buf));
+
+ /* save command info for redo */
+ r->count = el->el_state.doingarg ? el->el_state.argument : 0;
+ r->action = el->el_chared.c_vcmd.action;
+ r->pos = r->buf;
+ r->cmd = el->el_state.thiscmd;
+ r->ch = el->el_state.thisch;
+}
+
+/* cv_yank():
+ * Save yank/delete data for paste
+ */
+libedit_private void
+cv_yank(EditLine *el, const wchar_t *ptr, int size)
+{
+ c_kill_t *k = &el->el_chared.c_kill;
+
+ (void)memcpy(k->buf, ptr, (size_t)size * sizeof(*k->buf));
+ k->last = k->buf + size;
+}
+
+
+/* c_insert():
+ * Insert num characters
+ */
+libedit_private void
+c_insert(EditLine *el, int num)
+{
+ wchar_t *cp;
+
+ if (el->el_line.lastchar + num >= el->el_line.limit) {
+ if (!ch_enlargebufs(el, (size_t)num))
+ return; /* can't go past end of buffer */
+ }
+
+ if (el->el_line.cursor < el->el_line.lastchar) {
+ /* if I must move chars */
+ for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
+ cp[num] = *cp;
+ }
+ el->el_line.lastchar += num;
+}
+
+
+/* c_delafter():
+ * Delete num characters after the cursor
+ */
+libedit_private void
+c_delafter(EditLine *el, int num)
+{
+
+ if (el->el_line.cursor + num > el->el_line.lastchar)
+ num = (int)(el->el_line.lastchar - el->el_line.cursor);
+
+ if (el->el_map.current != el->el_map.emacs) {
+ cv_undo(el);
+ cv_yank(el, el->el_line.cursor, num);
+ }
+
+ if (num > 0) {
+ wchar_t *cp;
+
+ for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
+ *cp = cp[num];
+
+ el->el_line.lastchar -= num;
+ }
+}
+
+
+/* c_delafter1():
+ * Delete the character after the cursor, do not yank
+ */
+libedit_private void
+c_delafter1(EditLine *el)
+{
+ wchar_t *cp;
+
+ for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
+ *cp = cp[1];
+
+ el->el_line.lastchar--;
+}
+
+
+/* c_delbefore():
+ * Delete num characters before the cursor
+ */
+libedit_private void
+c_delbefore(EditLine *el, int num)
+{
+
+ if (el->el_line.cursor - num < el->el_line.buffer)
+ num = (int)(el->el_line.cursor - el->el_line.buffer);
+
+ if (el->el_map.current != el->el_map.emacs) {
+ cv_undo(el);
+ cv_yank(el, el->el_line.cursor - num, num);
+ }
+
+ if (num > 0) {
+ wchar_t *cp;
+
+ for (cp = el->el_line.cursor - num;
+ cp <= el->el_line.lastchar;
+ cp++)
+ *cp = cp[num];
+
+ el->el_line.lastchar -= num;
+ }
+}
+
+
+/* c_delbefore1():
+ * Delete the character before the cursor, do not yank
+ */
+libedit_private void
+c_delbefore1(EditLine *el)
+{
+ wchar_t *cp;
+
+ for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++)
+ *cp = cp[1];
+
+ el->el_line.lastchar--;
+}
+
+
+/* ce__isword():
+ * Return if p is part of a word according to emacs
+ */
+libedit_private int
+ce__isword(wint_t p)
+{
+ return iswalnum(p) || wcschr(L"*?_-.[]~=", p) != NULL;
+}
+
+
+/* cv__isword():
+ * Return if p is part of a word according to vi
+ */
+libedit_private int
+cv__isword(wint_t p)
+{
+ if (iswalnum(p) || p == L'_')
+ return 1;
+ if (iswgraph(p))
+ return 2;
+ return 0;
+}
+
+
+/* cv__isWord():
+ * Return if p is part of a big word according to vi
+ */
+libedit_private int
+cv__isWord(wint_t p)
+{
+ return !iswspace(p);
+}
+
+
+/* c__prev_word():
+ * Find the previous word
+ */
+libedit_private wchar_t *
+c__prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t))
+{
+ p--;
+
+ while (n--) {
+ while ((p >= low) && !(*wtest)(*p))
+ p--;
+ while ((p >= low) && (*wtest)(*p))
+ p--;
+ }
+
+ /* cp now points to one character before the word */
+ p++;
+ if (p < low)
+ p = low;
+ /* cp now points where we want it */
+ return p;
+}
+
+
+/* c__next_word():
+ * Find the next word
+ */
+libedit_private wchar_t *
+c__next_word(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t))
+{
+ while (n--) {
+ while ((p < high) && !(*wtest)(*p))
+ p++;
+ while ((p < high) && (*wtest)(*p))
+ p++;
+ }
+ if (p > high)
+ p = high;
+ /* p now points where we want it */
+ return p;
+}
+
+/* cv_next_word():
+ * Find the next word vi style
+ */
+libedit_private wchar_t *
+cv_next_word(EditLine *el, wchar_t *p, wchar_t *high, int n,
+ int (*wtest)(wint_t))
+{
+ int test;
+
+ while (n--) {
+ test = (*wtest)(*p);
+ while ((p < high) && (*wtest)(*p) == test)
+ p++;
+ /*
+ * vi historically deletes with cw only the word preserving the
+ * trailing whitespace! This is not what 'w' does..
+ */
+ if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
+ while ((p < high) && iswspace(*p))
+ p++;
+ }
+
+ /* p now points where we want it */
+ if (p > high)
+ return high;
+ else
+ return p;
+}
+
+
+/* cv_prev_word():
+ * Find the previous word vi style
+ */
+libedit_private wchar_t *
+cv_prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t))
+{
+ int test;
+
+ p--;
+ while (n--) {
+ while ((p > low) && iswspace(*p))
+ p--;
+ test = (*wtest)(*p);
+ while ((p >= low) && (*wtest)(*p) == test)
+ p--;
+ }
+ p++;
+
+ /* p now points where we want it */
+ if (p < low)
+ return low;
+ else
+ return p;
+}
+
+
+/* cv_delfini():
+ * Finish vi delete action
+ */
+libedit_private void
+cv_delfini(EditLine *el)
+{
+ int size;
+ int action = el->el_chared.c_vcmd.action;
+
+ if (action & INSERT)
+ el->el_map.current = el->el_map.key;
+
+ if (el->el_chared.c_vcmd.pos == 0)
+ /* sanity */
+ return;
+
+ size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos);
+ if (size == 0)
+ size = 1;
+ el->el_line.cursor = el->el_chared.c_vcmd.pos;
+ if (action & YANK) {
+ if (size > 0)
+ cv_yank(el, el->el_line.cursor, size);
+ else
+ cv_yank(el, el->el_line.cursor + size, -size);
+ } else {
+ if (size > 0) {
+ c_delafter(el, size);
+ re_refresh_cursor(el);
+ } else {
+ c_delbefore(el, -size);
+ el->el_line.cursor += size;
+ }
+ }
+ el->el_chared.c_vcmd.action = NOP;
+}
+
+
+/* cv__endword():
+ * Go to the end of this word according to vi
+ */
+libedit_private wchar_t *
+cv__endword(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t))
+{
+ int test;
+
+ p++;
+
+ while (n--) {
+ while ((p < high) && iswspace(*p))
+ p++;
+
+ test = (*wtest)(*p);
+ while ((p < high) && (*wtest)(*p) == test)
+ p++;
+ }
+ p--;
+ return p;
+}
+
+/* ch_init():
+ * Initialize the character editor
+ */
+libedit_private int
+ch_init(EditLine *el)
+{
+ el->el_line.buffer = el_malloc(EL_BUFSIZ *
+ sizeof(*el->el_line.buffer));
+ if (el->el_line.buffer == NULL)
+ return -1;
+
+ (void) memset(el->el_line.buffer, 0, EL_BUFSIZ *
+ sizeof(*el->el_line.buffer));
+ el->el_line.cursor = el->el_line.buffer;
+ el->el_line.lastchar = el->el_line.buffer;
+ el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
+
+ el->el_chared.c_undo.buf = el_malloc(EL_BUFSIZ *
+ sizeof(*el->el_chared.c_undo.buf));
+ if (el->el_chared.c_undo.buf == NULL)
+ return -1;
+ (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ *
+ sizeof(*el->el_chared.c_undo.buf));
+ el->el_chared.c_undo.len = -1;
+ el->el_chared.c_undo.cursor = 0;
+ el->el_chared.c_redo.buf = el_malloc(EL_BUFSIZ *
+ sizeof(*el->el_chared.c_redo.buf));
+ if (el->el_chared.c_redo.buf == NULL)
+ return -1;
+ el->el_chared.c_redo.pos = el->el_chared.c_redo.buf;
+ el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ;
+ el->el_chared.c_redo.cmd = ED_UNASSIGNED;
+
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_vcmd.pos = el->el_line.buffer;
+
+ el->el_chared.c_kill.buf = el_malloc(EL_BUFSIZ *
+ sizeof(*el->el_chared.c_kill.buf));
+ if (el->el_chared.c_kill.buf == NULL)
+ return -1;
+ (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ *
+ sizeof(*el->el_chared.c_kill.buf));
+ el->el_chared.c_kill.mark = el->el_line.buffer;
+ el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
+ el->el_chared.c_resizefun = NULL;
+ el->el_chared.c_resizearg = NULL;
+ el->el_chared.c_aliasfun = NULL;
+ el->el_chared.c_aliasarg = NULL;
+
+ el->el_map.current = el->el_map.key;
+
+ el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
+ el->el_state.doingarg = 0;
+ el->el_state.metanext = 0;
+ el->el_state.argument = 1;
+ el->el_state.lastcmd = ED_UNASSIGNED;
+
+ return 0;
+}
+
+/* ch_reset():
+ * Reset the character editor
+ */
+libedit_private void
+ch_reset(EditLine *el)
+{
+ el->el_line.cursor = el->el_line.buffer;
+ el->el_line.lastchar = el->el_line.buffer;
+
+ el->el_chared.c_undo.len = -1;
+ el->el_chared.c_undo.cursor = 0;
+
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_vcmd.pos = el->el_line.buffer;
+
+ el->el_chared.c_kill.mark = el->el_line.buffer;
+
+ el->el_map.current = el->el_map.key;
+
+ el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
+ el->el_state.doingarg = 0;
+ el->el_state.metanext = 0;
+ el->el_state.argument = 1;
+ el->el_state.lastcmd = ED_UNASSIGNED;
+
+ el->el_history.eventno = 0;
+}
+
+/* ch_enlargebufs():
+ * Enlarge line buffer to be able to hold twice as much characters.
+ * Returns 1 if successful, 0 if not.
+ */
+libedit_private int
+ch_enlargebufs(EditLine *el, size_t addlen)
+{
+ size_t sz, newsz;
+ wchar_t *newbuffer, *oldbuf, *oldkbuf;
+
+ sz = (size_t)(el->el_line.limit - el->el_line.buffer + EL_LEAVE);
+ newsz = sz * 2;
+ /*
+ * If newly required length is longer than current buffer, we need
+ * to make the buffer big enough to hold both old and new stuff.
+ */
+ if (addlen > sz) {
+ while(newsz - sz < addlen)
+ newsz *= 2;
+ }
+
+ /*
+ * Reallocate line buffer.
+ */
+ newbuffer = el_realloc(el->el_line.buffer, newsz * sizeof(*newbuffer));
+ if (!newbuffer)
+ return 0;
+
+ /* zero the newly added memory, leave old data in */
+ (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer));
+
+ oldbuf = el->el_line.buffer;
+
+ el->el_line.buffer = newbuffer;
+ el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
+ el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
+ /* don't set new size until all buffers are enlarged */
+ el->el_line.limit = &newbuffer[sz - EL_LEAVE];
+
+ /*
+ * Reallocate kill buffer.
+ */
+ newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz *
+ sizeof(*newbuffer));
+ if (!newbuffer)
+ return 0;
+
+ /* zero the newly added memory, leave old data in */
+ (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer));
+
+ oldkbuf = el->el_chared.c_kill.buf;
+
+ el->el_chared.c_kill.buf = newbuffer;
+ el->el_chared.c_kill.last = newbuffer +
+ (el->el_chared.c_kill.last - oldkbuf);
+ el->el_chared.c_kill.mark = el->el_line.buffer +
+ (el->el_chared.c_kill.mark - oldbuf);
+
+ /*
+ * Reallocate undo buffer.
+ */
+ newbuffer = el_realloc(el->el_chared.c_undo.buf,
+ newsz * sizeof(*newbuffer));
+ if (!newbuffer)
+ return 0;
+
+ /* zero the newly added memory, leave old data in */
+ (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer));
+ el->el_chared.c_undo.buf = newbuffer;
+
+ newbuffer = el_realloc(el->el_chared.c_redo.buf,
+ newsz * sizeof(*newbuffer));
+ if (!newbuffer)
+ return 0;
+ el->el_chared.c_redo.pos = newbuffer +
+ (el->el_chared.c_redo.pos - el->el_chared.c_redo.buf);
+ el->el_chared.c_redo.lim = newbuffer +
+ (el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
+ el->el_chared.c_redo.buf = newbuffer;
+
+ if (!hist_enlargebuf(el, sz, newsz))
+ return 0;
+
+ /* Safe to set enlarged buffer size */
+ el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE];
+ if (el->el_chared.c_resizefun)
+ (*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg);
+ return 1;
+}
+
+/* ch_end():
+ * Free the data structures used by the editor
+ */
+libedit_private void
+ch_end(EditLine *el)
+{
+ el_free(el->el_line.buffer);
+ el->el_line.buffer = NULL;
+ el->el_line.limit = NULL;
+ el_free(el->el_chared.c_undo.buf);
+ el->el_chared.c_undo.buf = NULL;
+ el_free(el->el_chared.c_redo.buf);
+ el->el_chared.c_redo.buf = NULL;
+ el->el_chared.c_redo.pos = NULL;
+ el->el_chared.c_redo.lim = NULL;
+ el->el_chared.c_redo.cmd = ED_UNASSIGNED;
+ el_free(el->el_chared.c_kill.buf);
+ el->el_chared.c_kill.buf = NULL;
+ ch_reset(el);
+}
+
+
+/* el_insertstr():
+ * Insert string at cursorI
+ */
+int
+el_winsertstr(EditLine *el, const wchar_t *s)
+{
+ size_t len;
+
+ if (s == NULL || (len = wcslen(s)) == 0)
+ return -1;
+ if (el->el_line.lastchar + len >= el->el_line.limit) {
+ if (!ch_enlargebufs(el, len))
+ return -1;
+ }
+
+ c_insert(el, (int)len);
+ while (*s)
+ *el->el_line.cursor++ = *s++;
+ return 0;
+}
+
+
+/* el_deletestr():
+ * Delete num characters before the cursor
+ */
+void
+el_deletestr(EditLine *el, int n)
+{
+ if (n <= 0)
+ return;
+
+ if (el->el_line.cursor < &el->el_line.buffer[n])
+ return;
+
+ c_delbefore(el, n); /* delete before dot */
+ el->el_line.cursor -= n;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+}
+
+/* el_cursor():
+ * Move the cursor to the left or the right of the current position
+ */
+int
+el_cursor(EditLine *el, int n)
+{
+ if (n == 0)
+ goto out;
+
+ el->el_line.cursor += n;
+
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+out:
+ return (int)(el->el_line.cursor - el->el_line.buffer);
+}
+
+/* c_gets():
+ * Get a string
+ */
+libedit_private int
+c_gets(EditLine *el, wchar_t *buf, const wchar_t *prompt)
+{
+ ssize_t len;
+ wchar_t *cp = el->el_line.buffer, ch;
+
+ if (prompt) {
+ len = (ssize_t)wcslen(prompt);
+ (void)memcpy(cp, prompt, (size_t)len * sizeof(*cp));
+ cp += len;
+ }
+ len = 0;
+
+ for (;;) {
+ el->el_line.cursor = cp;
+ *cp = ' ';
+ el->el_line.lastchar = cp + 1;
+ re_refresh(el);
+
+ if (el_wgetc(el, &ch) != 1) {
+ ed_end_of_file(el, 0);
+ len = -1;
+ break;
+ }
+
+ switch (ch) {
+
+ case L'\b': /* Delete and backspace */
+ case 0177:
+ if (len == 0) {
+ len = -1;
+ break;
+ }
+ len--;
+ cp--;
+ continue;
+
+ case 0033: /* ESC */
+ case L'\r': /* Newline */
+ case L'\n':
+ buf[len] = ch;
+ break;
+
+ default:
+ if (len >= (ssize_t)(EL_BUFSIZ - 16))
+ terminal_beep(el);
+ else {
+ buf[len++] = ch;
+ *cp++ = ch;
+ }
+ continue;
+ }
+ break;
+ }
+
+ el->el_line.buffer[0] = '\0';
+ el->el_line.lastchar = el->el_line.buffer;
+ el->el_line.cursor = el->el_line.buffer;
+ return (int)len;
+}
+
+
+/* c_hpos():
+ * Return the current horizontal position of the cursor
+ */
+libedit_private int
+c_hpos(EditLine *el)
+{
+ wchar_t *ptr;
+
+ /*
+ * Find how many characters till the beginning of this line.
+ */
+ if (el->el_line.cursor == el->el_line.buffer)
+ return 0;
+ else {
+ for (ptr = el->el_line.cursor - 1;
+ ptr >= el->el_line.buffer && *ptr != '\n';
+ ptr--)
+ continue;
+ return (int)(el->el_line.cursor - ptr - 1);
+ }
+}
+
+libedit_private int
+ch_resizefun(EditLine *el, el_zfunc_t f, void *a)
+{
+ el->el_chared.c_resizefun = f;
+ el->el_chared.c_resizearg = a;
+ return 0;
+}
+
+libedit_private int
+ch_aliasfun(EditLine *el, el_afunc_t f, void *a)
+{
+ el->el_chared.c_aliasfun = f;
+ el->el_chared.c_aliasarg = a;
+ return 0;
+}
diff --git a/third_party/heimdal/lib/libedit/src/chared.h b/third_party/heimdal/lib/libedit/src/chared.h
new file mode 100644
index 0000000..39f7d51
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/chared.h
@@ -0,0 +1,155 @@
+/* $NetBSD: chared.h,v 1.30 2016/05/22 19:44:26 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)chared.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.chared.h: Character editor interface
+ */
+#ifndef _h_el_chared
+#define _h_el_chared
+
+/*
+ * This is an issue of basic "vi" look-and-feel. Defining VI_MOVE works
+ * like real vi: i.e. the transition from command<->insert modes moves
+ * the cursor.
+ *
+ * On the other hand we really don't want to move the cursor, because
+ * all the editing commands don't include the character under the cursor.
+ * Probably the best fix is to make all the editing commands aware of
+ * this fact.
+ */
+#define VI_MOVE
+
+/*
+ * Undo information for vi - no undo in emacs (yet)
+ */
+typedef struct c_undo_t {
+ ssize_t len; /* length of saved line */
+ int cursor; /* position of saved cursor */
+ wchar_t *buf; /* full saved text */
+} c_undo_t;
+
+/* redo for vi */
+typedef struct c_redo_t {
+ wchar_t *buf; /* redo insert key sequence */
+ wchar_t *pos;
+ wchar_t *lim;
+ el_action_t cmd; /* command to redo */
+ wchar_t ch; /* char that invoked it */
+ int count;
+ int action; /* from cv_action() */
+} c_redo_t;
+
+/*
+ * Current action information for vi
+ */
+typedef struct c_vcmd_t {
+ int action;
+ wchar_t *pos;
+} c_vcmd_t;
+
+/*
+ * Kill buffer for emacs
+ */
+typedef struct c_kill_t {
+ wchar_t *buf;
+ wchar_t *last;
+ wchar_t *mark;
+} c_kill_t;
+
+typedef void (*el_zfunc_t)(EditLine *, void *);
+typedef const char *(*el_afunc_t)(void *, const char *);
+
+/*
+ * Note that we use both data structures because the user can bind
+ * commands from both editors!
+ */
+typedef struct el_chared_t {
+ c_undo_t c_undo;
+ c_kill_t c_kill;
+ c_redo_t c_redo;
+ c_vcmd_t c_vcmd;
+ el_zfunc_t c_resizefun;
+ el_afunc_t c_aliasfun;
+ void * c_resizearg;
+ void * c_aliasarg;
+} el_chared_t;
+
+
+#define STRQQ "\"\""
+
+#define isglob(a) (strchr("*[]?", (a)) != NULL)
+
+#define NOP 0x00
+#define DELETE 0x01
+#define INSERT 0x02
+#define YANK 0x04
+
+#define CHAR_FWD (+1)
+#define CHAR_BACK (-1)
+
+#define MODE_INSERT 0
+#define MODE_REPLACE 1
+#define MODE_REPLACE_1 2
+
+
+libedit_private int cv__isword(wint_t);
+libedit_private int cv__isWord(wint_t);
+libedit_private void cv_delfini(EditLine *);
+libedit_private wchar_t *cv__endword(wchar_t *, wchar_t *, int, int (*)(wint_t));
+libedit_private int ce__isword(wint_t);
+libedit_private void cv_undo(EditLine *);
+libedit_private void cv_yank(EditLine *, const wchar_t *, int);
+libedit_private wchar_t *cv_next_word(EditLine*, wchar_t *, wchar_t *, int,
+ int (*)(wint_t));
+libedit_private wchar_t *cv_prev_word(wchar_t *, wchar_t *, int, int (*)(wint_t));
+libedit_private wchar_t *c__next_word(wchar_t *, wchar_t *, int, int (*)(wint_t));
+libedit_private wchar_t *c__prev_word(wchar_t *, wchar_t *, int, int (*)(wint_t));
+libedit_private void c_insert(EditLine *, int);
+libedit_private void c_delbefore(EditLine *, int);
+libedit_private void c_delbefore1(EditLine *);
+libedit_private void c_delafter(EditLine *, int);
+libedit_private void c_delafter1(EditLine *);
+libedit_private int c_gets(EditLine *, wchar_t *, const wchar_t *);
+libedit_private int c_hpos(EditLine *);
+
+libedit_private int ch_init(EditLine *);
+libedit_private void ch_reset(EditLine *);
+libedit_private int ch_resizefun(EditLine *, el_zfunc_t, void *);
+libedit_private int ch_aliasfun(EditLine *, el_afunc_t, void *);
+libedit_private int ch_enlargebufs(EditLine *, size_t);
+libedit_private void ch_end(EditLine *);
+
+#endif /* _h_el_chared */
diff --git a/third_party/heimdal/lib/libedit/src/chartype.c b/third_party/heimdal/lib/libedit/src/chartype.c
new file mode 100644
index 0000000..f350dfd
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/chartype.c
@@ -0,0 +1,340 @@
+/* $NetBSD: chartype.c,v 1.30 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * chartype.c: character classification and meta information
+ */
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+__RCSID("$NetBSD: chartype.c,v 1.30 2016/05/09 21:46:56 christos Exp $");
+#endif /* not lint && not SCCSID */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "el.h"
+
+#define CT_BUFSIZ ((size_t)1024)
+
+static int ct_conv_cbuff_resize(ct_buffer_t *, size_t);
+static int ct_conv_wbuff_resize(ct_buffer_t *, size_t);
+
+static int
+ct_conv_cbuff_resize(ct_buffer_t *conv, size_t csize)
+{
+ void *p;
+
+ if (csize <= conv->csize)
+ return 0;
+
+ conv->csize = csize;
+
+ p = el_realloc(conv->cbuff, conv->csize * sizeof(*conv->cbuff));
+ if (p == NULL) {
+ conv->csize = 0;
+ el_free(conv->cbuff);
+ conv->cbuff = NULL;
+ return -1;
+ }
+ conv->cbuff = p;
+ return 0;
+}
+
+static int
+ct_conv_wbuff_resize(ct_buffer_t *conv, size_t wsize)
+{
+ void *p;
+
+ if (wsize <= conv->wsize)
+ return 0;
+
+ conv->wsize = wsize;
+
+ p = el_realloc(conv->wbuff, conv->wsize * sizeof(*conv->wbuff));
+ if (p == NULL) {
+ conv->wsize = 0;
+ el_free(conv->wbuff);
+ conv->wbuff = NULL;
+ return -1;
+ }
+ conv->wbuff = p;
+ return 0;
+}
+
+
+char *
+ct_encode_string(const wchar_t *s, ct_buffer_t *conv)
+{
+ char *dst;
+ ssize_t used;
+
+ if (!s)
+ return NULL;
+
+ dst = conv->cbuff;
+ for (;;) {
+ used = (ssize_t)(dst - conv->cbuff);
+ if ((conv->csize - (size_t)used) < 5) {
+ if (ct_conv_cbuff_resize(conv,
+ conv->csize + CT_BUFSIZ) == -1)
+ return NULL;
+ dst = conv->cbuff + used;
+ }
+ if (!*s)
+ break;
+ used = ct_encode_char(dst, (size_t)5, *s);
+ if (used == -1) /* failed to encode, need more buffer space */
+ abort();
+ ++s;
+ dst += used;
+ }
+ *dst = '\0';
+ return conv->cbuff;
+}
+
+wchar_t *
+ct_decode_string(const char *s, ct_buffer_t *conv)
+{
+ size_t len;
+
+ if (!s)
+ return NULL;
+
+ len = mbstowcs(NULL, s, (size_t)0);
+ if (len == (size_t)-1)
+ return NULL;
+
+ if (conv->wsize < ++len)
+ if (ct_conv_wbuff_resize(conv, len + CT_BUFSIZ) == -1)
+ return NULL;
+
+ mbstowcs(conv->wbuff, s, conv->wsize);
+ return conv->wbuff;
+}
+
+
+libedit_private wchar_t **
+ct_decode_argv(int argc, const char *argv[], ct_buffer_t *conv)
+{
+ size_t bufspace;
+ int i;
+ wchar_t *p;
+ wchar_t **wargv;
+ ssize_t bytes;
+
+ /* Make sure we have enough space in the conversion buffer to store all
+ * the argv strings. */
+ for (i = 0, bufspace = 0; i < argc; ++i)
+ bufspace += argv[i] ? strlen(argv[i]) + 1 : 0;
+ if (conv->wsize < ++bufspace)
+ if (ct_conv_wbuff_resize(conv, bufspace + CT_BUFSIZ) == -1)
+ return NULL;
+
+ wargv = el_malloc((size_t)argc * sizeof(*wargv));
+
+ for (i = 0, p = conv->wbuff; i < argc; ++i) {
+ if (!argv[i]) { /* don't pass null pointers to mbstowcs */
+ wargv[i] = NULL;
+ continue;
+ } else {
+ wargv[i] = p;
+ bytes = (ssize_t)mbstowcs(p, argv[i], bufspace);
+ }
+ if (bytes == -1) {
+ el_free(wargv);
+ return NULL;
+ } else
+ bytes++; /* include '\0' in the count */
+ bufspace -= (size_t)bytes;
+ p += bytes;
+ }
+
+ return wargv;
+}
+
+
+libedit_private size_t
+ct_enc_width(wchar_t c)
+{
+ /* UTF-8 encoding specific values */
+ if (c < 0x80)
+ return 1;
+ else if (c < 0x0800)
+ return 2;
+ else if (c < 0x10000)
+ return 3;
+ else if (c < 0x110000)
+ return 4;
+ else
+ return 0; /* not a valid codepoint */
+}
+
+libedit_private ssize_t
+ct_encode_char(char *dst, size_t len, wchar_t c)
+{
+ ssize_t l = 0;
+ if (len < ct_enc_width(c))
+ return -1;
+ l = wctomb(dst, c);
+
+ if (l < 0) {
+ wctomb(NULL, L'\0');
+ l = 0;
+ }
+ return l;
+}
+
+libedit_private const wchar_t *
+ct_visual_string(const wchar_t *s, ct_buffer_t *conv)
+{
+ wchar_t *dst;
+ ssize_t used;
+
+ if (!s)
+ return NULL;
+
+ if (ct_conv_wbuff_resize(conv, CT_BUFSIZ) == -1)
+ return NULL;
+
+ used = 0;
+ dst = conv->wbuff;
+ while (*s) {
+ used = ct_visual_char(dst,
+ conv->wsize - (size_t)(dst - conv->wbuff), *s);
+ if (used != -1) {
+ ++s;
+ dst += used;
+ continue;
+ }
+
+ /* failed to encode, need more buffer space */
+ used = dst - conv->wbuff;
+ if (ct_conv_wbuff_resize(conv, conv->wsize + CT_BUFSIZ) == -1)
+ return NULL;
+ dst = conv->wbuff + used;
+ }
+
+ if (dst >= (conv->wbuff + conv->wsize)) { /* sigh */
+ used = dst - conv->wbuff;
+ if (ct_conv_wbuff_resize(conv, conv->wsize + CT_BUFSIZ) == -1)
+ return NULL;
+ dst = conv->wbuff + used;
+ }
+
+ *dst = L'\0';
+ return conv->wbuff;
+}
+
+
+
+libedit_private int
+ct_visual_width(wchar_t c)
+{
+ int t = ct_chr_class(c);
+ switch (t) {
+ case CHTYPE_ASCIICTL:
+ return 2; /* ^@ ^? etc. */
+ case CHTYPE_TAB:
+ return 1; /* Hmm, this really need to be handled outside! */
+ case CHTYPE_NL:
+ return 0; /* Should this be 1 instead? */
+ case CHTYPE_PRINT:
+ return wcwidth(c);
+ case CHTYPE_NONPRINT:
+ if (c > 0xffff) /* prefer standard 4-byte display over 5-byte */
+ return 8; /* \U+12345 */
+ else
+ return 7; /* \U+1234 */
+ default:
+ return 0; /* should not happen */
+ }
+}
+
+
+libedit_private ssize_t
+ct_visual_char(wchar_t *dst, size_t len, wchar_t c)
+{
+ int t = ct_chr_class(c);
+ switch (t) {
+ case CHTYPE_TAB:
+ case CHTYPE_NL:
+ case CHTYPE_ASCIICTL:
+ if (len < 2)
+ return -1; /* insufficient space */
+ *dst++ = '^';
+ if (c == '\177')
+ *dst = '?'; /* DEL -> ^? */
+ else
+ *dst = c | 0100; /* uncontrolify it */
+ return 2;
+ case CHTYPE_PRINT:
+ if (len < 1)
+ return -1; /* insufficient space */
+ *dst = c;
+ return 1;
+ case CHTYPE_NONPRINT:
+ /* we only use single-width glyphs for display,
+ * so this is right */
+ if ((ssize_t)len < ct_visual_width(c))
+ return -1; /* insufficient space */
+ *dst++ = '\\';
+ *dst++ = 'U';
+ *dst++ = '+';
+#define tohexdigit(v) "0123456789ABCDEF"[v]
+ if (c > 0xffff) /* prefer standard 4-byte display over 5-byte */
+ *dst++ = tohexdigit(((unsigned int) c >> 16) & 0xf);
+ *dst++ = tohexdigit(((unsigned int) c >> 12) & 0xf);
+ *dst++ = tohexdigit(((unsigned int) c >> 8) & 0xf);
+ *dst++ = tohexdigit(((unsigned int) c >> 4) & 0xf);
+ *dst = tohexdigit(((unsigned int) c ) & 0xf);
+ return c > 0xffff ? 8 : 7;
+ /*FALLTHROUGH*/
+ /* these two should be handled outside this function */
+ default: /* we should never hit the default */
+ return 0;
+ }
+}
+
+
+
+
+libedit_private int
+ct_chr_class(wchar_t c)
+{
+ if (c == '\t')
+ return CHTYPE_TAB;
+ else if (c == '\n')
+ return CHTYPE_NL;
+ else if (c < 0x100 && iswcntrl(c))
+ return CHTYPE_ASCIICTL;
+ else if (iswprint(c))
+ return CHTYPE_PRINT;
+ else
+ return CHTYPE_NONPRINT;
+}
diff --git a/third_party/heimdal/lib/libedit/src/chartype.h b/third_party/heimdal/lib/libedit/src/chartype.h
new file mode 100644
index 0000000..7f4b8d9
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/chartype.h
@@ -0,0 +1,114 @@
+/* $NetBSD: chartype.h,v 1.34 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _h_chartype_f
+#define _h_chartype_f
+
+/* Ideally we should also test the value of the define to see if it
+ * supports non-BMP code points without requiring UTF-16, but nothing
+ * seems to actually advertise this properly, despite Unicode 3.1 having
+ * been around since 2001... */
+#if !defined(__NetBSD__) && !defined(__sun) && !(defined(__APPLE__) && defined(__MACH__)) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
+#ifndef __STDC_ISO_10646__
+/* In many places it is assumed that the first 127 code points are ASCII
+ * compatible, so ensure wchar_t indeed does ISO 10646 and not some other
+ * funky encoding that could break us in weird and wonderful ways. */
+ #error wchar_t must store ISO 10646 characters
+#endif
+#endif
+
+/* Oh for a <uchar.h> with char32_t and __STDC_UTF_32__ in it...
+ * ref: ISO/IEC DTR 19769
+ */
+#if WCHAR_MAX < INT32_MAX
+#warning Build environment does not support non-BMP characters
+#endif
+
+/*
+ * Conversion buffer
+ */
+typedef struct ct_buffer_t {
+ char *cbuff;
+ size_t csize;
+ wchar_t *wbuff;
+ size_t wsize;
+} ct_buffer_t;
+
+/* Encode a wide-character string and return the UTF-8 encoded result. */
+char *ct_encode_string(const wchar_t *, ct_buffer_t *);
+
+/* Decode a (multi)?byte string and return the wide-character string result. */
+wchar_t *ct_decode_string(const char *, ct_buffer_t *);
+
+/* Decode a (multi)?byte argv string array.
+ * The pointer returned must be free()d when done. */
+libedit_private wchar_t **ct_decode_argv(int, const char *[], ct_buffer_t *);
+
+/* Encode a character into the destination buffer, provided there is sufficient
+ * buffer space available. Returns the number of bytes used up (zero if the
+ * character cannot be encoded, -1 if there was not enough space available). */
+libedit_private ssize_t ct_encode_char(char *, size_t, wchar_t);
+libedit_private size_t ct_enc_width(wchar_t);
+
+/* The maximum buffer size to hold the most unwieldy visual representation,
+ * in this case \U+nnnnn. */
+#define VISUAL_WIDTH_MAX ((size_t)8)
+
+/* The terminal is thought of in terms of X columns by Y lines. In the cases
+ * where a wide character takes up more than one column, the adjacent
+ * occupied column entries will contain this faux character. */
+#define MB_FILL_CHAR ((wchar_t)-1)
+
+/* Visual width of character c, taking into account ^? , \0177 and \U+nnnnn
+ * style visual expansions. */
+libedit_private int ct_visual_width(wchar_t);
+
+/* Turn the given character into the appropriate visual format, matching
+ * the width given by ct_visual_width(). Returns the number of characters used
+ * up, or -1 if insufficient space. Buffer length is in count of wchar_t's. */
+libedit_private ssize_t ct_visual_char(wchar_t *, size_t, wchar_t);
+
+/* Convert the given string into visual format, using the ct_visual_char()
+ * function. Uses a static buffer, so not threadsafe. */
+libedit_private const wchar_t *ct_visual_string(const wchar_t *, ct_buffer_t *);
+
+
+/* printable character, use ct_visual_width() to find out display width */
+#define CHTYPE_PRINT ( 0)
+/* control character found inside the ASCII portion of the charset */
+#define CHTYPE_ASCIICTL (-1)
+/* a \t */
+#define CHTYPE_TAB (-2)
+/* a \n */
+#define CHTYPE_NL (-3)
+/* non-printable character */
+#define CHTYPE_NONPRINT (-4)
+/* classification of character c, as one of the above defines */
+libedit_private int ct_chr_class(wchar_t c);
+
+#endif /* _chartype_f */
diff --git a/third_party/heimdal/lib/libedit/src/common.c b/third_party/heimdal/lib/libedit/src/common.c
new file mode 100644
index 0000000..2708605
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/common.c
@@ -0,0 +1,835 @@
+/* $NetBSD: common.c,v 1.47 2016/05/22 19:44:26 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: common.c,v 1.47 2016/05/22 19:44:26 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * common.c: Common Editor functions
+ */
+#include <ctype.h>
+#include <string.h>
+
+#include "el.h"
+#include "common.h"
+#include "fcns.h"
+#include "parse.h"
+#include "vi.h"
+
+/* ed_end_of_file():
+ * Indicate end of file
+ * [^D]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_end_of_file(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ re_goto_bottom(el);
+ *el->el_line.lastchar = '\0';
+ return CC_EOF;
+}
+
+
+/* ed_insert():
+ * Add character to the line
+ * Insert a character [bound to all insert keys]
+ */
+libedit_private el_action_t
+ed_insert(EditLine *el, wint_t c)
+{
+ int count = el->el_state.argument;
+
+ if (c == '\0')
+ return CC_ERROR;
+
+ if (el->el_line.lastchar + el->el_state.argument >=
+ el->el_line.limit) {
+ /* end of buffer space, try to allocate more */
+ if (!ch_enlargebufs(el, (size_t) count))
+ return CC_ERROR; /* error allocating more */
+ }
+
+ if (count == 1) {
+ if (el->el_state.inputmode == MODE_INSERT
+ || el->el_line.cursor >= el->el_line.lastchar)
+ c_insert(el, 1);
+
+ *el->el_line.cursor++ = c;
+ re_fastaddc(el); /* fast refresh for one char. */
+ } else {
+ if (el->el_state.inputmode != MODE_REPLACE_1)
+ c_insert(el, el->el_state.argument);
+
+ while (count-- && el->el_line.cursor < el->el_line.lastchar)
+ *el->el_line.cursor++ = c;
+ re_refresh(el);
+ }
+
+ if (el->el_state.inputmode == MODE_REPLACE_1)
+ return vi_command_mode(el, 0);
+
+ return CC_NORM;
+}
+
+
+/* ed_delete_prev_word():
+ * Delete from beginning of current word to cursor
+ * [M-^?] [^W]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_delete_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *cp, *p, *kp;
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return CC_ERROR;
+
+ cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
+ el->el_state.argument, ce__isword);
+
+ for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
+ *kp++ = *p;
+ el->el_chared.c_kill.last = kp;
+
+ c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */
+ el->el_line.cursor = cp;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer; /* bounds check */
+ return CC_REFRESH;
+}
+
+
+/* ed_delete_next_char():
+ * Delete character under cursor
+ * [^D] [x]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_delete_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+#ifdef DEBUG_EDIT
+#define EL el->el_line
+ (void) fprintf(el->el_errfile,
+ "\nD(b: %p(%ls) c: %p(%ls) last: %p(%ls) limit: %p(%ls)\n",
+ EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
+ EL.lastchar, EL.limit, EL.limit);
+#endif
+ if (el->el_line.cursor == el->el_line.lastchar) {
+ /* if I'm at the end */
+ if (el->el_map.type == MAP_VI) {
+ if (el->el_line.cursor == el->el_line.buffer) {
+ /* if I'm also at the beginning */
+#ifdef KSHVI
+ return CC_ERROR;
+#else
+ /* then do an EOF */
+ terminal_writec(el, c);
+ return CC_EOF;
+#endif
+ } else {
+#ifdef KSHVI
+ el->el_line.cursor--;
+#else
+ return CC_ERROR;
+#endif
+ }
+ } else
+ return CC_ERROR;
+ }
+ c_delafter(el, el->el_state.argument); /* delete after dot */
+ if (el->el_map.type == MAP_VI &&
+ el->el_line.cursor >= el->el_line.lastchar &&
+ el->el_line.cursor > el->el_line.buffer)
+ /* bounds check */
+ el->el_line.cursor = el->el_line.lastchar - 1;
+ return CC_REFRESH;
+}
+
+
+/* ed_kill_line():
+ * Cut to the end of line
+ * [^K] [^K]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *kp, *cp;
+
+ cp = el->el_line.cursor;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.lastchar)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ /* zap! -- delete to end */
+ el->el_line.lastchar = el->el_line.cursor;
+ return CC_REFRESH;
+}
+
+
+/* ed_move_to_end():
+ * Move cursor to the end of line
+ * [^E] [^E]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_move_to_end(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_line.cursor = el->el_line.lastchar;
+ if (el->el_map.type == MAP_VI) {
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+#ifdef VI_MOVE
+ el->el_line.cursor--;
+#endif
+ }
+ return CC_CURSOR;
+}
+
+
+/* ed_move_to_beg():
+ * Move cursor to the beginning of line
+ * [^A] [^A]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_move_to_beg(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_line.cursor = el->el_line.buffer;
+
+ if (el->el_map.type == MAP_VI) {
+ /* We want FIRST non space character */
+ while (iswspace(*el->el_line.cursor))
+ el->el_line.cursor++;
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ }
+ return CC_CURSOR;
+}
+
+
+/* ed_transpose_chars():
+ * Exchange the character to the left of the cursor with the one under it
+ * [^T] [^T]
+ */
+libedit_private el_action_t
+ed_transpose_chars(EditLine *el, wint_t c)
+{
+
+ if (el->el_line.cursor < el->el_line.lastchar) {
+ if (el->el_line.lastchar <= &el->el_line.buffer[1])
+ return CC_ERROR;
+ else
+ el->el_line.cursor++;
+ }
+ if (el->el_line.cursor > &el->el_line.buffer[1]) {
+ /* must have at least two chars entered */
+ c = el->el_line.cursor[-2];
+ el->el_line.cursor[-2] = el->el_line.cursor[-1];
+ el->el_line.cursor[-1] = c;
+ return CC_REFRESH;
+ } else
+ return CC_ERROR;
+}
+
+
+/* ed_next_char():
+ * Move to the right one character
+ * [^F] [^F]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *lim = el->el_line.lastchar;
+
+ if (el->el_line.cursor >= lim ||
+ (el->el_line.cursor == lim - 1 &&
+ el->el_map.type == MAP_VI &&
+ el->el_chared.c_vcmd.action == NOP))
+ return CC_ERROR;
+
+ el->el_line.cursor += el->el_state.argument;
+ if (el->el_line.cursor > lim)
+ el->el_line.cursor = lim;
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* ed_prev_word():
+ * Move to the beginning of the current word
+ * [M-b] [b]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return CC_ERROR;
+
+ el->el_line.cursor = c__prev_word(el->el_line.cursor,
+ el->el_line.buffer,
+ el->el_state.argument,
+ ce__isword);
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* ed_prev_char():
+ * Move to the left one character
+ * [^B] [^B]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor > el->el_line.buffer) {
+ el->el_line.cursor -= el->el_state.argument;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+ } else
+ return CC_ERROR;
+}
+
+
+/* ed_quoted_insert():
+ * Add the next character typed verbatim
+ * [^V] [^V]
+ */
+libedit_private el_action_t
+ed_quoted_insert(EditLine *el, wint_t c)
+{
+ int num;
+
+ tty_quotemode(el);
+ num = el_wgetc(el, &c);
+ tty_noquotemode(el);
+ if (num == 1)
+ return ed_insert(el, c);
+ else
+ return ed_end_of_file(el, 0);
+}
+
+
+/* ed_digit():
+ * Adds to argument or enters a digit
+ */
+libedit_private el_action_t
+ed_digit(EditLine *el, wint_t c)
+{
+
+ if (!iswdigit(c))
+ return CC_ERROR;
+
+ if (el->el_state.doingarg) {
+ /* if doing an arg, add this in... */
+ if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
+ el->el_state.argument = c - '0';
+ else {
+ if (el->el_state.argument > 1000000)
+ return CC_ERROR;
+ el->el_state.argument =
+ (el->el_state.argument * 10) + (c - '0');
+ }
+ return CC_ARGHACK;
+ }
+
+ return ed_insert(el, c);
+}
+
+
+/* ed_argument_digit():
+ * Digit that starts argument
+ * For ESC-n
+ */
+libedit_private el_action_t
+ed_argument_digit(EditLine *el, wint_t c)
+{
+
+ if (!iswdigit(c))
+ return CC_ERROR;
+
+ if (el->el_state.doingarg) {
+ if (el->el_state.argument > 1000000)
+ return CC_ERROR;
+ el->el_state.argument = (el->el_state.argument * 10) +
+ (c - '0');
+ } else { /* else starting an argument */
+ el->el_state.argument = c - '0';
+ el->el_state.doingarg = 1;
+ }
+ return CC_ARGHACK;
+}
+
+
+/* ed_unassigned():
+ * Indicates unbound character
+ * Bound to keys that are not assigned
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_unassigned(EditLine *el __attribute__((__unused__)),
+ wint_t c __attribute__((__unused__)))
+{
+
+ return CC_ERROR;
+}
+
+
+/* ed_ignore():
+ * Input characters that have no effect
+ * [^C ^O ^Q ^S ^Z ^\ ^]] [^C ^O ^Q ^S ^\]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_ignore(EditLine *el __attribute__((__unused__)),
+ wint_t c __attribute__((__unused__)))
+{
+
+ return CC_NORM;
+}
+
+
+/* ed_newline():
+ * Execute command
+ * [^J]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_newline(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ re_goto_bottom(el);
+ *el->el_line.lastchar++ = '\n';
+ *el->el_line.lastchar = '\0';
+ return CC_NEWLINE;
+}
+
+
+/* ed_delete_prev_char():
+ * Delete the character to the left of the cursor
+ * [^?]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor <= el->el_line.buffer)
+ return CC_ERROR;
+
+ c_delbefore(el, el->el_state.argument);
+ el->el_line.cursor -= el->el_state.argument;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+ return CC_REFRESH;
+}
+
+
+/* ed_clear_screen():
+ * Clear screen leaving current line at the top
+ * [^L]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_clear_screen(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ terminal_clear_screen(el); /* clear the whole real screen */
+ re_clear_display(el); /* reset everything */
+ return CC_REFRESH;
+}
+
+
+/* ed_redisplay():
+ * Redisplay everything
+ * ^R
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_redisplay(EditLine *el __attribute__((__unused__)),
+ wint_t c __attribute__((__unused__)))
+{
+
+ return CC_REDISPLAY;
+}
+
+
+/* ed_start_over():
+ * Erase current line and start from scratch
+ * [^G]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_start_over(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ ch_reset(el);
+ return CC_REFRESH;
+}
+
+
+/* ed_sequence_lead_in():
+ * First character in a bound sequence
+ * Placeholder for external keys
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_sequence_lead_in(EditLine *el __attribute__((__unused__)),
+ wint_t c __attribute__((__unused__)))
+{
+
+ return CC_NORM;
+}
+
+
+/* ed_prev_history():
+ * Move to the previous history line
+ * [^P] [k]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ char beep = 0;
+ int sv_event = el->el_history.eventno;
+
+ el->el_chared.c_undo.len = -1;
+ *el->el_line.lastchar = '\0'; /* just in case */
+
+ if (el->el_history.eventno == 0) { /* save the current buffer
+ * away */
+ (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
+ EL_BUFSIZ);
+ el->el_history.last = el->el_history.buf +
+ (el->el_line.lastchar - el->el_line.buffer);
+ }
+ el->el_history.eventno += el->el_state.argument;
+
+ if (hist_get(el) == CC_ERROR) {
+ if (el->el_map.type == MAP_VI) {
+ el->el_history.eventno = sv_event;
+ }
+ beep = 1;
+ /* el->el_history.eventno was fixed by first call */
+ (void) hist_get(el);
+ }
+ if (beep)
+ return CC_REFRESH_BEEP;
+ return CC_REFRESH;
+}
+
+
+/* ed_next_history():
+ * Move to the next history line
+ * [^N] [j]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ el_action_t beep = CC_REFRESH, rval;
+
+ el->el_chared.c_undo.len = -1;
+ *el->el_line.lastchar = '\0'; /* just in case */
+
+ el->el_history.eventno -= el->el_state.argument;
+
+ if (el->el_history.eventno < 0) {
+ el->el_history.eventno = 0;
+ beep = CC_REFRESH_BEEP;
+ }
+ rval = hist_get(el);
+ if (rval == CC_REFRESH)
+ return beep;
+ return rval;
+
+}
+
+
+/* ed_search_prev_history():
+ * Search previous in history for a line matching the current
+ * next search history [M-P] [K]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_search_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ const wchar_t *hp;
+ int h;
+ int found = 0;
+
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_undo.len = -1;
+ *el->el_line.lastchar = '\0'; /* just in case */
+ if (el->el_history.eventno < 0) {
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile,
+ "e_prev_search_hist(): eventno < 0;\n");
+#endif
+ el->el_history.eventno = 0;
+ return CC_ERROR;
+ }
+ if (el->el_history.eventno == 0) {
+ (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
+ EL_BUFSIZ);
+ el->el_history.last = el->el_history.buf +
+ (el->el_line.lastchar - el->el_line.buffer);
+ }
+ if (el->el_history.ref == NULL)
+ return CC_ERROR;
+
+ hp = HIST_FIRST(el);
+ if (hp == NULL)
+ return CC_ERROR;
+
+ c_setpat(el); /* Set search pattern !! */
+
+ for (h = 1; h <= el->el_history.eventno; h++)
+ hp = HIST_NEXT(el);
+
+ while (hp != NULL) {
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
+#endif
+ if ((wcsncmp(hp, el->el_line.buffer, (size_t)
+ (el->el_line.lastchar - el->el_line.buffer)) ||
+ hp[el->el_line.lastchar - el->el_line.buffer]) &&
+ c_hmatch(el, hp)) {
+ found = 1;
+ break;
+ }
+ h++;
+ hp = HIST_NEXT(el);
+ }
+
+ if (!found) {
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "not found\n");
+#endif
+ return CC_ERROR;
+ }
+ el->el_history.eventno = h;
+
+ return hist_get(el);
+}
+
+
+/* ed_search_next_history():
+ * Search next in history for a line matching the current
+ * [M-N] [J]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_search_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ const wchar_t *hp;
+ int h;
+ int found = 0;
+
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_undo.len = -1;
+ *el->el_line.lastchar = '\0'; /* just in case */
+
+ if (el->el_history.eventno == 0)
+ return CC_ERROR;
+
+ if (el->el_history.ref == NULL)
+ return CC_ERROR;
+
+ hp = HIST_FIRST(el);
+ if (hp == NULL)
+ return CC_ERROR;
+
+ c_setpat(el); /* Set search pattern !! */
+
+ for (h = 1; h < el->el_history.eventno && hp; h++) {
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
+#endif
+ if ((wcsncmp(hp, el->el_line.buffer, (size_t)
+ (el->el_line.lastchar - el->el_line.buffer)) ||
+ hp[el->el_line.lastchar - el->el_line.buffer]) &&
+ c_hmatch(el, hp))
+ found = h;
+ hp = HIST_NEXT(el);
+ }
+
+ if (!found) { /* is it the current history number? */
+ if (!c_hmatch(el, el->el_history.buf)) {
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "not found\n");
+#endif
+ return CC_ERROR;
+ }
+ }
+ el->el_history.eventno = found;
+
+ return hist_get(el);
+}
+
+
+/* ed_prev_line():
+ * Move up one line
+ * Could be [k] [^p]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_prev_line(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *ptr;
+ int nchars = c_hpos(el);
+
+ /*
+ * Move to the line requested
+ */
+ if (*(ptr = el->el_line.cursor) == '\n')
+ ptr--;
+
+ for (; ptr >= el->el_line.buffer; ptr--)
+ if (*ptr == '\n' && --el->el_state.argument <= 0)
+ break;
+
+ if (el->el_state.argument > 0)
+ return CC_ERROR;
+
+ /*
+ * Move to the beginning of the line
+ */
+ for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
+ continue;
+
+ /*
+ * Move to the character requested
+ */
+ for (ptr++;
+ nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
+ ptr++)
+ continue;
+
+ el->el_line.cursor = ptr;
+ return CC_CURSOR;
+}
+
+
+/* ed_next_line():
+ * Move down one line
+ * Could be [j] [^n]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_next_line(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *ptr;
+ int nchars = c_hpos(el);
+
+ /*
+ * Move to the line requested
+ */
+ for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
+ if (*ptr == '\n' && --el->el_state.argument <= 0)
+ break;
+
+ if (el->el_state.argument > 0)
+ return CC_ERROR;
+
+ /*
+ * Move to the character requested
+ */
+ for (ptr++;
+ nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
+ ptr++)
+ continue;
+
+ el->el_line.cursor = ptr;
+ return CC_CURSOR;
+}
+
+
+/* ed_command():
+ * Editline extended command
+ * [M-X] [:]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+ed_command(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t tmpbuf[EL_BUFSIZ];
+ int tmplen;
+
+ tmplen = c_gets(el, tmpbuf, L"\n: ");
+ terminal__putc(el, '\n');
+
+ if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
+ terminal_beep(el);
+
+ el->el_map.current = el->el_map.key;
+ re_clear_display(el);
+ return CC_REFRESH;
+}
diff --git a/third_party/heimdal/lib/libedit/src/editline.3 b/third_party/heimdal/lib/libedit/src/editline.3
new file mode 100644
index 0000000..bb57972
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/editline.3
@@ -0,0 +1,997 @@
+.\" $NetBSD: editline.3,v 1.92 2016/05/22 23:54:20 christos Exp $
+.\"
+.\" Copyright (c) 1997-2014 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This file was contributed to The NetBSD Foundation by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd May 22, 2016
+.Dt EDITLINE 3
+.Os
+.Sh NAME
+.Nm editline ,
+.Nm el_init ,
+.Nm el_init_fd ,
+.Nm el_end ,
+.Nm el_reset ,
+.Nm el_gets ,
+.Nm el_wgets ,
+.Nm el_getc ,
+.Nm el_wgetc ,
+.Nm el_push ,
+.Nm el_wpush ,
+.Nm el_parse ,
+.Nm el_wparse ,
+.Nm el_set ,
+.Nm el_wset ,
+.Nm el_get ,
+.Nm el_wget ,
+.Nm el_source ,
+.Nm el_resize ,
+.Nm el_cursor ,
+.Nm el_line ,
+.Nm el_wline ,
+.Nm el_insertstr ,
+.Nm el_winsertstr ,
+.Nm el_deletestr ,
+.Nm el_wdeletestr ,
+.Nm history_init ,
+.Nm history_winit ,
+.Nm history_end ,
+.Nm history_wend ,
+.Nm history ,
+.Nm history_w ,
+.Nm tok_init ,
+.Nm tok_winit ,
+.Nm tok_end ,
+.Nm tok_wend ,
+.Nm tok_reset ,
+.Nm tok_wreset ,
+.Nm tok_line ,
+.Nm tok_wline ,
+.Nm tok_str ,
+.Nm tok_wstr
+.Nd line editor, history and tokenization functions
+.Sh LIBRARY
+.Lb libedit
+.Sh SYNOPSIS
+.In histedit.h
+.Ft EditLine *
+.Fn el_init "const char *prog" "FILE *fin" "FILE *fout" "FILE *ferr"
+.Ft EditLine *
+.Fn el_init_fd "const char *prog" "FILE *fin" "FILE *fout" "FILE *ferr" "int fdin" "int fdout" "int fderr"
+.Ft void
+.Fn el_end "EditLine *e"
+.Ft void
+.Fn el_reset "EditLine *e"
+.Ft const char *
+.Fn el_gets "EditLine *e" "int *count"
+.Ft const wchar_t *
+.Fn el_wgets "EditLine *e" "int *count"
+.Ft int
+.Fn el_getc "EditLine *e" "char *ch"
+.Ft int
+.Fn el_wgetc "EditLine *e" "wchar_t *wc"
+.Ft void
+.Fn el_push "EditLine *e" "const char *mbs"
+.Ft void
+.Fn el_wpush "EditLine *e" "const wchar_t *wcs"
+.Ft int
+.Fn el_parse "EditLine *e" "int argc" "const char *argv[]"
+.Ft int
+.Fn el_wparse "EditLine *e" "int argc" "const wchar_t *argv[]"
+.Ft int
+.Fn el_set "EditLine *e" "int op" "..."
+.Ft int
+.Fn el_wset "EditLine *e" "int op" "..."
+.Ft int
+.Fn el_get "EditLine *e" "int op" "..."
+.Ft int
+.Fn el_wget "EditLine *e" "int op" "..."
+.Ft int
+.Fn el_source "EditLine *e" "const char *file"
+.Ft void
+.Fn el_resize "EditLine *e"
+.Ft int
+.Fn el_cursor "EditLine *e" "int count"
+.Ft const LineInfo *
+.Fn el_line "EditLine *e"
+.Ft const LineInfoW *
+.Fn el_wline "EditLine *e"
+.Ft int
+.Fn el_insertstr "EditLine *e" "const char *str"
+.Ft int
+.Fn el_winsertstr "EditLine *e" "const wchar_t *str"
+.Ft void
+.Fn el_deletestr "EditLine *e" "int count"
+.Ft void
+.Fn el_wdeletestr "EditLine *e" "int count"
+.Ft History *
+.Fn history_init void
+.Ft HistoryW *
+.Fn history_winit void
+.Ft void
+.Fn history_end "History *h"
+.Ft void
+.Fn history_wend "HistoryW *h"
+.Ft int
+.Fn history "History *h" "HistEvent *ev" "int op" "..."
+.Ft int
+.Fn history_w "HistoryW *h" "HistEventW *ev" "int op" "..."
+.Ft Tokenizer *
+.Fn tok_init "const char *IFS"
+.Ft TokenizerW *
+.Fn tok_winit "const wchar_t *IFS"
+.Ft void
+.Fn tok_end "Tokenizer *t"
+.Ft void
+.Fn tok_wend "TokenizerW *t"
+.Ft void
+.Fn tok_reset "Tokenizer *t"
+.Ft void
+.Fn tok_wreset "TokenizerW *t"
+.Ft int
+.Fn tok_line "Tokenizer *t" "const LineInfo *li" "int *argc" "const char **argv[]" "int *cursorc" "int *cursoro"
+.Ft int
+.Fn tok_wline "TokenizerW *t" "const LineInfoW *li" "int *argc" "const wchar_t **argv[]" "int *cursorc" "int *cursoro"
+.Ft int
+.Fn tok_str "Tokenizer *t" "const char *str" "int *argc" "const char **argv[]"
+.Ft int
+.Fn tok_wstr "TokenizerW *t" "const wchar_t *str" "int *argc" "const wchar_t **argv[]"
+.Sh DESCRIPTION
+The
+.Nm
+library provides generic line editing, history and tokenization functions,
+similar to those found in
+.Xr sh 1 .
+.Pp
+These functions are available in the
+.Nm libedit
+library (which needs the
+.Nm libtermcap
+library).
+Programs should be linked with
+.Fl ledit ltermcap .
+.Pp
+The
+.Nm
+library respects the
+.Ev LC_CTYPE
+locale set by the application program and never uses
+.Xr setlocale 3
+to change the locale.
+The only locales supported are UTF-8 and the default C or POSIX locale.
+If any other locale is set, behaviour is undefined.
+.Sh LINE EDITING FUNCTIONS
+The line editing functions use a common data structure,
+.Fa EditLine ,
+which is created by
+.Fn el_init
+or
+.Fn el_init_fd
+and freed by
+.Fn el_end .
+.Pp
+The wide-character functions behave the same way as their narrow
+counterparts.
+.Pp
+The following functions are available:
+.Bl -tag -width 4n
+.It Fn el_init
+Initialize the line editor, and return a data structure
+to be used by all other line editing functions, or
+.Dv NULL
+on failure.
+.Fa prog
+is the name of the invoking program, used when reading the
+.Xr editrc 5
+file to determine which settings to use.
+.Fa fin ,
+.Fa fout
+and
+.Fa ferr
+are the input, output, and error streams (respectively) to use.
+In this documentation, references to
+.Dq the tty
+are actually to this input/output stream combination.
+.It Fn el_init_fd
+Like
+.Fn el_init
+but allows specifying file descriptors for the
+.Xr stdio 3
+corresponding streams, in case those were created with
+.Xr funopen 3 .
+.It Fn el_end
+Clean up and finish with
+.Fa e ,
+assumed to have been created with
+.Fn el_init
+or
+.Fn el_init_fd .
+.It Fn el_reset
+Reset the tty and the parser.
+This should be called after an error which may have upset the tty's
+state.
+.It Fn el_gets
+Read a line from the tty.
+.Fa count
+is modified to contain the number of characters read.
+Returns the line read if successful, or
+.Dv NULL
+if no characters were read or if an error occurred.
+If an error occurred,
+.Fa count
+is set to \-1 and
+.Dv errno
+contains the error code that caused it.
+The return value may not remain valid across calls to
+.Fn el_gets
+and must be copied if the data is to be retained.
+.It Fn el_wgetc
+Read a wide character from the tty, respecting the current locale,
+or from the input queue described in
+.Xr editline 7
+if that is not empty, and store it in
+.Fa wc .
+If an invalid or incomplete character is found, it is discarded,
+.Va errno
+is set to
+.Er EILSEQ ,
+and the next character is read and stored in
+.Fa wc .
+Returns 1 if a valid character was read, 0 on end of file, or \-1 on
+.Xr read 2
+failure.
+In the latter case,
+.Va errno
+is set to indicate the error.
+.It Fn el_getc
+Read a wide character as described for
+.Fn el_wgetc
+and return 0 on end of file or \-1 on failure.
+If the wide character can be represented as a single-byte character,
+convert it with
+.Xr wctob 3 ,
+store the result in
+.Fa ch ,
+and return 1; otherwise, set
+.Va errno
+to
+.Er ERANGE
+and return \-1.
+In the C or POSIX locale, this simply reads a byte, but for any other
+locale, including UTF-8, this is rarely useful.
+.It Fn el_wpush
+Push the wide character string
+.Fa wcs
+back onto the input queue described in
+.Xr editline 7 .
+If the queue overflows, for example due to a recursive macro,
+or if an error occurs, for example because
+.Fa wcs
+is
+.Dv NULL
+or memory allocation fails, the function beeps at the user,
+but does not report the problem to the caller.
+.It Fn el_push
+Use the current locale to convert the multibyte string
+.Fa mbs
+to a wide character string, and pass the result to
+.Fn el_wpush .
+.It Fn el_parse
+Parses the
+.Fa argv
+array (which is
+.Fa argc
+elements in size)
+to execute builtin
+.Nm
+commands.
+If the command is prefixed with
+.Dq prog :
+then
+.Fn el_parse
+will only execute the command if
+.Dq prog
+matches the
+.Fa prog
+argument supplied to
+.Fn el_init .
+The return value is
+\-1 if the command is unknown,
+0 if there was no error or
+.Dq prog
+didn't match, or
+1 if the command returned an error.
+Refer to
+.Xr editrc 5
+for more information.
+.It Fn el_set
+Set
+.Nm
+parameters.
+.Fa op
+determines which parameter to set, and each operation has its
+own parameter list.
+Returns 0 on success, \-1 on failure.
+.Pp
+The following values for
+.Fa op
+are supported, along with the required argument list:
+.Bl -tag -width 4n
+.It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)"
+Define prompt printing function as
+.Fa f ,
+which is to return a string that contains the prompt.
+.It Dv EL_PROMPT_ESC , Fa "char *(*f)(EditLine *)" , Fa "char c"
+Same as
+.Dv EL_PROMPT ,
+but the
+.Fa c
+argument indicates the start/stop literal prompt character.
+.Pp
+If a start/stop literal character is found in the prompt, the
+character itself
+is not printed, but characters after it are printed directly to the
+terminal without affecting the state of the current line.
+A subsequent second start/stop literal character ends this behavior.
+This is typically used to embed literal escape sequences that change the
+color/style of the terminal in the prompt.
+.Dv 0
+unsets it.
+.It Dv EL_REFRESH
+Re-display the current line on the next terminal line.
+.It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)"
+Define right side prompt printing function as
+.Fa f ,
+which is to return a string that contains the prompt.
+.It Dv EL_RPROMPT_ESC , Fa "char *(*f)(EditLine *)" , Fa "char c"
+Define the right prompt printing function but with a literal escape character.
+.It Dv EL_TERMINAL , Fa "const char *type"
+Define terminal type of the tty to be
+.Fa type ,
+or to
+.Ev TERM
+if
+.Fa type
+is
+.Dv NULL .
+.It Dv EL_EDITOR , Fa "const char *mode"
+Set editing mode to
+.Fa mode ,
+which must be one of
+.Dq emacs
+or
+.Dq vi .
+.It Dv EL_SIGNAL , Fa "int flag"
+If
+.Fa flag
+is non-zero,
+.Nm
+will install its own signal handler for the following signals when
+reading command input:
+.Dv SIGCONT ,
+.Dv SIGHUP ,
+.Dv SIGINT ,
+.Dv SIGQUIT ,
+.Dv SIGSTOP ,
+.Dv SIGTERM ,
+.Dv SIGTSTP ,
+and
+.Dv SIGWINCH .
+Otherwise, the current signal handlers will be used.
+.It Dv EL_BIND , Fa "const char *" , Fa "..." , Dv NULL
+Perform the
+.Ic bind
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_ECHOTC , Fa "const char *" , Fa "..." , Dv NULL
+Perform the
+.Ic echotc
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_SETTC , Fa "const char *" , Fa "..." , Dv NULL
+Perform the
+.Ic settc
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_SETTY , Fa "const char *" , Fa "..." , Dv NULL
+Perform the
+.Ic setty
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_TELLTC , Fa "const char *" , Fa "..." , Dv NULL
+Perform the
+.Ic telltc
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_ADDFN , Fa "const char *name" , Fa "const char *help" , \
+Fa "unsigned char (*func)(EditLine *e, int ch)"
+Add a user defined function,
+.Fn func ,
+referred to as
+.Fa name
+which is invoked when a key which is bound to
+.Fa name
+is entered.
+.Fa help
+is a description of
+.Fa name .
+At invocation time,
+.Fa ch
+is the key which caused the invocation.
+The return value of
+.Fn func
+should be one of:
+.Bl -tag -width "CC_REDISPLAY"
+.It Dv CC_NORM
+Add a normal character.
+.It Dv CC_NEWLINE
+End of line was entered.
+.It Dv CC_EOF
+EOF was entered.
+.It Dv CC_ARGHACK
+Expecting further command input as arguments, do nothing visually.
+.It Dv CC_REFRESH
+Refresh display.
+.It Dv CC_REFRESH_BEEP
+Refresh display, and beep.
+.It Dv CC_CURSOR
+Cursor moved, so update and perform
+.Dv CC_REFRESH .
+.It Dv CC_REDISPLAY
+Redisplay entire input line.
+This is useful if a key binding outputs extra information.
+.It Dv CC_ERROR
+An error occurred.
+Beep, and flush tty.
+.It Dv CC_FATAL
+Fatal error, reset tty to known state.
+.El
+.It Dv EL_HIST , Fa "History *(*func)(History *, int op, ...)" , \
+Fa "const char *ptr"
+Defines which history function to use, which is usually
+.Fn history .
+.Fa ptr
+should be the value returned by
+.Fn history_init .
+.It Dv EL_EDITMODE , Fa "int flag"
+If
+.Fa flag
+is non-zero,
+editing is enabled (the default).
+Note that this is only an indication, and does not
+affect the operation of
+.Nm .
+At this time, it is the caller's responsibility to
+check this
+(using
+.Fn el_get )
+to determine if editing should be enabled or not.
+.It Dv EL_UNBUFFERED , Fa "int flag"
+If
+.Fa flag
+is zero,
+unbuffered mode is disabled (the default).
+In unbuffered mode,
+.Fn el_gets
+will return immediately after processing a single character.
+.It Dv EL_GETCFN , Fa "el_rfunc_t f"
+Whenever reading a character, use the function
+.Bd -ragged -offset indent -compact
+.Ft int
+.Fo f
+.Fa "EditLine *e"
+.Fa "wchar_t *wc"
+.Fc
+.Ed
+which stores the character in
+.Fa wc
+and returns 1 on success, 0 on end of file, or \-1 on I/O or encoding
+errors.
+Functions internally using it include
+.Fn el_wgets ,
+.Fn el_wgetc ,
+.Fn el_gets ,
+and
+.Fn el_getc .
+Initially, a builtin function is installed, and replacing it
+is discouraged because writing such a function is very error prone.
+The builtin function can be restored at any time by passing the
+special value
+.Dv EL_BUILTIN_GETCFN
+instead of a function pointer.
+.It Dv EL_CLIENTDATA , Fa "void *data"
+Register
+.Fa data
+to be associated with this EditLine structure.
+It can be retrieved with the corresponding
+.Fn el_get
+call.
+.It Dv EL_SETFP , Fa "int fd" , Fa "FILE *fp"
+Set the current
+.Nm editline
+file pointer for
+.Dq input
+.Fa fd
+=
+.Dv 0 ,
+.Dq output
+.Fa fd
+=
+.Dv 1 ,
+or
+.Dq error
+.Fa fd
+=
+.Dv 2
+from
+.Fa fp .
+.El
+.It Fn el_get
+Get
+.Nm
+parameters.
+.Fa op
+determines which parameter to retrieve into
+.Fa result .
+Returns 0 if successful, \-1 otherwise.
+.Pp
+The following values for
+.Fa op
+are supported, along with actual type of
+.Fa result :
+.Bl -tag -width 4n
+.It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)" , Fa "char *c"
+Set
+.Fa f
+to a pointer to the function that displays the prompt.
+If
+.Fa c
+is not
+.Dv NULL ,
+set it to the start/stop literal prompt character.
+.It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)" , Fa "char *c"
+Set
+.Fa f
+to a pointer to the function that displays the prompt.
+If
+.Fa c
+is not
+.Dv NULL ,
+set it to the start/stop literal prompt character.
+.It Dv EL_EDITOR , Fa "const char **n"
+Set the name of the editor in
+.Fa n ,
+which will be one of
+.Dq emacs
+or
+.Dq vi .
+.It Dv EL_GETTC , Fa "const char *name" , Fa "void *value"
+If
+.Fa name
+is a valid
+.Xr termcap 5
+capability set
+.Fa value
+to the current value of that capability.
+.It Dv EL_SIGNAL , Fa "int *s"
+Set
+.Fa s
+to non-zero if
+.Nm
+has installed private signal handlers (see
+.Fn el_get
+above).
+.It Dv EL_EDITMODE , Fa "int *c"
+Set
+.Fa c
+to non-zero if editing is enabled.
+.It Dv EL_GETCFN , Fa "el_rfunc_t *f"
+Set
+.Fa f
+to a pointer to the function that reads characters, or to
+.Dv EL_BUILTIN_GETCFN
+if the builtin function is in use.
+.It Dv EL_CLIENTDATA , Fa "void **data"
+Set
+.Fa data
+to the previously registered client data set by an
+.Fn el_set
+call.
+.It Dv EL_UNBUFFERED , Fa "int *c"
+Set
+.Fa c
+to non-zero if unbuffered mode is enabled.
+.It Dv EL_GETFP , Fa "int fd", Fa "FILE **fp"
+Set
+.Fa fp
+to the current
+.Nm editline
+file pointer for
+.Dq input
+.Fa fd
+=
+.Dv 0 ,
+.Dq output
+.Fa fd
+=
+.Dv 1 ,
+or
+.Dq error
+.Fa fd
+=
+.Dv 2 .
+.El
+.It Fn el_source
+Initialize
+.Nm
+by reading the contents of
+.Fa file .
+.Fn el_parse
+is called for each line in
+.Fa file .
+If
+.Fa file
+is
+.Dv NULL ,
+try
+.Pa $HOME/.editrc .
+Refer to
+.Xr editrc 5
+for details on the format of
+.Fa file .
+.Fn el_source
+returns 0 on success and \-1 on error.
+.It Fn el_resize
+Must be called if the terminal size changes.
+If
+.Dv EL_SIGNAL
+has been set with
+.Fn el_set ,
+then this is done automatically.
+Otherwise, it's the responsibility of the application to call
+.Fn el_resize
+on the appropriate occasions.
+.It Fn el_cursor
+Move the cursor to the right (if positive) or to the left (if negative)
+.Fa count
+characters.
+Returns the resulting offset of the cursor from the beginning of the line.
+.It Fn el_line
+Return the editing information for the current line in a
+.Fa LineInfo
+structure, which is defined as follows:
+.Bd -literal
+typedef struct lineinfo {
+ const char *buffer; /* address of buffer */
+ const char *cursor; /* address of cursor */
+ const char *lastchar; /* address of last character */
+} LineInfo;
+.Ed
+.Pp
+.Fa buffer
+is not NUL terminated.
+This function may be called after
+.Fn el_gets
+to obtain the
+.Fa LineInfo
+structure pertaining to line returned by that function,
+and from within user defined functions added with
+.Dv EL_ADDFN .
+.It Fn el_insertstr
+Insert
+.Fa str
+into the line at the cursor.
+Returns \-1 if
+.Fa str
+is empty or won't fit, and 0 otherwise.
+.It Fn el_deletestr
+Delete
+.Fa count
+characters before the cursor.
+.El
+.Sh HISTORY LIST FUNCTIONS
+The history functions use a common data structure,
+.Fa History ,
+which is created by
+.Fn history_init
+and freed by
+.Fn history_end .
+.Pp
+The following functions are available:
+.Bl -tag -width 4n
+.It Fn history_init
+Initialize the history list, and return a data structure
+to be used by all other history list functions, or
+.Dv NULL
+on failure.
+.It Fn history_end
+Clean up and finish with
+.Fa h ,
+assumed to have been created with
+.Fn history_init .
+.It Fn history
+Perform operation
+.Fa op
+on the history list, with optional arguments as needed by the
+operation.
+.Fa ev
+is changed accordingly to operation.
+The following values for
+.Fa op
+are supported, along with the required argument list:
+.Bl -tag -width 4n
+.It Dv H_SETSIZE , Fa "int size"
+Set size of history to
+.Fa size
+elements.
+.It Dv H_GETSIZE
+Get number of events currently in history.
+.It Dv H_END
+Cleans up and finishes with
+.Fa h ,
+assumed to be created with
+.Fn history_init .
+.It Dv H_CLEAR
+Clear the history.
+.It Dv H_FUNC , Fa "void *ptr" , Fa "history_gfun_t first" , \
+Fa "history_gfun_t next" , Fa "history_gfun_t last" , \
+Fa "history_gfun_t prev" , Fa "history_gfun_t curr" , \
+Fa "history_sfun_t set" , Fa "history_vfun_t clear" , \
+Fa "history_efun_t enter" , Fa "history_efun_t add"
+Define functions to perform various history operations.
+.Fa ptr
+is the argument given to a function when it's invoked.
+.It Dv H_FIRST
+Return the first element in the history.
+.It Dv H_LAST
+Return the last element in the history.
+.It Dv H_PREV
+Return the previous element in the history.
+It is newer than the current one.
+.It Dv H_NEXT
+Return the next element in the history.
+It is older than the current one.
+.It Dv H_CURR
+Return the current element in the history.
+.It Dv H_SET
+Set the cursor to point to the requested element.
+.It Dv H_ADD , Fa "const char *str"
+Append
+.Fa str
+to the current element of the history, or perform the
+.Dv H_ENTER
+operation with argument
+.Fa str
+if there is no current element.
+.It Dv H_APPEND , Fa "const char *str"
+Append
+.Fa str
+to the last new element of the history.
+.It Dv H_ENTER , Fa "const char *str"
+Add
+.Fa str
+as a new element to the history and, if necessary,
+removing the oldest entry to keep the list to the created size.
+If
+.Dv H_SETUNIQUE
+has been called with a non-zero argument, the element
+will not be entered into the history if its contents match
+the ones of the current history element.
+If the element is entered
+.Fn history
+returns 1; if it is ignored as a duplicate returns 0.
+Finally
+.Fn history
+returns \-1 if an error occurred.
+.It Dv H_PREV_STR , Fa "const char *str"
+Return the closest previous event that starts with
+.Fa str .
+.It Dv H_NEXT_STR , Fa "const char *str"
+Return the closest next event that starts with
+.Fa str .
+.It Dv H_PREV_EVENT , Fa "int e"
+Return the previous event numbered
+.Fa e .
+.It Dv H_NEXT_EVENT , Fa "int e"
+Return the next event numbered
+.Fa e .
+.It Dv H_LOAD , Fa "const char *file"
+Load the history list stored in
+.Fa file .
+.It Dv H_SAVE , Fa "const char *file"
+Save the history list to
+.Fa file .
+.It Dv H_SAVE_FP , Fa "FILE *fp"
+Save the history list to the opened
+.Ft FILE
+pointer
+.Fa fp .
+.It Dv H_SETUNIQUE , Fa "int unique"
+Set flag that adjacent identical event strings should not be entered
+into the history.
+.It Dv H_GETUNIQUE
+Retrieve the current setting if adjacent identical elements should
+be entered into the history.
+.It Dv H_DEL , Fa "int e"
+Delete the event numbered
+.Fa e .
+This function is only provided for
+.Xr readline 3
+compatibility.
+The caller is responsible for free'ing the string in the returned
+.Fa HistEvent .
+.El
+.Pp
+.Fn history
+returns \*[Gt]= 0 if the operation
+.Fa op
+succeeds.
+Otherwise, \-1 is returned and
+.Fa ev
+is updated to contain more details about the error.
+.El
+.Sh TOKENIZATION FUNCTIONS
+The tokenization functions use a common data structure,
+.Fa Tokenizer ,
+which is created by
+.Fn tok_init
+and freed by
+.Fn tok_end .
+.Pp
+The following functions are available:
+.Bl -tag -width 4n
+.It Fn tok_init
+Initialize the tokenizer, and return a data structure
+to be used by all other tokenizer functions.
+.Fa IFS
+contains the Input Field Separators, which defaults to
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline
+if
+.Dv NULL .
+.It Fn tok_end
+Clean up and finish with
+.Fa t ,
+assumed to have been created with
+.Fn tok_init .
+.It Fn tok_reset
+Reset the tokenizer state.
+Use after a line has been successfully tokenized
+by
+.Fn tok_line
+or
+.Fn tok_str
+and before a new line is to be tokenized.
+.It Fn tok_line
+Tokenize
+.Fa li ,
+If successful, modify:
+.Fa argv
+to contain the words,
+.Fa argc
+to contain the number of words,
+.Fa cursorc
+(if not
+.Dv NULL )
+to contain the index of the word containing the cursor,
+and
+.Fa cursoro
+(if not
+.Dv NULL )
+to contain the offset within
+.Fa argv[cursorc]
+of the cursor.
+.Pp
+Returns
+0 if successful,
+\-1 for an internal error,
+1 for an unmatched single quote,
+2 for an unmatched double quote,
+and
+3 for a backslash quoted
+.Aq newline .
+A positive exit code indicates that another line should be read
+and tokenization attempted again.
+.
+.It Fn tok_str
+A simpler form of
+.Fn tok_line ;
+.Fa str
+is a NUL terminated string to tokenize.
+.El
+.
+.\"XXX.Sh EXAMPLES
+.\"XXX: provide some examples
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr signal 3 ,
+.Xr termcap 3 ,
+.Xr editrc 5 ,
+.Xr termcap 5 ,
+.Xr editline 7
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Bx 4.4 .
+.Dv CC_REDISPLAY
+appeared in
+.Nx 1.3 .
+.Dv CC_REFRESH_BEEP ,
+.Dv EL_EDITMODE
+and the readline emulation appeared in
+.Nx 1.4 .
+.Dv EL_RPROMPT
+appeared in
+.Nx 1.5 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+library was written by
+.An Christos Zoulas .
+.An Luke Mewburn
+wrote this manual and implemented
+.Dv CC_REDISPLAY ,
+.Dv CC_REFRESH_BEEP ,
+.Dv EL_EDITMODE ,
+and
+.Dv EL_RPROMPT .
+.An Jaromir Dolecek
+implemented the readline emulation.
+.An Johny Mattsson
+implemented wide-character support.
+.Sh BUGS
+At this time, it is the responsibility of the caller to
+check the result of the
+.Dv EL_EDITMODE
+operation of
+.Fn el_get
+(after an
+.Fn el_source
+or
+.Fn el_parse )
+to determine if
+.Nm
+should be used for further input.
+I.e.,
+.Dv EL_EDITMODE
+is purely an indication of the result of the most recent
+.Xr editrc 5
+.Ic edit
+command.
diff --git a/third_party/heimdal/lib/libedit/src/editline.7 b/third_party/heimdal/lib/libedit/src/editline.7
new file mode 100644
index 0000000..863bab9
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/editline.7
@@ -0,0 +1,935 @@
+.\" $NetBSD: editline.7,v 1.5 2016/05/09 21:27:55 christos Exp $
+.\" $OpenBSD: editline.7,v 1.1 2016/04/20 01:11:45 schwarze Exp $
+.\"
+.\" Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd May 7, 2016
+.Dt EDITLINE 7
+.Os
+.Sh NAME
+.Nm editline
+.Nd line editing user interface
+.Sh DESCRIPTION
+When a program using the
+.Xr editline 3
+library prompts for an input string using the function
+.Xr el_wgets 3 ,
+it reads characters from the terminal.
+Invalid input bytes that do not form characters are silently
+discarded.
+For each character read, one editor command is executed.
+The mapping of input characters to editor commands depends on the
+editing mode.
+There are three editing modes: vi insert mode, vi command mode,
+and emacs mode.
+The default is vi insert mode.
+The program can switch the default to emacs mode by using the
+.Xr el_set 3
+or
+.Xr el_parse 3
+functions, and the user can switch to emacs mode either in the
+.Xr editrc 5
+configuration file or interactively with the
+.Ic ed-command
+editor command, in all three cases executing the
+.Ic bind Fl e
+builtin command.
+.Pp
+If trying to read from the terminal results in end of file or an
+error, the library signals end of file to the program and does not
+return a string.
+.Ss Input character bindings
+All default bindings described below can be overridden by individual
+programs and can be changed with the
+.Xr editrc 5
+.Ic bind
+builtin command.
+.Pp
+In the following tables,
+.Sq Ctrl-
+indicates a character with the bit 0x40 flipped, and
+.Sq Meta-
+indicates a character with the bit 0x80 set.
+In vi insert mode and in emacs mode, all Meta-characters considered
+printable by the current
+.Xr locale 1
+are bound to
+.Ic ed-insert
+instead of to the editor command listed below.
+Consequently, in UTF-8 mode, most of the Meta-characters are not
+directly accessible because their code points are occupied by
+printable Unicode characters, and Meta-characters are usually input
+using the
+.Ic em-meta-next
+editor command.
+For example, to enter
+.Sq Meta-B
+in order to call the
+.Ic ed-prev-word
+editor command in emacs mode, call
+.Ic em-meta-next
+by pressing and releasing the escape key (or equivalently, Ctrl-[),
+then press and release the
+.Sq B
+key.
+If you have configured a Meta-key on your keyboard, for example
+with
+.Ql setxkbmap -option altwin:left_meta_win ,
+the Ctrl-Meta-characters are directly accessible.
+For example, to enter
+.Sq Ctrl-Meta-H
+in order to call the
+.Ic ed-delete-prev-word
+editor command in emacs mode, hold down the keys
+.Sq Ctrl ,
+.Sq Meta ,
+and
+.Sq H
+at the same time.
+Alternatively, press and release the escape key, then press and
+release
+.Sq Ctrl-H .
+.Pp
+In vi input mode, input characters are bound to the following editor
+commands by default:
+.Bl -column -offset indent "Ctrl-Z, TSTP" "ed-search-next-history"
+.It Ctrl-D, EOF Ta Ic vi-list-or-eof
+.It Ctrl-H, BS Ta Ic vi-delete-prev-char
+.It Ctrl-J, LF Ta Ic ed-newline
+.It Ctrl-M, CR Ta Ic ed-newline
+.It Ctrl-Q Ta Ic ed-tty-start-output
+.It Ctrl-S Ta Ic ed-tty-stop-output
+.It Ctrl-U Ta Ic vi-kill-line-prev
+.It Ctrl-V Ta Ic ed-quoted-insert
+.It Ctrl-W Ta Ic ed-delete-prev-word
+.It Ctrl-[, ESC Ta Ic vi-command-mode
+.It Ctrl-\e, QUIT Ta Ic ed-tty-sigquit
+.It Ctrl-?, DEL Ta Ic vi-delete-prev-char
+.El
+.Pp
+All other input characters except the NUL character (Ctrl-@) are
+bound to
+.Ic ed-insert .
+.Pp
+In vi command mode, input characters are bound to the following
+editor commands by default:
+.Bl -column -offset indent "Ctrl-Z, TSTP" "ed-search-next-history"
+.It Ctrl-A Ta Ic ed-move-to-beg
+.It Ctrl-C, INT Ta Ic ed-tty-sigint
+.It Ctrl-E Ta Ic ed-move-to-end
+.It Ctrl-H, BS Ta Ic ed-delete-prev-char
+.It Ctrl-J, LF Ta Ic ed-newline
+.It Ctrl-K Ta Ic ed-kill-line
+.It Ctrl-L, FF Ta Ic ed-clear-screen
+.It Ctrl-M, CR Ta Ic ed-newline
+.It Ctrl-N Ta Ic ed-next-history
+.It Ctrl-O Ta Ic ed-tty-flush-output
+.It Ctrl-P Ta Ic ed-prev-history
+.It Ctrl-Q Ta Ic ed-tty-start-output
+.It Ctrl-R Ta Ic ed-redisplay
+.It Ctrl-S Ta Ic ed-tty-stop-output
+.It Ctrl-U Ta Ic vi-kill-line-prev
+.It Ctrl-W Ta Ic ed-delete-prev-word
+.It Ctrl-[, ESC Ta Ic em-meta-next
+.It Ctrl-\e, QUIT Ta Ic ed-tty-sigquit
+.It Space Ta Ic ed-next-char
+.It # Ta Ic vi-comment-out
+.It $ Ta Ic ed-move-to-end
+.It % Ta Ic vi-match
+.It + Ta Ic ed-next-history
+.It \&, Ta Ic vi-repeat-prev-char
+.It - Ta Ic ed-prev-history
+.It \&. Ta Ic vi-redo
+.It / Ta Ic vi-search-prev
+.It 0 Ta Ic vi-zero
+.It 1 to 9 Ta Ic ed-argument-digit
+.It \&: Ta Ic ed-command
+.It \&; Ta Ic vi-repeat-next-char
+.It \&? Ta Ic vi-search-next
+.It @ Ta Ic vi-alias
+.It A Ta Ic vi-add-at-eol
+.It B Ta Ic vi-prev-big-word
+.It C Ta Ic vi-change-to-eol
+.It D Ta Ic ed-kill-line
+.It E Ta Ic vi-end-big-word
+.It F Ta Ic vi-prev-char
+.It G Ta Ic vi-to-history-line
+.It I Ta Ic vi-insert-at-bol
+.It J Ta Ic ed-search-next-history
+.It K Ta Ic ed-search-prev-history
+.It N Ta Ic vi-repeat-search-prev
+.It O Ta Ic ed-sequence-lead-in
+.It P Ta Ic vi-paste-prev
+.It R Ta Ic vi-replace-mode
+.It S Ta Ic vi-substitute-line
+.It T Ta Ic vi-to-prev-char
+.It U Ta Ic vi-undo-line
+.It W Ta Ic vi-next-big-word
+.It X Ta Ic ed-delete-prev-char
+.It Y Ta Ic vi-yank-end
+.It \&[ Ta Ic ed-sequence-lead-in
+.It ^ Ta Ic ed-move-to-beg
+.It _ Ta Ic vi-history-word
+.It a Ta Ic vi-add
+.It b Ta Ic vi-prev-word
+.It c Ta Ic vi-change-meta
+.It d Ta Ic vi-delete-meta
+.It e Ta Ic vi-end-word
+.It f Ta Ic vi-next-char
+.It h Ta Ic ed-prev-char
+.It i Ta Ic vi-insert
+.It j Ta Ic ed-next-history
+.It k Ta Ic ed-prev-history
+.It l Ta Ic ed-next-char
+.It n Ta Ic vi-repeat-search-next
+.It p Ta Ic vi-paste-next
+.It r Ta Ic vi-replace-char
+.It s Ta Ic vi-substitute-char
+.It t Ta Ic vi-to-next-char
+.It u Ta Ic vi-undo
+.It v Ta Ic vi-histedit
+.It w Ta Ic vi-next-word
+.It x Ta Ic ed-delete-next-char
+.It y Ta Ic vi-yank
+.It \&| Ta Ic vi-to-column
+.It ~ Ta Ic vi-change-case
+.It Ctrl-?, DEL Ta Ic ed-delete-prev-char
+.It Meta-O Ta Ic ed-sequence-lead-in
+.It Meta-[ Ta Ic ed-sequence-lead-in
+.El
+.Pp
+In emacs mode, input characters are bound to the following editor
+commands by default:
+.Bl -column -offset indent "Ctrl-Z, TSTP" "ed-search-next-history"
+.It 0 to 9 Ta Ic ed-digit
+.It Ctrl-@, NUL Ta Ic em-set-mark
+.It Ctrl-A Ta Ic ed-move-to-beg
+.It Ctrl-B Ta Ic ed-prev-char
+.It Ctrl-C, INT Ta Ic ed-tty-sigint
+.It Ctrl-D, EOF Ta Ic em-delete-or-list
+.It Ctrl-E Ta Ic ed-move-to-end
+.It Ctrl-F Ta Ic ed-next-char
+.It Ctrl-H, BS Ta Ic em-delete-prev-char
+.It Ctrl-J, LF Ta Ic ed-newline
+.It Ctrl-K Ta Ic ed-kill-line
+.It Ctrl-L, FF Ta Ic ed-clear-screen
+.It Ctrl-M, CR Ta Ic ed-newline
+.It Ctrl-N Ta Ic ed-next-history
+.It Ctrl-O Ta Ic ed-tty-flush-output
+.It Ctrl-P Ta Ic ed-prev-history
+.It Ctrl-Q Ta Ic ed-tty-start-output
+.It Ctrl-R Ta Ic ed-redisplay
+.It Ctrl-S Ta Ic ed-tty-stop-output
+.It Ctrl-T Ta Ic ed-transpose-chars
+.It Ctrl-U Ta Ic ed-kill-line
+.It Ctrl-V Ta Ic ed-quoted-insert
+.It Ctrl-W Ta Ic em-kill-region
+.It Ctrl-X Ta Ic ed-sequence-lead-in
+.It Ctrl-Y Ta Ic em-yank
+.It Ctrl-Z, TSTP Ta Ic ed-tty-sigtstp
+.It Ctrl-[, ESC Ta Ic em-meta-next
+.It Ctrl-\e, QUIT Ta Ic ed-tty-sigquit
+.It Ctrl-] Ta Ic ed-tty-dsusp
+.It Ctrl-?, DEL Ta Ic em-delete-prev-char
+.It Ctrl-Meta-H Ta Ic ed-delete-prev-word
+.It Ctrl-Meta-L Ta Ic ed-clear-screen
+.It Ctrl-Meta-_ Ta Ic em-copy-prev-word
+.It Meta-0 to 9 Ta Ic ed-argument-digit
+.It Meta-B Ta Ic ed-prev-word
+.It Meta-C Ta Ic em-capitol-case
+.It Meta-D Ta Ic em-delete-next-word
+.It Meta-F Ta Ic em-next-word
+.It Meta-L Ta Ic em-lower-case
+.It Meta-N Ta Ic ed-search-next-history
+.It Meta-O Ta Ic ed-sequence-lead-in
+.It Meta-P Ta Ic ed-search-prev-history
+.It Meta-U Ta Ic em-upper-case
+.It Meta-W Ta Ic em-copy-region
+.It Meta-X Ta Ic ed-command
+.It Meta-[ Ta Ic ed-sequence-lead-in
+.It Meta-b Ta Ic ed-prev-word
+.It Meta-c Ta Ic em-capitol-case
+.It Meta-d Ta Ic em-delete-next-word
+.It Meta-f Ta Ic em-next-word
+.It Meta-l Ta Ic em-lower-case
+.It Meta-n Ta Ic ed-search-next-history
+.It Meta-p Ta Ic ed-search-prev-history
+.It Meta-u Ta Ic em-upper-case
+.It Meta-w Ta Ic em-copy-region
+.It Meta-x Ta Ic ed-command
+.It Ctrl-Meta-? Ta Ic ed-delete-prev-word
+.El
+.Pp
+The remaining
+.Xr ascii 7
+characters in the range 0x20 to 0x7e are bound to
+.Ic ed-insert .
+.Pp
+If standard output is not connected to a terminal device
+or
+.Xr el_set 3
+was used to set
+.Dv EL_EDITMODE
+to 0, all input character bindings are disabled and all characters
+typed are appended to the edit buffer.
+In that case, the edit buffer is returned to the program after a
+newline or carriage return character is typed, or after the first
+character typed if
+.Xr el_set 3
+was used to set
+.Dv EL_UNBUFFERED
+to non-zero.
+.Ss Editor commands
+Most editor commands accept an optional argument.
+The argument is entered by prefixing the editor command with one
+or more of the editor commands
+.Ic ed-argument-digit ,
+.Ic ed-digit ,
+.Ic em-universal-argument ,
+or
+.Ic vi-zero .
+When an argument is not provided, it defaults to 1.
+For most editor commands, the effect of an argument is to repeatedly
+execute the command that number of times.
+.Pp
+When talking about a character string from a left character to a
+right character, the left character is included in the string, while
+the right character is not included.
+.Pp
+If an editor command causes an error, the input character is discarded,
+no action occurs, and the terminal bell is rung.
+In case of a non-fatal error, the terminal bell is also rung,
+but the editor command takes effect anyway.
+.Pp
+In the following list, the default key bindings are listed after
+each editor command.
+.Bl -tag -width 4n
+.It Ic ed-argument-digit Pq vi command: 1 to 9; emacs: Meta-0 to Meta-9
+If in argument input mode, append the input digit to the argument
+being read.
+Otherwise, switch to argument input mode and use the input digit
+as the most significant digit of the argument.
+It is an error if the input character is not a digit or if the
+existing argument is already greater than a million.
+.It Ic ed-clear-screen Pq vi command: Ctrl-L; emacs: Ctrl-L, Ctrl-Meta-L
+Clear the screen and display the edit buffer at the top.
+Ignore any argument.
+.It Ic ed-command Pq vi command: So \&: Sc ; emacs: Meta-X, Meta-x
+Read a line from the terminal bypassing the normal line editing
+functionality and execute that line as an
+.Xr editrc 5
+builtin command.
+If in vi command mode, also switch back to vi insert mode.
+Ignore any argument.
+.It Ic ed-delete-next-char Pq vi command: x
+Delete the character at the cursor position.
+With an argument, delete that number of characters.
+In emacs mode, it is an error if the cursor is at the end of the
+edit buffer.
+In vi mode, the last character in the edit buffer is deleted in
+that case, and it is an error if the buffer is empty.
+.It Ic ed-delete-prev-char Pq vi command: X, Ctrl-H, BS, Ctrl-?, DEL
+Delete the character to the left of the cursor position.
+With an argument, delete that number of characters.
+It is an error if the cursor is at the beginning of the edit buffer.
+.It Ic ed-delete-prev-word Pq vi: Ctrl-W; emacs: Ctrl-Meta-H, Ctrl-Meta-?
+Move to the left to the closest beginning of a word, delete the
+string from that position to the cursor, and save it to the cut
+buffer.
+With an argument, delete that number of words.
+It is an error if the cursor is at the beginning of the edit buffer.
+.It Ic ed-digit Pq emacs: 0 to 9
+If in argument input mode, append the input digit to the argument
+being read.
+Otherwise, call
+.Ic ed-insert .
+It is an error if the input character is not a digit or if the
+existing argument is already greater than a million.
+.It Ic ed-end-of-file Pq not bound by default
+Discard the edit buffer and indicate end of file to the program.
+Ignore any argument.
+.It Ic ed-ignore Pq various
+Discard the input character and do nothing.
+.It Ic ed-insert Pq vi input: almost all; emacs: printable characters
+In insert mode, insert the input character left of the cursor
+position.
+In replace mode, overwrite the character at the cursor and move the
+cursor to the right by one character position.
+Accept an argument to do this repeatedly.
+It is an error if the input character is the NUL character (Ctrl-@).
+Failure to enlarge the edit buffer also results in an error.
+.It Ic ed-kill-line Pq vi command: D, Ctrl-K; emacs: Ctrl-K, Ctrl-U
+Delete the string from the cursor position to the end of the line
+and save it to the cut buffer.
+Ignore any argument.
+.It Ic ed-move-to-beg Pq vi command: ^, Ctrl-A; emacs: Ctrl-A
+In vi mode, move the cursor to the first non-space character in the
+edit buffer.
+In emacs mode, move the cursor to the beginning of the edit buffer.
+Ignore any argument.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+.It Ic ed-move-to-end Pq vi command: $, Ctrl-E; emacs: Ctrl-E
+Move the cursor to the end of the edit buffer.
+Ignore any argument.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+.It Ic ed-newline Pq all modes: Ctrl-J, LF, Ctrl-M, CR
+Append a newline character to the edit buffer and return the edit
+buffer to the program.
+Ignore any argument.
+.It Ic ed-next-char Pq vi command: Space, l; emacs: Ctrl-F
+Move the cursor one character position to the right.
+With an argument, move by that number of characters.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the end of the edit
+buffer.
+.It Ic ed-next-history Pq vi command: j, +, Ctrl-N; emacs: Ctrl-N
+Replace the edit buffer with the next history line.
+That line is older than the current line.
+With an argument, go forward by that number of history lines.
+It is a non-fatal error to advance by more lines than are available.
+.It Ic ed-next-line Pq not bound by default
+Move the cursor down one line.
+With an argument, move down by that number of lines.
+It is an error if the edit buffer does not contain enough newline
+characters to the right of the cursor position.
+.It Ic ed-prev-char Pq vi command: h; emacs: Ctrl-B
+Move the cursor one character position to the left.
+With an argument, move by that number of characters.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the beginning of the
+edit buffer.
+.It Ic ed-prev-history Pq vi command: k, -, Ctrl-P; emacs: Ctrl-P
+Replace the edit buffer with the previous history line.
+That line is newer than the current line.
+With an argument, go back by that number of lines.
+It is a non-fatal error to back up by more lines than are available.
+.It Ic ed-prev-line Pq not bound by default
+Move the cursor up one line.
+With an argument, move up by that number of lines.
+It is an error if the edit buffer does not contain enough newline
+characters to the left of the cursor position.
+.It Ic ed-prev-word Pq emacs: Meta-B, Meta-b
+Move the cursor to the left to the closest beginning of a word.
+With an argument, repeat that number of times.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the beginning of the
+edit buffer.
+.It Ic ed-quoted-insert Pq vi insert, emacs: Ctrl-V
+Read one character from the terminal bypassing the normal line
+editing functionality and call
+.Ic ed-insert
+on it.
+If trying to read the character returns end of file or an error,
+call
+.Ic ed-end-of-file
+instead.
+.It Ic ed-redisplay Pq vi command, emacs: Ctrl-R
+Redisplay everything.
+Ignore any argument.
+.It Ic ed-search-next-history Pq vi command: J; emacs: Meta-N, Meta-n
+Replace the edit buffer with the next matching history entry.
+.It Ic ed-search-prev-history Pq vi command: K; emacs: Meta-P, Meta-p
+Replace the edit buffer with the previous matching history entry.
+.It Ic ed-sequence-lead-in Pq vi cmd: O, \&[; emacs: Ctrl-X;\
+ both: Meta-O, Meta-[
+Call a macro.
+See the section about
+.Sx Macros
+below for details.
+.It Ic ed-start-over Pq not bound by default
+Discard the contents of the edit buffer and start from scratch.
+Ignore any argument.
+.It Ic ed-transpose-chars Pq emacs: Ctrl-T
+Exchange the character at the cursor position with the one to the
+left of it and move the cursor to the character to the right of the
+two exchanged characters.
+Ignore any argument.
+It is an error if the cursor is at the beginning of the edit buffer
+or if the edit buffer contains less than two characters.
+.It Ic ed-unassigned Pq all characters not listed
+This editor command always results in an error.
+.It Ic em-capitol-case Pq emacs: Meta-C, Meta-c
+Capitalize the string from the cursor to the end of the current
+word.
+That is, if it contains at least one alphabetic character, convert
+the first alphabetic character to upper case, and convert all
+characters to the right of it to lower case.
+In any case, move the cursor to the next character after the end
+of the current word.
+.It Ic em-copy-prev-word Pq emacs: Ctrl-Meta-_
+Copy the string from the beginning of the current word to the cursor
+and insert it to the left of the cursor.
+Move the cursor to the character after the inserted string.
+It is an error if the cursor is at the beginning of the edit buffer.
+.It Ic em-copy-region Pq emacs: Meta-W, Meta-w
+Copy the string from the cursor to the mark to the cut buffer.
+It is an error if the mark is not set.
+.It Ic em-delete-next-word Pq emacs: Meta-D, Meta-d
+Delete the string from the cursor to the end of the current word
+and save it to the cut buffer.
+It is an error if the cursor is at the end of the edit buffer.
+.It Ic em-delete-or-list Pq emacs: Ctrl-D, EOF
+If the cursor is not at the end of the line, delete the character
+at the cursor.
+If the edit buffer is empty, indicate end of file to the program.
+It is an error if the cursor is at the end of the edit buffer and
+the edit buffer is not empty.
+.It Ic em-delete-prev-char Pq emacs: Ctrl-H, BS, Ctrl-?, DEL
+Delete the character to the left of the cursor.
+It is an error if the cursor is at the beginning of the edit buffer.
+.It Ic em-exchange-mark Pq not bound by default
+Exchange the cursor and the mark.
+.It Ic em-gosmacs-transpose Pq not bound by default
+Exchange the two characters to the left of the cursor.
+It is an error if the cursor is on the first or second character
+of the edit buffer.
+.It Ic em-inc-search-next Pq not bound by default
+Emacs incremental next search.
+.It Ic em-inc-search-prev Pq not bound by default
+Emacs incremental reverse search.
+.It Ic em-kill-line Pq not bound by default
+Delete the entire contents of the edit buffer and save it to the
+cut buffer.
+.It Ic em-kill-region Pq emacs: Ctrl-W
+Delete the string from the cursor to the mark and save it to the
+cut buffer.
+It is an error if the mark is not set.
+.It Ic em-lower-case Pq emacs: Meta-L, Meta-l
+Convert the characters from the cursor to the end of the current
+word to lower case.
+.It Ic em-meta-next Pq vi command, emacs: Ctrl-[, ESC
+Set the bit 0x80 on the next character typed.
+Unless the resulting code point is printable, holding down the
+.Sq Meta-
+key while typing that character is a simpler way to achieve the
+same effect.
+.It Ic em-next-word Pq Meta-F, Meta-f
+Move the cursor to the end of the current word.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the end of the edit
+buffer.
+.It Ic em-set-mark Pq emacs: Ctrl-Q, NUL
+Set the mark at the current cursor position.
+.It Ic em-toggle-overwrite Pq not bound by default
+Switch from insert to overwrite mode or vice versa.
+.It Ic em-universal-argument Pq not bound by default
+If in argument input mode, multiply the argument by 4.
+Otherwise, switch to argument input mode and set the argument to 4.
+It is an error if the existing argument is already greater than a
+million.
+.It Ic em-upper-case Pq emacs: Meta-U, Meta-u
+Convert the characters from the cursor to the end of the current
+word to upper case.
+.It Ic em-yank Pq emacs: Ctrl-Y
+Paste the cut buffer to the left of the cursor.
+.It Ic vi-add Pq vi command: a
+Switch to vi insert mode.
+Unless the cursor is already at the end of the edit buffer, move
+it one character position to the right.
+.It Ic vi-add-at-eol Pq vi command: A
+Switch to vi insert mode and move the cursor to the end of the edit
+buffer.
+.It Ic vi-alias Pq vi command: @
+If an alias function was defined by calling the
+.Xr el_set 3
+or
+.Xr el_wset 3
+function with the argument
+.Dv EL_ALIAS_TEXT ,
+read one character from the terminal bypassing the normal line
+editing functionality, call the alias function passing the argument that was specified with
+.Dv EL_ALIAS_TEXT
+as the first argument and the character read, with an underscore
+prepended, as the second argument, and pass the string returned
+from the alias function to
+.Xr el_wpush 3 .
+It is an error if no alias function is defined or if trying to read
+the character results in end of file or an error.
+.It Ic vi-change-case Pq vi command: ~
+Change the case of the character at the cursor and move the cursor
+one character position to the right.
+It is an error if the cursor is already at the end of the edit
+buffer.
+.It Ic vi-change-meta Pq vi command: c
+Delete the string from the cursor to the position specified by the
+following movement command and save a copy of it to the cut buffer.
+When given twice in a row, instead delete the whole contents of the
+edit buffer and save a copy of it to the cut buffer.
+In either case, switch to vi insert mode after that.
+.It Ic vi-change-to-eol Pq vi command: C
+Delete the string from the cursor position to the end of the line
+and save it to the cut buffer, then switch to vi insert mode.
+.It Ic vi-command-mode Pq vi insert: Ctrl-[, ESC
+Discard pending actions and arguments and switch to vi command mode.
+Unless the cursor is already at the beginning of the edit buffer,
+move it to the left by one character position.
+.It Ic vi-comment-out Pq vi command: #
+Insert a
+.Sq #
+character at the beginning of the edit buffer and return the edit
+buffer to the program.
+.It Ic vi-delete-meta Pq vi command: d
+Delete the string from the cursor to the position specified by the
+following movement command and save a copy of it to the cut buffer.
+When given twice in a row, instead delete the whole contents of the
+edit buffer and save a copy of it to the cut buffer.
+.It Ic vi-delete-prev-char Pq vi insert: Ctrl-H, BS, Ctrl-?, DEL
+Delete the character to the left of the cursor.
+It is an error if the cursor is already at the beginning of the
+edit buffer.
+.It Ic vi-end-big-word Pq vi command: E
+Move the cursor to the end of the current space delimited word.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the end of the edit
+buffer.
+.It Ic vi-end-word Pq vi command: e
+Move the cursor to the end of the current word.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the end of the edit
+buffer.
+.It Ic vi-history-word Pq vi command: _
+Insert the first word from the most recent history entry after the
+cursor, move the cursor after to the character after the inserted
+word, and switch to vi insert mode.
+It is an error if there is no history entry or the most recent
+history entry is empty.
+.It Ic vi-insert Pq vi command: i
+Enter insert mode.
+.It Ic vi-insert-at-bol Pq vi command: I
+Move the cursor to the beginning of the edit buffer and switch to
+vi insert mode.
+.It Ic vi-kill-line-prev Pq vi: Ctrl-U
+Delete the string from the beginning of the edit buffer to the
+cursor and save it to the cut buffer.
+.It Ic vi-list-or-eof Pq vi insert: Ctrl-D, EOF
+If the edit buffer is empty, indicate end of file to the program.
+It is an error if the edit buffer is not empty.
+.It Ic vi-match Pq vi command: %
+Consider opening and closing parentheses, braces, and brackets as
+delimiters.
+If the cursor is not at a delimiter, move it to the right until it
+gets to one, then move it to the matching delimiter.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if there is no delimiter at the cursor or in the
+string to the right of the cursor, or if the first such delimiter
+has no matching delimiter.
+.It Ic vi-next-big-word Pq vi command: W
+Move the cursor to the right to the beginning of the next space
+delimited word.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the end of the edit
+buffer or on its last character.
+.It Ic vi-next-char Pq vi command: f
+Read one character from the terminal bypassing the normal line
+editing functionality and move the cursor to the right to the next
+instance of that character in the edit buffer.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+If trying to read the character results in end of file or an error,
+call
+.Ic ed-end-of-file
+instead.
+It is an error if the character is not found searching to the right
+in the edit buffer.
+.It Ic vi-next-word Pq vi command: w
+Move the cursor to the right to the beginning of the next word.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the end of the edit
+buffer or on its last character.
+.It Ic vi-paste-next Pq vi command: p
+Insert a copy of the cut buffer to the right of the cursor.
+It is an error if the cut buffer is empty.
+.It Ic vi-paste-prev Pq vi command: P
+Insert a copy of the cut buffer to the left of the cursor.
+It is an error if the cut buffer is empty.
+.It Ic vi-prev-big-word Pq vi command: B
+Move the cursor to the left to the next beginning of a space delimited
+word.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the beginning of the
+edit buffer.
+.It Ic vi-prev-char Pq vi command: F
+Read one character from the terminal bypassing the normal line
+editing functionality and move the cursor to the left to the next
+instance of that character in the edit buffer.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+If trying to read the character results in end of file or an error,
+call
+.Ic ed-end-of-file
+instead.
+It is an error if the character is not found searching to the left
+in the edit buffer.
+.It Ic vi-prev-word Pq vi command: b
+Move the cursor to the left to the next beginning of a word.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+It is an error if the cursor is already at the beginning of the
+edit buffer.
+.It Ic vi-redo Pq vi command: Sq \&.
+Redo the last non-motion command.
+.It Ic vi-repeat-next-char Pq vi command: Sq \&;
+Repeat the most recent character search in the same search direction.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+.It Ic vi-repeat-prev-char Pq vi command: Sq \&,
+Repeat the most recent character search in the opposite search
+direction.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+.It Ic vi-repeat-search-next Pq vi command: n
+Repeat the most recent history search in the same search direction.
+.It Ic vi-repeat-search-prev Pq vi command: N
+Repeat the most recent history search in the opposite search
+direction.
+.It Ic vi-replace-char Pq vi command: r
+Switch to vi replace mode, and automatically switch back to vi
+command mode after the next character typed.
+See
+.Ic ed-insert
+for a description of replace mode.
+It is an error if the cursor is at the end of the edit buffer.
+.It Ic vi-replace-mode Pq vi command: R
+Switch to vi replace mode.
+This is a variant of vi insert mode; see
+.Ic ed-insert
+for the difference.
+.It Ic vi-search-next Pq vi command: \&?
+Replace the edit buffer with the next matching history entry.
+.It Ic vi-search-prev Pq vi command: /
+Replace the edit buffer with the previous matching history entry.
+.It Ic vi-substitute-char Pq vi command: s
+Delete the character at the cursor and switch to vi insert mode.
+.It Ic vi-substitute-line Pq vi command: S
+Delete the entire contents of the edit buffer, save a copy of it
+in the cut buffer, and enter vi insert mode.
+.It Ic vi-to-column Pq vi command: \&|
+Move the cursor to the column specified as the argument.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+.It Ic vi-to-history-line Pq vi command: G
+Replace the edit buffer with the specified history entry.
+.It Ic vi-to-next-char Pq vi command: t
+Read one character from the terminal bypassing the normal line
+editing functionality and move the cursor to the right to the
+character before the next instance of that character in the edit
+buffer.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+If trying to read the character results in end of file or an error,
+call
+.Ic ed-end-of-file
+instead.
+It is an error if the character is not found searching to the right
+in the edit buffer.
+.It Ic vi-to-prev-char Pq vi command: T
+Read one character from the terminal bypassing the normal line
+editing functionality and move the cursor to the left to the character
+after the next instance of that character in the edit buffer.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+If trying to read the character results in end of file or an error,
+call
+.Ic ed-end-of-file
+instead.
+It is an error if the character is not found searching to the left
+in the edit buffer.
+.It Ic vi-undo Pq vi command: u
+Undo the last change.
+.It Ic vi-undo-line Pq vi command: U
+Undo all changes to the edit buffer.
+.It Ic vi-yank Pq vi command: y
+Copy the string from the cursor to the position specified by the
+following movement command to the cut buffer.
+When given twice in a row, instead copy the whole contents of the
+edit buffer to the cut buffer.
+.It Ic vi-yank-end Pq vi command: Y
+Copy the string from the cursor to the end of the edit buffer to
+the cut buffer.
+.It Ic vi-zero Pq vi command: 0
+If in argument input mode, multiply the argument by ten.
+Otherwise, move the cursor to the beginning of the edit buffer.
+Can be used as a movement command after
+.Ic vi_change_meta ,
+.Ic vi_delete_meta ,
+or
+.Ic vi_yank .
+.El
+.Ss Macros
+If an input character is bound to the editor command
+.Ic ed-sequence-lead-in ,
+.Nm
+attempts to call a macro.
+If the input character by itself forms the name of a macro, that
+macro is executed.
+Otherwise, additional input characters are read until the string
+read forms the name of a macro, in which case that macro is executed,
+or until the string read matches the beginning of none of the existing
+macro names, in which case the string including the final, mismatching
+character is discarded and the terminal bell is rung.
+.Pp
+There are two kinds of macros.
+Command macros execute a single editor command.
+Keyboard macros return a string of characters that is appended
+as a new line to the
+.Sx Input Queue .
+.Pp
+The following command macros are defined by default in vi command
+mode and in emacs mode:
+.Bl -column -offset indent "Esc O A, Esc O A" "em-exchange-mark"
+.It Esc \&[ A, Esc O A Ta Ic ed-prev-history
+.It Esc \&[ B, Esc O B Ta Ic ed-next-history
+.It Esc \&[ C, Esc O C Ta Ic ed-next-char
+.It Esc \&[ D, Esc O D Ta Ic ed-prev-char
+.It Esc \&[ F, Esc O F Ta Ic ed-move-to-end
+.It Esc \&[ H, Esc O H Ta Ic ed-move-to-beg
+.El
+.Pp
+In vi command mode, they are also defined by default without the
+initial escape character.
+.Pp
+In addition, the
+.Nm
+library tries to bind the strings generated by the arrow keys
+as reported by the
+.Xr terminfo 5
+database to these editor commands, unless that would clobber
+user settings.
+.Pp
+In emacs mode, the two-character string
+.Dq Ctrl-X Ctrl-X
+is bound to the
+.Ic em-exchange-mark
+editor command.
+.Ss Input Queue
+The
+.Nm
+library maintains an input queue operated in FIFO mode.
+Whenever it needs an input character, it takes the first character
+from the first line of the input queue.
+When the queue is empty, it reads from the terminal.
+.Pp
+A line can be appended to the end of the input queue in several ways:
+.Bl -dash -offset indent
+.It
+By calling one of the keyboard
+.Sx Macros .
+.It
+By calling the editor command
+.Ic vi-redo .
+.It
+By calling the editor command
+.Ic vi-alias .
+.It
+By pressing a key in emacs incremental search mode that doesn't
+have a special meaning in that mode but returns to normal emacs
+mode.
+.It
+If an application program directly calls the functions
+.Xr el_push 3
+or
+.Xr el_wpush 3 ,
+it can provide additional, program-specific ways
+of appending to the input queue.
+.El
+.Sh SEE ALSO
+.Xr mg 1 ,
+.Xr vi 1 ,
+.Xr editline 3 ,
+.Xr el_wgets 3 ,
+.Xr el_wpush 3 ,
+.Xr el_wset 3 ,
+.Xr editrc 5
+.Sh HISTORY
+This manual page first appeared in
+.Ox 6.0
+and
+.Nx 8 .
+.Sh AUTHORS
+.An -nosplit
+This manual page was written by
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
diff --git a/third_party/heimdal/lib/libedit/src/editrc.5 b/third_party/heimdal/lib/libedit/src/editrc.5
new file mode 100644
index 0000000..723cb9e
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/editrc.5
@@ -0,0 +1,317 @@
+.\" $NetBSD: editrc.5,v 1.32 2016/05/22 23:54:20 christos Exp $
+.\"
+.\" Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This file was contributed to The NetBSD Foundation by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd May 22, 2016
+.Dt EDITRC 5
+.Os
+.Sh NAME
+.Nm editrc
+.Nd configuration file for editline library
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+file defines various settings to be used by the
+.Xr editline 3
+library.
+.Pp
+The format of each line is:
+.Pp
+.Dl [prog:]command [arg ...]
+.Pp
+.Ar command
+is one of the
+.Xr editline 3
+builtin commands.
+Refer to
+.Sx BUILTIN COMMANDS
+for more information.
+.Pp
+.Ar prog
+is the program name string that a program defines when it calls
+.Xr el_init 3
+to set up
+.Xr editline 3 ,
+which is usually
+.Va argv[0] .
+.Ar command
+will be executed for any program which matches
+.Ar prog .
+.Pp
+.Ar prog
+may also be a
+.Xr regex 3
+style
+regular expression, in which case
+.Ar command
+will be executed for any program that matches the regular expression.
+.Pp
+If
+.Ar prog
+is absent,
+.Ar command
+is executed for all programs.
+.Sh BUILTIN COMMANDS
+The
+.Nm editline
+library has some builtin commands, which affect the way
+that the line editing and history functions operate.
+These are based on similar named builtins present in the
+.Xr tcsh 1
+shell.
+.Pp
+The following builtin commands are available:
+.Bl -tag -width 4n
+.It Ic bind Oo Fl aeklrsv Oc Op Ar key Op Ar command
+Without options and arguments, list all bound keys and macros, and
+the editor command or input string to which each one is bound.
+If only
+.Ar key
+is supplied, show the binding for that key or macro.
+If
+.Ar key command
+is supplied, bind the editor
+.Ar command
+to that key or macro.
+.Pp
+The options are as follows:
+.Bl -tag -width 4n
+.It Fl a
+List or change key bindings in the
+.Xr vi 1
+mode alternate (command mode) key map.
+.It Fl e
+Bind all keys to the standard GNU Emacs-like bindings.
+.It Fl k
+.Ar key
+is interpreted as a symbolic arrow key name, which may be one of
+.Sq up ,
+.Sq down ,
+.Sq left
+or
+.Sq right .
+.It Fl l
+List all editor commands and a short description of each.
+.It Fl r
+Remove the binding of the key or macro
+.Ar key .
+.It Fl s
+Define a keyboard macro rather than a key binding or command macro:
+.Ar command
+is taken as a literal string and appended to the input queue whenever
+.Ar key
+is typed.
+Bound keys and macros in
+.Ar command
+are themselves reinterpreted, and this continues for ten levels of
+interpretation.
+.It Fl v
+Bind all keys to the standard
+.Xr vi 1 Ns -like
+bindings.
+.El
+.Pp
+The
+.Xr editline 7
+manual documents all editor commands and contains more information
+about macros and the input queue.
+.Pp
+.Ar key
+and
+.Ar command
+can contain control characters of the form
+.Sm off
+.Sq No ^ Ar character
+.Sm on
+.Po
+e.g.\&
+.Sq ^A
+.Pc ,
+and the following backslashed escape sequences:
+.Pp
+.Bl -tag -compact -offset indent -width 4n
+.It Ic \ea
+Bell
+.It Ic \eb
+Backspace
+.It Ic \ee
+Escape
+.It Ic \ef
+Formfeed
+.It Ic \en
+Newline
+.It Ic \er
+Carriage return
+.It Ic \et
+Horizontal tab
+.It Ic \ev
+Vertical tab
+.Sm off
+.It Sy \e Ar nnn
+.Sm on
+The ASCII character corresponding to the octal number
+.Ar nnn .
+.El
+.Pp
+.Sq \e
+nullifies the special meaning of the following character,
+if it has any, notably
+.Sq \e
+and
+.Sq ^ .
+.It Ic echotc Oo Fl sv Oc Ar arg Ar ...
+Exercise terminal capabilities given in
+.Ar arg ... .
+If
+.Ar arg
+is
+.Sq baud ,
+.Sq cols ,
+.Sq lines ,
+.Sq rows ,
+.Sq meta ,
+or
+.Sq tabs ,
+the value of that capability is printed, with
+.Dq yes
+or
+.Dq no
+indicating that the terminal does or does not have that capability.
+.Pp
+.Fl s
+returns an empty string for non-existent capabilities, rather than
+causing an error.
+.Fl v
+causes messages to be verbose.
+.It Ic edit Op Li on | Li off
+Enable or disable the
+.Nm editline
+functionality in a program.
+.It Ic history Ar list | Ar size Dv n | Ar unique Dv n
+The
+.Ar list
+command lists all entries in the history.
+The
+.Ar size
+command sets the history size to
+.Dv n
+entries.
+The
+.Ar unique
+command controls if history should keep duplicate entries.
+If
+.Dv n
+is non zero, only keep unique history entries.
+If
+.Dv n
+is zero, then keep all entries (the default).
+.It Ic settc Ar cap Ar val
+Set the terminal capability
+.Ar cap
+to
+.Ar val ,
+as defined in
+.Xr termcap 5 .
+No sanity checking is done.
+.It Ic setty Oo Fl a Oc Oo Fl d Oc Oo Fl q Oc Oo Fl x Oc Oo Ar +mode Oc \
+Oo Ar -mode Oc Oo Ar mode Oc Oo Ar char=c Oc
+Control which tty modes that
+.Nm
+won't allow the user to change.
+.Fl d ,
+.Fl q
+or
+.Fl x
+tells
+.Ic setty
+to act on the
+.Sq edit ,
+.Sq quote
+or
+.Sq execute
+set of tty modes respectively; defaulting to
+.Fl x .
+.Pp
+Without other arguments,
+.Ic setty
+lists the modes in the chosen set which are fixed on
+.Po
+.Sq +mode
+.Pc
+or off
+.Po
+.Sq -mode
+.Pc .
+.Fl a
+lists all tty modes in the chosen set regardless of the setting.
+With
+.Ar +mode ,
+.Ar -mode
+or
+.Ar mode ,
+fixes
+.Ar mode
+on or off or removes control of
+.Ar mode
+in the chosen set.
+.Pp
+.Ic Setty
+can also be used to set tty characters to particular values using
+.Ar char=value .
+If
+.Ar value
+is empty
+then the character is set to
+.Dv _POSIX_VDISABLE .
+.It Ic telltc
+List the values of all the terminal capabilities (see
+.Xr termcap 5 ) .
+.El
+.Sh FILES
+.Bl -tag -width "~/.editrcXXX"
+.It Pa ~/.editrc
+User configuration file for the
+.Xr editline 3
+library.
+.El
+.Sh SEE ALSO
+.Xr editline 3 ,
+.Xr regex 3 ,
+.Xr termcap 5 ,
+.Xr editline 7
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm editline
+library was written by
+.An Christos Zoulas ,
+and this manual was written by
+.An Luke Mewburn ,
+with some sections inspired by
+.Xr tcsh 1 .
diff --git a/third_party/heimdal/lib/libedit/src/el.c b/third_party/heimdal/lib/libedit/src/el.c
new file mode 100644
index 0000000..acde929
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/el.c
@@ -0,0 +1,640 @@
+/* $NetBSD: el.c,v 1.92 2016/05/22 19:44:26 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94";
+#else
+__RCSID("$NetBSD: el.c,v 1.92 2016/05/22 19:44:26 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * el.c: EditLine interface functions
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "el.h"
+#include "parse.h"
+#include "read.h"
+
+/* el_init():
+ * Initialize editline and set default parameters.
+ */
+EditLine *
+el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
+{
+ return el_init_fd(prog, fin, fout, ferr, fileno(fin), fileno(fout),
+ fileno(ferr));
+}
+
+EditLine *
+el_init_fd(const char *prog, FILE *fin, FILE *fout, FILE *ferr,
+ int fdin, int fdout, int fderr)
+{
+ EditLine *el = el_malloc(sizeof(*el));
+
+ if (el == NULL)
+ return NULL;
+
+ memset(el, 0, sizeof(EditLine));
+
+ el->el_infile = fin;
+ el->el_outfile = fout;
+ el->el_errfile = ferr;
+
+ el->el_infd = fdin;
+ el->el_outfd = fdout;
+ el->el_errfd = fderr;
+
+ el->el_prog = wcsdup(ct_decode_string(prog, &el->el_scratch));
+ if (el->el_prog == NULL) {
+ el_free(el);
+ return NULL;
+ }
+
+ /*
+ * Initialize all the modules. Order is important!!!
+ */
+ el->el_flags = 0;
+ if (setlocale(LC_CTYPE, NULL) != NULL){
+ if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
+ el->el_flags |= CHARSET_IS_UTF8;
+ }
+
+ if (terminal_init(el) == -1) {
+ el_free(el->el_prog);
+ el_free(el);
+ return NULL;
+ }
+ (void) keymacro_init(el);
+ (void) map_init(el);
+ if (tty_init(el) == -1)
+ el->el_flags |= NO_TTY;
+ (void) ch_init(el);
+ (void) search_init(el);
+ (void) hist_init(el);
+ (void) prompt_init(el);
+ (void) sig_init(el);
+ if (read_init(el) == -1) {
+ el_end(el);
+ return NULL;
+ }
+ return el;
+}
+
+
+/* el_end():
+ * Clean up.
+ */
+void
+el_end(EditLine *el)
+{
+
+ if (el == NULL)
+ return;
+
+ el_reset(el);
+
+ terminal_end(el);
+ keymacro_end(el);
+ map_end(el);
+ if (!(el->el_flags & NO_TTY))
+ tty_end(el);
+ ch_end(el);
+ read_end(el->el_read);
+ search_end(el);
+ hist_end(el);
+ prompt_end(el);
+ sig_end(el);
+
+ el_free(el->el_prog);
+ el_free(el->el_visual.cbuff);
+ el_free(el->el_visual.wbuff);
+ el_free(el->el_scratch.cbuff);
+ el_free(el->el_scratch.wbuff);
+ el_free(el->el_lgcyconv.cbuff);
+ el_free(el->el_lgcyconv.wbuff);
+ el_free(el);
+}
+
+
+/* el_reset():
+ * Reset the tty and the parser
+ */
+void
+el_reset(EditLine *el)
+{
+
+ tty_cookedmode(el);
+ ch_reset(el); /* XXX: Do we want that? */
+}
+
+
+/* el_set():
+ * set the editline parameters
+ */
+int
+el_wset(EditLine *el, int op, ...)
+{
+ va_list ap;
+ int rv = 0;
+
+ if (el == NULL)
+ return -1;
+ va_start(ap, op);
+
+ switch (op) {
+ case EL_PROMPT:
+ case EL_RPROMPT: {
+ el_pfunc_t p = va_arg(ap, el_pfunc_t);
+
+ rv = prompt_set(el, p, 0, op, 1);
+ break;
+ }
+
+ case EL_RESIZE: {
+ el_zfunc_t p = va_arg(ap, el_zfunc_t);
+ void *arg = va_arg(ap, void *);
+ rv = ch_resizefun(el, p, arg);
+ break;
+ }
+
+ case EL_ALIAS_TEXT: {
+ el_afunc_t p = va_arg(ap, el_afunc_t);
+ void *arg = va_arg(ap, void *);
+ rv = ch_aliasfun(el, p, arg);
+ break;
+ }
+
+ case EL_PROMPT_ESC:
+ case EL_RPROMPT_ESC: {
+ el_pfunc_t p = va_arg(ap, el_pfunc_t);
+ int c = va_arg(ap, int);
+
+ rv = prompt_set(el, p, (wchar_t)c, op, 1);
+ break;
+ }
+
+ case EL_TERMINAL:
+ rv = terminal_set(el, va_arg(ap, char *));
+ break;
+
+ case EL_EDITOR:
+ rv = map_set_editor(el, va_arg(ap, wchar_t *));
+ break;
+
+ case EL_SIGNAL:
+ if (va_arg(ap, int))
+ el->el_flags |= HANDLE_SIGNALS;
+ else
+ el->el_flags &= ~HANDLE_SIGNALS;
+ break;
+
+ case EL_BIND:
+ case EL_TELLTC:
+ case EL_SETTC:
+ case EL_ECHOTC:
+ case EL_SETTY:
+ {
+ const wchar_t *argv[20];
+ int i;
+
+ for (i = 1; i < (int)__arraycount(argv); i++)
+ if ((argv[i] = va_arg(ap, wchar_t *)) == NULL)
+ break;
+
+ switch (op) {
+ case EL_BIND:
+ argv[0] = L"bind";
+ rv = map_bind(el, i, argv);
+ break;
+
+ case EL_TELLTC:
+ argv[0] = L"telltc";
+ rv = terminal_telltc(el, i, argv);
+ break;
+
+ case EL_SETTC:
+ argv[0] = L"settc";
+ rv = terminal_settc(el, i, argv);
+ break;
+
+ case EL_ECHOTC:
+ argv[0] = L"echotc";
+ rv = terminal_echotc(el, i, argv);
+ break;
+
+ case EL_SETTY:
+ argv[0] = L"setty";
+ rv = tty_stty(el, i, argv);
+ break;
+
+ default:
+ rv = -1;
+ EL_ABORT((el->el_errfile, "Bad op %d\n", op));
+ break;
+ }
+ break;
+ }
+
+ case EL_ADDFN:
+ {
+ wchar_t *name = va_arg(ap, wchar_t *);
+ wchar_t *help = va_arg(ap, wchar_t *);
+ el_func_t func = va_arg(ap, el_func_t);
+
+ rv = map_addfunc(el, name, help, func);
+ break;
+ }
+
+ case EL_HIST:
+ {
+ hist_fun_t func = va_arg(ap, hist_fun_t);
+ void *ptr = va_arg(ap, void *);
+
+ rv = hist_set(el, func, ptr);
+ if (!(el->el_flags & CHARSET_IS_UTF8))
+ el->el_flags &= ~NARROW_HISTORY;
+ break;
+ }
+
+ case EL_EDITMODE:
+ if (va_arg(ap, int))
+ el->el_flags &= ~EDIT_DISABLED;
+ else
+ el->el_flags |= EDIT_DISABLED;
+ rv = 0;
+ break;
+
+ case EL_GETCFN:
+ {
+ el_rfunc_t rc = va_arg(ap, el_rfunc_t);
+ rv = el_read_setfn(el->el_read, rc);
+ break;
+ }
+
+ case EL_CLIENTDATA:
+ el->el_data = va_arg(ap, void *);
+ break;
+
+ case EL_UNBUFFERED:
+ rv = va_arg(ap, int);
+ if (rv && !(el->el_flags & UNBUFFERED)) {
+ el->el_flags |= UNBUFFERED;
+ read_prepare(el);
+ } else if (!rv && (el->el_flags & UNBUFFERED)) {
+ el->el_flags &= ~UNBUFFERED;
+ read_finish(el);
+ }
+ rv = 0;
+ break;
+
+ case EL_PREP_TERM:
+ rv = va_arg(ap, int);
+ if (rv)
+ (void) tty_rawmode(el);
+ else
+ (void) tty_cookedmode(el);
+ rv = 0;
+ break;
+
+ case EL_SETFP:
+ {
+ FILE *fp;
+ int what;
+
+ what = va_arg(ap, int);
+ fp = va_arg(ap, FILE *);
+
+ rv = 0;
+ switch (what) {
+ case 0:
+ el->el_infile = fp;
+ el->el_infd = fileno(fp);
+ break;
+ case 1:
+ el->el_outfile = fp;
+ el->el_outfd = fileno(fp);
+ break;
+ case 2:
+ el->el_errfile = fp;
+ el->el_errfd = fileno(fp);
+ break;
+ default:
+ rv = -1;
+ break;
+ }
+ break;
+ }
+
+ case EL_REFRESH:
+ re_clear_display(el);
+ re_refresh(el);
+ terminal__flush(el);
+ break;
+
+ default:
+ rv = -1;
+ break;
+ }
+
+ va_end(ap);
+ return rv;
+}
+
+
+/* el_get():
+ * retrieve the editline parameters
+ */
+int
+el_wget(EditLine *el, int op, ...)
+{
+ va_list ap;
+ int rv;
+
+ if (el == NULL)
+ return -1;
+
+ va_start(ap, op);
+
+ switch (op) {
+ case EL_PROMPT:
+ case EL_RPROMPT: {
+ el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
+ rv = prompt_get(el, p, 0, op);
+ break;
+ }
+ case EL_PROMPT_ESC:
+ case EL_RPROMPT_ESC: {
+ el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
+ wchar_t *c = va_arg(ap, wchar_t *);
+
+ rv = prompt_get(el, p, c, op);
+ break;
+ }
+
+ case EL_EDITOR:
+ rv = map_get_editor(el, va_arg(ap, const wchar_t **));
+ break;
+
+ case EL_SIGNAL:
+ *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
+ rv = 0;
+ break;
+
+ case EL_EDITMODE:
+ *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
+ rv = 0;
+ break;
+
+ case EL_TERMINAL:
+ terminal_get(el, va_arg(ap, const char **));
+ rv = 0;
+ break;
+
+ case EL_GETTC:
+ {
+ static char name[] = "gettc";
+ char *argv[20];
+ int i;
+
+ for (i = 1; i < (int)__arraycount(argv); i++)
+ if ((argv[i] = va_arg(ap, char *)) == NULL)
+ break;
+
+ argv[0] = name;
+ rv = terminal_gettc(el, i, argv);
+ break;
+ }
+
+ case EL_GETCFN:
+ *va_arg(ap, el_rfunc_t *) = el_read_getfn(el->el_read);
+ rv = 0;
+ break;
+
+ case EL_CLIENTDATA:
+ *va_arg(ap, void **) = el->el_data;
+ rv = 0;
+ break;
+
+ case EL_UNBUFFERED:
+ *va_arg(ap, int *) = (el->el_flags & UNBUFFERED) != 0;
+ rv = 0;
+ break;
+
+ case EL_GETFP:
+ {
+ int what;
+ FILE **fpp;
+
+ what = va_arg(ap, int);
+ fpp = va_arg(ap, FILE **);
+ rv = 0;
+ switch (what) {
+ case 0:
+ *fpp = el->el_infile;
+ break;
+ case 1:
+ *fpp = el->el_outfile;
+ break;
+ case 2:
+ *fpp = el->el_errfile;
+ break;
+ default:
+ rv = -1;
+ break;
+ }
+ break;
+ }
+ default:
+ rv = -1;
+ break;
+ }
+ va_end(ap);
+
+ return rv;
+}
+
+
+/* el_line():
+ * Return editing info
+ */
+const LineInfoW *
+el_wline(EditLine *el)
+{
+
+ return (const LineInfoW *)(void *)&el->el_line;
+}
+
+
+/* el_source():
+ * Source a file
+ */
+int
+el_source(EditLine *el, const char *fname)
+{
+ FILE *fp;
+ size_t len;
+ ssize_t slen;
+ char *ptr;
+ char *path = NULL;
+ const wchar_t *dptr;
+ int error = 0;
+
+ fp = NULL;
+ if (fname == NULL) {
+#ifdef HAVE_ISSETUGID
+ static const char elpath[] = "/.editrc";
+ size_t plen = sizeof(elpath);
+
+ if (issetugid())
+ return -1;
+ if ((ptr = getenv("HOME")) == NULL)
+ return -1;
+ plen += strlen(ptr);
+ if ((path = el_malloc(plen * sizeof(*path))) == NULL)
+ return -1;
+ (void)snprintf(path, plen, "%s%s", ptr, elpath);
+ fname = path;
+#else
+ /*
+ * If issetugid() is missing, always return an error, in order
+ * to keep from inadvertently opening up the user to a security
+ * hole.
+ */
+ return -1;
+#endif
+ }
+ if (fp == NULL)
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ el_free(path);
+ return -1;
+ }
+
+ ptr = NULL;
+ len = 0;
+ while ((slen = getline(&ptr, &len, fp)) != -1) {
+ if (*ptr == '\n')
+ continue; /* Empty line. */
+ if (slen > 0 && ptr[--slen] == '\n')
+ ptr[slen] = '\0';
+
+ dptr = ct_decode_string(ptr, &el->el_scratch);
+ if (!dptr)
+ continue;
+ /* loop until first non-space char or EOL */
+ while (*dptr != '\0' && iswspace(*dptr))
+ dptr++;
+ if (*dptr == '#')
+ continue; /* ignore, this is a comment line */
+ if ((error = parse_line(el, dptr)) == -1)
+ break;
+ }
+ free(ptr);
+
+ el_free(path);
+ (void) fclose(fp);
+ return error;
+}
+
+
+/* el_resize():
+ * Called from program when terminal is resized
+ */
+void
+el_resize(EditLine *el)
+{
+ int lins, cols;
+ sigset_t oset, nset;
+
+ (void) sigemptyset(&nset);
+ (void) sigaddset(&nset, SIGWINCH);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ /* get the correct window size */
+ if (terminal_get_size(el, &lins, &cols))
+ terminal_change_size(el, lins, cols);
+
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
+
+/* el_beep():
+ * Called from the program to beep
+ */
+void
+el_beep(EditLine *el)
+{
+
+ terminal_beep(el);
+}
+
+
+/* el_editmode()
+ * Set the state of EDIT_DISABLED from the `edit' command.
+ */
+libedit_private int
+/*ARGSUSED*/
+el_editmode(EditLine *el, int argc, const wchar_t **argv)
+{
+ const wchar_t *how;
+
+ if (argv == NULL || argc != 2 || argv[1] == NULL)
+ return -1;
+
+ how = argv[1];
+ if (wcscmp(how, L"on") == 0) {
+ el->el_flags &= ~EDIT_DISABLED;
+ tty_rawmode(el);
+ } else if (wcscmp(how, L"off") == 0) {
+ tty_cookedmode(el);
+ el->el_flags |= EDIT_DISABLED;
+ }
+ else {
+ (void) fprintf(el->el_errfile, "edit: Bad value `%ls'.\n",
+ how);
+ return -1;
+ }
+ return 0;
+}
diff --git a/third_party/heimdal/lib/libedit/src/el.h b/third_party/heimdal/lib/libedit/src/el.h
new file mode 100644
index 0000000..c281bc0
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/el.h
@@ -0,0 +1,153 @@
+/* $NetBSD: el.h,v 1.41 2016/05/24 15:00:45 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)el.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.h: Internal structures.
+ */
+#ifndef _h_el
+#define _h_el
+/*
+ * Local defaults
+ */
+#define KSHVI
+#define VIDEFAULT
+#define ANCHOR
+
+#include "histedit.h"
+#include "chartype.h"
+
+#define EL_BUFSIZ ((size_t)1024) /* Maximum line size */
+
+#define HANDLE_SIGNALS 0x01
+#define NO_TTY 0x02
+#define EDIT_DISABLED 0x04
+#define UNBUFFERED 0x08
+#define CHARSET_IS_UTF8 0x10
+#define NARROW_HISTORY 0x40
+
+typedef unsigned char el_action_t; /* Index to command array */
+
+typedef struct coord_t { /* Position on the screen */
+ int h;
+ int v;
+} coord_t;
+
+typedef struct el_line_t {
+ wchar_t *buffer; /* Input line */
+ wchar_t *cursor; /* Cursor position */
+ wchar_t *lastchar; /* Last character */
+ const wchar_t *limit; /* Max position */
+} el_line_t;
+
+/*
+ * Editor state
+ */
+typedef struct el_state_t {
+ int inputmode; /* What mode are we in? */
+ int doingarg; /* Are we getting an argument? */
+ int argument; /* Numeric argument */
+ int metanext; /* Is the next char a meta char */
+ el_action_t lastcmd; /* Previous command */
+ el_action_t thiscmd; /* this command */
+ wchar_t thisch; /* char that generated it */
+} el_state_t;
+
+/*
+ * Until we come up with something better...
+ */
+#define el_malloc(a) malloc(a)
+#define el_realloc(a,b) realloc(a, b)
+#define el_free(a) free(a)
+
+#include "tty.h"
+#include "prompt.h"
+#include "keymacro.h"
+#include "terminal.h"
+#include "refresh.h"
+#include "chared.h"
+#include "search.h"
+#include "hist.h"
+#include "map.h"
+#include "sig.h"
+
+struct el_read_t;
+
+struct editline {
+ wchar_t *el_prog; /* the program name */
+ FILE *el_infile; /* Stdio stuff */
+ FILE *el_outfile; /* Stdio stuff */
+ FILE *el_errfile; /* Stdio stuff */
+ int el_infd; /* Input file descriptor */
+ int el_outfd; /* Output file descriptor */
+ int el_errfd; /* Error file descriptor */
+ int el_flags; /* Various flags. */
+ coord_t el_cursor; /* Cursor location */
+ wchar_t **el_display; /* Real screen image = what is there */
+ wchar_t **el_vdisplay; /* Virtual screen image = what we see */
+ void *el_data; /* Client data */
+ el_line_t el_line; /* The current line information */
+ el_state_t el_state; /* Current editor state */
+ el_terminal_t el_terminal; /* Terminal dependent stuff */
+ el_tty_t el_tty; /* Tty dependent stuff */
+ el_refresh_t el_refresh; /* Refresh stuff */
+ el_prompt_t el_prompt; /* Prompt stuff */
+ el_prompt_t el_rprompt; /* Prompt stuff */
+ el_chared_t el_chared; /* Characted editor stuff */
+ el_map_t el_map; /* Key mapping stuff */
+ el_keymacro_t el_keymacro; /* Key binding stuff */
+ el_history_t el_history; /* History stuff */
+ el_search_t el_search; /* Search stuff */
+ el_signal_t el_signal; /* Signal handling stuff */
+ struct el_read_t *el_read; /* Character reading stuff */
+ ct_buffer_t el_visual; /* Buffer for displayable str */
+ ct_buffer_t el_scratch; /* Scratch conversion buffer */
+ ct_buffer_t el_lgcyconv; /* Buffer for legacy wrappers */
+ LineInfo el_lgcylinfo; /* Legacy LineInfo buffer */
+};
+
+libedit_private int el_editmode(EditLine *, int, const wchar_t **);
+
+#ifdef DEBUG
+#define EL_ABORT(a) do { \
+ fprintf(el->el_errfile, "%s, %d: ", \
+ __FILE__, __LINE__); \
+ fprintf a; \
+ abort(); \
+ } while( /*CONSTCOND*/0);
+#else
+#define EL_ABORT(a) abort()
+#endif
+#endif /* _h_el */
diff --git a/third_party/heimdal/lib/libedit/src/eln.c b/third_party/heimdal/lib/libedit/src/eln.c
new file mode 100644
index 0000000..aa0a5b5
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/eln.c
@@ -0,0 +1,388 @@
+/* $NetBSD: eln.c,v 1.34 2016/05/09 21:37:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+__RCSID("$NetBSD: eln.c,v 1.34 2016/05/09 21:37:34 christos Exp $");
+#endif /* not lint && not SCCSID */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "el.h"
+
+int
+el_getc(EditLine *el, char *cp)
+{
+ int num_read;
+ wchar_t wc = 0;
+
+ num_read = el_wgetc(el, &wc);
+ *cp = '\0';
+ if (num_read <= 0)
+ return num_read;
+ num_read = wctob(wc);
+ if (num_read == EOF) {
+ errno = ERANGE;
+ return -1;
+ } else {
+ *cp = (char)num_read;
+ return 1;
+ }
+}
+
+
+void
+el_push(EditLine *el, const char *str)
+{
+ /* Using multibyte->wide string decoding works fine under single-byte
+ * character sets too, and Does The Right Thing. */
+ el_wpush(el, ct_decode_string(str, &el->el_lgcyconv));
+}
+
+
+const char *
+el_gets(EditLine *el, int *nread)
+{
+ const wchar_t *tmp;
+
+ tmp = el_wgets(el, nread);
+ if (tmp != NULL) {
+ int i;
+ size_t nwread = 0;
+
+ for (i = 0; i < *nread; i++)
+ nwread += ct_enc_width(tmp[i]);
+ *nread = (int)nwread;
+ }
+ return ct_encode_string(tmp, &el->el_lgcyconv);
+}
+
+
+int
+el_parse(EditLine *el, int argc, const char *argv[])
+{
+ int ret;
+ const wchar_t **wargv;
+
+ wargv = (void *)ct_decode_argv(argc, argv, &el->el_lgcyconv);
+ if (!wargv)
+ return -1;
+ ret = el_wparse(el, argc, wargv);
+ el_free(wargv);
+
+ return ret;
+}
+
+
+int
+el_set(EditLine *el, int op, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (!el)
+ return -1;
+ va_start(ap, op);
+
+ switch (op) {
+ case EL_PROMPT: /* el_pfunc_t */
+ case EL_RPROMPT: {
+ el_pfunc_t p = va_arg(ap, el_pfunc_t);
+ ret = prompt_set(el, p, 0, op, 0);
+ break;
+ }
+
+ case EL_RESIZE: {
+ el_zfunc_t p = va_arg(ap, el_zfunc_t);
+ void *arg = va_arg(ap, void *);
+ ret = ch_resizefun(el, p, arg);
+ break;
+ }
+
+ case EL_ALIAS_TEXT: {
+ el_afunc_t p = va_arg(ap, el_afunc_t);
+ void *arg = va_arg(ap, void *);
+ ret = ch_aliasfun(el, p, arg);
+ break;
+ }
+
+ case EL_PROMPT_ESC:
+ case EL_RPROMPT_ESC: {
+ el_pfunc_t p = va_arg(ap, el_pfunc_t);
+ int c = va_arg(ap, int);
+
+ ret = prompt_set(el, p, c, op, 0);
+ break;
+ }
+
+ case EL_TERMINAL: /* const char * */
+ ret = el_wset(el, op, va_arg(ap, char *));
+ break;
+
+ case EL_EDITOR: /* const wchar_t * */
+ ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *),
+ &el->el_lgcyconv));
+ break;
+
+ case EL_SIGNAL: /* int */
+ case EL_EDITMODE:
+ case EL_UNBUFFERED:
+ case EL_PREP_TERM:
+ ret = el_wset(el, op, va_arg(ap, int));
+ break;
+
+ case EL_BIND: /* const char * list -> const wchar_t * list */
+ case EL_TELLTC:
+ case EL_SETTC:
+ case EL_ECHOTC:
+ case EL_SETTY: {
+ const char *argv[20];
+ int i;
+ const wchar_t **wargv;
+ for (i = 1; i < (int)__arraycount(argv) - 1; ++i)
+ if ((argv[i] = va_arg(ap, const char *)) == NULL)
+ break;
+ argv[0] = argv[i] = NULL;
+ wargv = (void *)ct_decode_argv(i + 1, argv, &el->el_lgcyconv);
+ if (!wargv) {
+ ret = -1;
+ goto out;
+ }
+ /*
+ * AFAIK we can't portably pass through our new wargv to
+ * el_wset(), so we have to reimplement the body of
+ * el_wset() for these ops.
+ */
+ switch (op) {
+ case EL_BIND:
+ wargv[0] = L"bind";
+ ret = map_bind(el, i, wargv);
+ break;
+ case EL_TELLTC:
+ wargv[0] = L"telltc";
+ ret = terminal_telltc(el, i, wargv);
+ break;
+ case EL_SETTC:
+ wargv[0] = L"settc";
+ ret = terminal_settc(el, i, wargv);
+ break;
+ case EL_ECHOTC:
+ wargv[0] = L"echotc";
+ ret = terminal_echotc(el, i, wargv);
+ break;
+ case EL_SETTY:
+ wargv[0] = L"setty";
+ ret = tty_stty(el, i, wargv);
+ break;
+ default:
+ ret = -1;
+ }
+ el_free(wargv);
+ break;
+ }
+
+ /* XXX: do we need to change el_func_t too? */
+ case EL_ADDFN: { /* const char *, const char *, el_func_t */
+ const char *args[2];
+ el_func_t func;
+ wchar_t **wargv;
+
+ args[0] = va_arg(ap, const char *);
+ args[1] = va_arg(ap, const char *);
+ func = va_arg(ap, el_func_t);
+
+ wargv = ct_decode_argv(2, args, &el->el_lgcyconv);
+ if (!wargv) {
+ ret = -1;
+ goto out;
+ }
+ /* XXX: The two strdup's leak */
+ ret = map_addfunc(el, wcsdup(wargv[0]), wcsdup(wargv[1]),
+ func);
+ el_free(wargv);
+ break;
+ }
+ case EL_HIST: { /* hist_fun_t, const char * */
+ hist_fun_t fun = va_arg(ap, hist_fun_t);
+ void *ptr = va_arg(ap, void *);
+ ret = hist_set(el, fun, ptr);
+ el->el_flags |= NARROW_HISTORY;
+ break;
+ }
+
+ case EL_GETCFN: /* el_rfunc_t */
+ ret = el_wset(el, op, va_arg(ap, el_rfunc_t));
+ break;
+
+ case EL_CLIENTDATA: /* void * */
+ ret = el_wset(el, op, va_arg(ap, void *));
+ break;
+
+ case EL_SETFP: { /* int, FILE * */
+ int what = va_arg(ap, int);
+ FILE *fp = va_arg(ap, FILE *);
+ ret = el_wset(el, op, what, fp);
+ break;
+ }
+
+ case EL_REFRESH:
+ re_clear_display(el);
+ re_refresh(el);
+ terminal__flush(el);
+ ret = 0;
+ break;
+
+ default:
+ ret = -1;
+ break;
+ }
+
+out:
+ va_end(ap);
+ return ret;
+}
+
+
+int
+el_get(EditLine *el, int op, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (!el)
+ return -1;
+
+ va_start(ap, op);
+
+ switch (op) {
+ case EL_PROMPT: /* el_pfunc_t * */
+ case EL_RPROMPT: {
+ el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
+ ret = prompt_get(el, p, 0, op);
+ break;
+ }
+
+ case EL_PROMPT_ESC: /* el_pfunc_t *, char **/
+ case EL_RPROMPT_ESC: {
+ el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
+ char *c = va_arg(ap, char *);
+ wchar_t wc = 0;
+ ret = prompt_get(el, p, &wc, op);
+ *c = (char)wc;
+ break;
+ }
+
+ case EL_EDITOR: {
+ const char **p = va_arg(ap, const char **);
+ const wchar_t *pw;
+ ret = el_wget(el, op, &pw);
+ *p = ct_encode_string(pw, &el->el_lgcyconv);
+ if (!el->el_lgcyconv.csize)
+ ret = -1;
+ break;
+ }
+
+ case EL_TERMINAL: /* const char ** */
+ ret = el_wget(el, op, va_arg(ap, const char **));
+ break;
+
+ case EL_SIGNAL: /* int * */
+ case EL_EDITMODE:
+ case EL_UNBUFFERED:
+ case EL_PREP_TERM:
+ ret = el_wget(el, op, va_arg(ap, int *));
+ break;
+
+ case EL_GETTC: {
+ char *argv[20];
+ static char gettc[] = "gettc";
+ int i;
+ for (i = 1; i < (int)__arraycount(argv); ++i)
+ if ((argv[i] = va_arg(ap, char *)) == NULL)
+ break;
+ argv[0] = gettc;
+ ret = terminal_gettc(el, i, argv);
+ break;
+ }
+
+ case EL_GETCFN: /* el_rfunc_t */
+ ret = el_wget(el, op, va_arg(ap, el_rfunc_t *));
+ break;
+
+ case EL_CLIENTDATA: /* void ** */
+ ret = el_wget(el, op, va_arg(ap, void **));
+ break;
+
+ case EL_GETFP: { /* int, FILE ** */
+ int what = va_arg(ap, int);
+ FILE **fpp = va_arg(ap, FILE **);
+ ret = el_wget(el, op, what, fpp);
+ break;
+ }
+
+ default:
+ ret = -1;
+ break;
+ }
+
+ va_end(ap);
+ return ret;
+}
+
+
+const LineInfo *
+el_line(EditLine *el)
+{
+ const LineInfoW *winfo = el_wline(el);
+ LineInfo *info = &el->el_lgcylinfo;
+ size_t offset;
+ const wchar_t *p;
+
+ info->buffer = ct_encode_string(winfo->buffer, &el->el_lgcyconv);
+
+ offset = 0;
+ for (p = winfo->buffer; p < winfo->cursor; p++)
+ offset += ct_enc_width(*p);
+ info->cursor = info->buffer + offset;
+
+ offset = 0;
+ for (p = winfo->buffer; p < winfo->lastchar; p++)
+ offset += ct_enc_width(*p);
+ info->lastchar = info->buffer + offset;
+
+ return info;
+}
+
+
+int
+el_insertstr(EditLine *el, const char *str)
+{
+ return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv));
+}
diff --git a/third_party/heimdal/lib/libedit/src/emacs.c b/third_party/heimdal/lib/libedit/src/emacs.c
new file mode 100644
index 0000000..0636c28
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/emacs.c
@@ -0,0 +1,512 @@
+/* $NetBSD: emacs.c,v 1.36 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: emacs.c,v 1.36 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * emacs.c: Emacs functions
+ */
+#include <ctype.h>
+
+#include "el.h"
+#include "emacs.h"
+#include "fcns.h"
+
+/* em_delete_or_list():
+ * Delete character under cursor or list completions if at end of line
+ * [^D]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_delete_or_list(EditLine *el, wint_t c)
+{
+
+ if (el->el_line.cursor == el->el_line.lastchar) {
+ /* if I'm at the end */
+ if (el->el_line.cursor == el->el_line.buffer) {
+ /* and the beginning */
+ terminal_writec(el, c); /* then do an EOF */
+ return CC_EOF;
+ } else {
+ /*
+ * Here we could list completions, but it is an
+ * error right now
+ */
+ terminal_beep(el);
+ return CC_ERROR;
+ }
+ } else {
+ if (el->el_state.doingarg)
+ c_delafter(el, el->el_state.argument);
+ else
+ c_delafter1(el);
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ /* bounds check */
+ return CC_REFRESH;
+ }
+}
+
+
+/* em_delete_next_word():
+ * Cut from cursor to end of current word
+ * [M-d]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_delete_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *cp, *p, *kp;
+
+ if (el->el_line.cursor == el->el_line.lastchar)
+ return CC_ERROR;
+
+ cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
+ el->el_state.argument, ce__isword);
+
+ for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
+ /* save the text */
+ *kp++ = *p;
+ el->el_chared.c_kill.last = kp;
+
+ c_delafter(el, (int)(cp - el->el_line.cursor)); /* delete after dot */
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ /* bounds check */
+ return CC_REFRESH;
+}
+
+
+/* em_yank():
+ * Paste cut buffer at cursor position
+ * [^Y]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_yank(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *kp, *cp;
+
+ if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
+ return CC_NORM;
+
+ if (el->el_line.lastchar +
+ (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
+ el->el_line.limit)
+ return CC_ERROR;
+
+ el->el_chared.c_kill.mark = el->el_line.cursor;
+ cp = el->el_line.cursor;
+
+ /* open the space, */
+ c_insert(el,
+ (int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf));
+ /* copy the chars */
+ for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
+ *cp++ = *kp;
+
+ /* if an arg, cursor at beginning else cursor at end */
+ if (el->el_state.argument == 1)
+ el->el_line.cursor = cp;
+
+ return CC_REFRESH;
+}
+
+
+/* em_kill_line():
+ * Cut the entire line and save in cut buffer
+ * [^U]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *kp, *cp;
+
+ cp = el->el_line.buffer;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.lastchar)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ /* zap! -- delete all of it */
+ el->el_line.lastchar = el->el_line.buffer;
+ el->el_line.cursor = el->el_line.buffer;
+ return CC_REFRESH;
+}
+
+
+/* em_kill_region():
+ * Cut area between mark and cursor and save in cut buffer
+ * [^W]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_kill_region(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *kp, *cp;
+
+ if (!el->el_chared.c_kill.mark)
+ return CC_ERROR;
+
+ if (el->el_chared.c_kill.mark > el->el_line.cursor) {
+ cp = el->el_line.cursor;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_chared.c_kill.mark)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ c_delafter(el, (int)(cp - el->el_line.cursor));
+ } else { /* mark is before cursor */
+ cp = el->el_chared.c_kill.mark;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.cursor)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark));
+ el->el_line.cursor = el->el_chared.c_kill.mark;
+ }
+ return CC_REFRESH;
+}
+
+
+/* em_copy_region():
+ * Copy area between mark and cursor to cut buffer
+ * [M-W]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_copy_region(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *kp, *cp;
+
+ if (!el->el_chared.c_kill.mark)
+ return CC_ERROR;
+
+ if (el->el_chared.c_kill.mark > el->el_line.cursor) {
+ cp = el->el_line.cursor;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_chared.c_kill.mark)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ } else {
+ cp = el->el_chared.c_kill.mark;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.cursor)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ }
+ return CC_NORM;
+}
+
+
+/* em_gosmacs_transpose():
+ * Exchange the two characters before the cursor
+ * Gosling emacs transpose chars [^T]
+ */
+libedit_private el_action_t
+em_gosmacs_transpose(EditLine *el, wint_t c)
+{
+
+ if (el->el_line.cursor > &el->el_line.buffer[1]) {
+ /* must have at least two chars entered */
+ c = el->el_line.cursor[-2];
+ el->el_line.cursor[-2] = el->el_line.cursor[-1];
+ el->el_line.cursor[-1] = c;
+ return CC_REFRESH;
+ } else
+ return CC_ERROR;
+}
+
+
+/* em_next_word():
+ * Move next to end of current word
+ * [M-f]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ if (el->el_line.cursor == el->el_line.lastchar)
+ return CC_ERROR;
+
+ el->el_line.cursor = c__next_word(el->el_line.cursor,
+ el->el_line.lastchar,
+ el->el_state.argument,
+ ce__isword);
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* em_upper_case():
+ * Uppercase the characters from cursor to end of current word
+ * [M-u]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_upper_case(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *cp, *ep;
+
+ ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
+ el->el_state.argument, ce__isword);
+
+ for (cp = el->el_line.cursor; cp < ep; cp++)
+ if (iswlower(*cp))
+ *cp = towupper(*cp);
+
+ el->el_line.cursor = ep;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ return CC_REFRESH;
+}
+
+
+/* em_capitol_case():
+ * Capitalize the characters from cursor to end of current word
+ * [M-c]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_capitol_case(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *cp, *ep;
+
+ ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
+ el->el_state.argument, ce__isword);
+
+ for (cp = el->el_line.cursor; cp < ep; cp++) {
+ if (iswalpha(*cp)) {
+ if (iswlower(*cp))
+ *cp = towupper(*cp);
+ cp++;
+ break;
+ }
+ }
+ for (; cp < ep; cp++)
+ if (iswupper(*cp))
+ *cp = towlower(*cp);
+
+ el->el_line.cursor = ep;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ return CC_REFRESH;
+}
+
+
+/* em_lower_case():
+ * Lowercase the characters from cursor to end of current word
+ * [M-l]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_lower_case(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *cp, *ep;
+
+ ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
+ el->el_state.argument, ce__isword);
+
+ for (cp = el->el_line.cursor; cp < ep; cp++)
+ if (iswupper(*cp))
+ *cp = towlower(*cp);
+
+ el->el_line.cursor = ep;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ return CC_REFRESH;
+}
+
+
+/* em_set_mark():
+ * Set the mark at cursor
+ * [^@]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_set_mark(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_chared.c_kill.mark = el->el_line.cursor;
+ return CC_NORM;
+}
+
+
+/* em_exchange_mark():
+ * Exchange the cursor and mark
+ * [^X^X]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_exchange_mark(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *cp;
+
+ cp = el->el_line.cursor;
+ el->el_line.cursor = el->el_chared.c_kill.mark;
+ el->el_chared.c_kill.mark = cp;
+ return CC_CURSOR;
+}
+
+
+/* em_universal_argument():
+ * Universal argument (argument times 4)
+ * [^U]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_universal_argument(EditLine *el, wint_t c __attribute__((__unused__)))
+{ /* multiply current argument by 4 */
+
+ if (el->el_state.argument > 1000000)
+ return CC_ERROR;
+ el->el_state.doingarg = 1;
+ el->el_state.argument *= 4;
+ return CC_ARGHACK;
+}
+
+
+/* em_meta_next():
+ * Add 8th bit to next character typed
+ * [<ESC>]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_meta_next(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_state.metanext = 1;
+ return CC_ARGHACK;
+}
+
+
+/* em_toggle_overwrite():
+ * Switch from insert to overwrite mode or vice versa
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_toggle_overwrite(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
+ MODE_REPLACE : MODE_INSERT;
+ return CC_NORM;
+}
+
+
+/* em_copy_prev_word():
+ * Copy current word to cursor
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_copy_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *cp, *oldc, *dp;
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return CC_ERROR;
+
+ oldc = el->el_line.cursor;
+ /* does a bounds check */
+ cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
+ el->el_state.argument, ce__isword);
+
+ c_insert(el, (int)(oldc - cp));
+ for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
+ *dp++ = *cp;
+
+ el->el_line.cursor = dp;/* put cursor at end */
+
+ return CC_REFRESH;
+}
+
+
+/* em_inc_search_next():
+ * Emacs incremental next search
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_inc_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_search.patlen = 0;
+ return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
+}
+
+
+/* em_inc_search_prev():
+ * Emacs incremental reverse search
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_inc_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_search.patlen = 0;
+ return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
+}
+
+
+/* em_delete_prev_char():
+ * Delete the character to the left of the cursor
+ * [^?]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+em_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor <= el->el_line.buffer)
+ return CC_ERROR;
+
+ if (el->el_state.doingarg)
+ c_delbefore(el, el->el_state.argument);
+ else
+ c_delbefore1(el);
+ el->el_line.cursor -= el->el_state.argument;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+ return CC_REFRESH;
+}
diff --git a/third_party/heimdal/lib/libedit/src/filecomplete.c b/third_party/heimdal/lib/libedit/src/filecomplete.c
new file mode 100644
index 0000000..d1051f0
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/filecomplete.c
@@ -0,0 +1,573 @@
+/* $NetBSD: filecomplete.c,v 1.44 2016/10/31 17:46:32 abhinav Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jaromir Dolecek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+__RCSID("$NetBSD: filecomplete.c,v 1.44 2016/10/31 17:46:32 abhinav Exp $");
+#endif /* not lint && not SCCSID */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "el.h"
+#include "filecomplete.h"
+
+static const wchar_t break_chars[] = L" \t\n\"\\'`@$><=;|&{(";
+
+/********************************/
+/* completion functions */
+
+/*
+ * does tilde expansion of strings of type ``~user/foo''
+ * if ``user'' isn't valid user name or ``txt'' doesn't start
+ * w/ '~', returns pointer to strdup()ed copy of ``txt''
+ *
+ * it's the caller's responsibility to free() the returned string
+ */
+char *
+fn_tilde_expand(const char *txt)
+{
+#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT)
+ struct passwd pwres;
+ char pwbuf[1024];
+#endif
+ struct passwd *pass;
+ char *temp;
+ size_t len = 0;
+
+ if (txt[0] != '~')
+ return strdup(txt);
+
+ temp = strchr(txt + 1, '/');
+ if (temp == NULL) {
+ temp = strdup(txt + 1);
+ if (temp == NULL)
+ return NULL;
+ } else {
+ /* text until string after slash */
+ len = (size_t)(temp - txt + 1);
+ temp = el_malloc(len * sizeof(*temp));
+ if (temp == NULL)
+ return NULL;
+ (void)strncpy(temp, txt + 1, len - 2);
+ temp[len - 2] = '\0';
+ }
+ if (temp[0] == 0) {
+#ifdef HAVE_GETPW_R_POSIX
+ if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf),
+ &pass) != 0)
+ pass = NULL;
+#elif HAVE_GETPW_R_DRAFT
+ pass = getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf));
+#else
+ pass = getpwuid(getuid());
+#endif
+ } else {
+#ifdef HAVE_GETPW_R_POSIX
+ if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0)
+ pass = NULL;
+#elif HAVE_GETPW_R_DRAFT
+ pass = getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf));
+#else
+ pass = getpwnam(temp);
+#endif
+ }
+ el_free(temp); /* value no more needed */
+ if (pass == NULL)
+ return strdup(txt);
+
+ /* update pointer txt to point at string immedially following */
+ /* first slash */
+ txt += len;
+
+ len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1;
+ temp = el_malloc(len * sizeof(*temp));
+ if (temp == NULL)
+ return NULL;
+ (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt);
+
+ return temp;
+}
+
+
+/*
+ * return first found file name starting by the ``text'' or NULL if no
+ * such file can be found
+ * value of ``state'' is ignored
+ *
+ * it's the caller's responsibility to free the returned string
+ */
+char *
+fn_filename_completion_function(const char *text, int state)
+{
+ static DIR *dir = NULL;
+ static char *filename = NULL, *dirname = NULL, *dirpath = NULL;
+ static size_t filename_len = 0;
+ struct dirent *entry;
+ char *temp;
+ size_t len;
+
+ if (state == 0 || dir == NULL) {
+ temp = strrchr(text, '/');
+ if (temp) {
+ char *nptr;
+ temp++;
+ nptr = el_realloc(filename, (strlen(temp) + 1) *
+ sizeof(*nptr));
+ if (nptr == NULL) {
+ el_free(filename);
+ filename = NULL;
+ return NULL;
+ }
+ filename = nptr;
+ (void)strcpy(filename, temp);
+ len = (size_t)(temp - text); /* including last slash */
+
+ nptr = el_realloc(dirname, (len + 1) *
+ sizeof(*nptr));
+ if (nptr == NULL) {
+ el_free(dirname);
+ dirname = NULL;
+ return NULL;
+ }
+ dirname = nptr;
+ (void)strncpy(dirname, text, len);
+ dirname[len] = '\0';
+ } else {
+ el_free(filename);
+ if (*text == 0)
+ filename = NULL;
+ else {
+ filename = strdup(text);
+ if (filename == NULL)
+ return NULL;
+ }
+ el_free(dirname);
+ dirname = NULL;
+ }
+
+ if (dir != NULL) {
+ (void)closedir(dir);
+ dir = NULL;
+ }
+
+ /* support for ``~user'' syntax */
+
+ el_free(dirpath);
+ dirpath = NULL;
+ if (dirname == NULL) {
+ if ((dirname = strdup("")) == NULL)
+ return NULL;
+ dirpath = strdup("./");
+ } else if (*dirname == '~')
+ dirpath = fn_tilde_expand(dirname);
+ else
+ dirpath = strdup(dirname);
+
+ if (dirpath == NULL)
+ return NULL;
+
+ dir = opendir(dirpath);
+ if (!dir)
+ return NULL; /* cannot open the directory */
+
+ /* will be used in cycle */
+ filename_len = filename ? strlen(filename) : 0;
+ }
+
+ /* find the match */
+ while ((entry = readdir(dir)) != NULL) {
+ /* skip . and .. */
+ if (entry->d_name[0] == '.' && (!entry->d_name[1]
+ || (entry->d_name[1] == '.' && !entry->d_name[2])))
+ continue;
+ if (filename_len == 0)
+ break;
+ /* otherwise, get first entry where first */
+ /* filename_len characters are equal */
+ if (entry->d_name[0] == filename[0]
+#if HAVE_STRUCT_DIRENT_D_NAMLEN
+ && entry->d_namlen >= filename_len
+#else
+ && strlen(entry->d_name) >= filename_len
+#endif
+ && strncmp(entry->d_name, filename,
+ filename_len) == 0)
+ break;
+ }
+
+ if (entry) { /* match found */
+
+#if HAVE_STRUCT_DIRENT_D_NAMLEN
+ len = entry->d_namlen;
+#else
+ len = strlen(entry->d_name);
+#endif
+
+ len = strlen(dirname) + len + 1;
+ temp = el_malloc(len * sizeof(*temp));
+ if (temp == NULL)
+ return NULL;
+ (void)snprintf(temp, len, "%s%s", dirname, entry->d_name);
+ } else {
+ (void)closedir(dir);
+ dir = NULL;
+ temp = NULL;
+ }
+
+ return temp;
+}
+
+
+static const char *
+append_char_function(const char *name)
+{
+ struct stat stbuf;
+ char *expname = *name == '~' ? fn_tilde_expand(name) : NULL;
+ const char *rs = " ";
+
+ if (stat(expname ? expname : name, &stbuf) == -1)
+ goto out;
+ if (S_ISDIR(stbuf.st_mode))
+ rs = "/";
+out:
+ if (expname)
+ el_free(expname);
+ return rs;
+}
+/*
+ * returns list of completions for text given
+ * non-static for readline.
+ */
+char ** completion_matches(const char *, char *(*)(const char *, int));
+char **
+completion_matches(const char *text, char *(*genfunc)(const char *, int))
+{
+ char **match_list = NULL, *retstr, *prevstr;
+ size_t match_list_len, max_equal, which, i;
+ size_t matches;
+
+ matches = 0;
+ match_list_len = 1;
+ while ((retstr = (*genfunc) (text, (int)matches)) != NULL) {
+ /* allow for list terminator here */
+ if (matches + 3 >= match_list_len) {
+ char **nmatch_list;
+ while (matches + 3 >= match_list_len)
+ match_list_len <<= 1;
+ nmatch_list = el_realloc(match_list,
+ match_list_len * sizeof(*nmatch_list));
+ if (nmatch_list == NULL) {
+ el_free(match_list);
+ return NULL;
+ }
+ match_list = nmatch_list;
+
+ }
+ match_list[++matches] = retstr;
+ }
+
+ if (!match_list)
+ return NULL; /* nothing found */
+
+ /* find least denominator and insert it to match_list[0] */
+ which = 2;
+ prevstr = match_list[1];
+ max_equal = strlen(prevstr);
+ for (; which <= matches; which++) {
+ for (i = 0; i < max_equal &&
+ prevstr[i] == match_list[which][i]; i++)
+ continue;
+ max_equal = i;
+ }
+
+ retstr = el_malloc((max_equal + 1) * sizeof(*retstr));
+ if (retstr == NULL) {
+ el_free(match_list);
+ return NULL;
+ }
+ (void)strncpy(retstr, match_list[1], max_equal);
+ retstr[max_equal] = '\0';
+ match_list[0] = retstr;
+
+ /* add NULL as last pointer to the array */
+ match_list[matches + 1] = NULL;
+
+ return match_list;
+}
+
+/*
+ * Sort function for qsort(). Just wrapper around strcasecmp().
+ */
+static int
+_fn_qsort_string_compare(const void *i1, const void *i2)
+{
+ const char *s1 = ((const char * const *)i1)[0];
+ const char *s2 = ((const char * const *)i2)[0];
+
+ return strcasecmp(s1, s2);
+}
+
+/*
+ * Display list of strings in columnar format on readline's output stream.
+ * 'matches' is list of strings, 'num' is number of strings in 'matches',
+ * 'width' is maximum length of string in 'matches'.
+ *
+ * matches[0] is not one of the match strings, but it is counted in
+ * num, so the strings are matches[1] *through* matches[num-1].
+ */
+void
+fn_display_match_list (EditLine *el, char **matches, size_t num, size_t width)
+{
+ size_t line, lines, col, cols, thisguy;
+ int screenwidth = el->el_terminal.t_size.h;
+
+ /* Ignore matches[0]. Avoid 1-based array logic below. */
+ matches++;
+ num--;
+
+ /*
+ * Find out how many entries can be put on one line; count
+ * with one space between strings the same way it's printed.
+ */
+ cols = (size_t)screenwidth / (width + 1);
+ if (cols == 0)
+ cols = 1;
+
+ /* how many lines of output, rounded up */
+ lines = (num + cols - 1) / cols;
+
+ /* Sort the items. */
+ qsort(matches, num, sizeof(char *), _fn_qsort_string_compare);
+
+ /*
+ * On the ith line print elements i, i+lines, i+lines*2, etc.
+ */
+ for (line = 0; line < lines; line++) {
+ for (col = 0; col < cols; col++) {
+ thisguy = line + col * lines;
+ if (thisguy >= num)
+ break;
+ (void)fprintf(el->el_outfile, "%s%-*s",
+ col == 0 ? "" : " ", (int)width, matches[thisguy]);
+ }
+ (void)fprintf(el->el_outfile, "\n");
+ }
+}
+
+/*
+ * Complete the word at or before point,
+ * 'what_to_do' says what to do with the completion.
+ * \t means do standard completion.
+ * `?' means list the possible completions.
+ * `*' means insert all of the possible completions.
+ * `!' means to do standard completion, and list all possible completions if
+ * there is more than one.
+ *
+ * Note: '*' support is not implemented
+ * '!' could never be invoked
+ */
+int
+fn_complete(EditLine *el,
+ char *(*complet_func)(const char *, int),
+ char **(*attempted_completion_function)(const char *, int, int),
+ const wchar_t *word_break, const wchar_t *special_prefixes,
+ const char *(*app_func)(const char *), size_t query_items,
+ int *completion_type, int *over, int *point, int *end)
+{
+ const LineInfoW *li;
+ wchar_t *temp;
+ char **matches;
+ const wchar_t *ctemp;
+ size_t len;
+ int what_to_do = '\t';
+ int retval = CC_NORM;
+
+ if (el->el_state.lastcmd == el->el_state.thiscmd)
+ what_to_do = '?';
+
+ /* readline's rl_complete() has to be told what we did... */
+ if (completion_type != NULL)
+ *completion_type = what_to_do;
+
+ if (!complet_func)
+ complet_func = fn_filename_completion_function;
+ if (!app_func)
+ app_func = append_char_function;
+
+ /* We now look backwards for the start of a filename/variable word */
+ li = el_wline(el);
+ ctemp = li->cursor;
+ while (ctemp > li->buffer
+ && !wcschr(word_break, ctemp[-1])
+ && (!special_prefixes || !wcschr(special_prefixes, ctemp[-1]) ) )
+ ctemp--;
+
+ len = (size_t)(li->cursor - ctemp);
+ temp = el_malloc((len + 1) * sizeof(*temp));
+ (void)wcsncpy(temp, ctemp, len);
+ temp[len] = '\0';
+
+ /* these can be used by function called in completion_matches() */
+ /* or (*attempted_completion_function)() */
+ if (point != NULL)
+ *point = (int)(li->cursor - li->buffer);
+ if (end != NULL)
+ *end = (int)(li->lastchar - li->buffer);
+
+ if (attempted_completion_function) {
+ int cur_off = (int)(li->cursor - li->buffer);
+ matches = (*attempted_completion_function)(
+ ct_encode_string(temp, &el->el_scratch),
+ cur_off - (int)len, cur_off);
+ } else
+ matches = NULL;
+ if (!attempted_completion_function ||
+ (over != NULL && !*over && !matches))
+ matches = completion_matches(
+ ct_encode_string(temp, &el->el_scratch), complet_func);
+
+ if (over != NULL)
+ *over = 0;
+
+ if (matches) {
+ int i;
+ size_t matches_num, maxlen, match_len, match_display=1;
+
+ retval = CC_REFRESH;
+ /*
+ * Only replace the completed string with common part of
+ * possible matches if there is possible completion.
+ */
+ if (matches[0][0] != '\0') {
+ el_deletestr(el, (int) len);
+ el_winsertstr(el,
+ ct_decode_string(matches[0], &el->el_scratch));
+ }
+
+
+ if (matches[2] == NULL &&
+ (matches[1] == NULL || strcmp(matches[0], matches[1]) == 0)) {
+ /*
+ * We found exact match. Add a space after
+ * it, unless we do filename completion and the
+ * object is a directory.
+ */
+ el_winsertstr(el,
+ ct_decode_string((*app_func)(matches[0]),
+ &el->el_scratch));
+ } else if (what_to_do == '!' || what_to_do == '?') {
+ /*
+ * More than one match and requested to list possible
+ * matches.
+ */
+
+ for(i = 1, maxlen = 0; matches[i]; i++) {
+ match_len = strlen(matches[i]);
+ if (match_len > maxlen)
+ maxlen = match_len;
+ }
+ /* matches[1] through matches[i-1] are available */
+ matches_num = (size_t)(i - 1);
+
+ /* newline to get on next line from command line */
+ (void)fprintf(el->el_outfile, "\n");
+
+ /*
+ * If there are too many items, ask user for display
+ * confirmation.
+ */
+ if (matches_num > query_items) {
+ (void)fprintf(el->el_outfile,
+ "Display all %zu possibilities? (y or n) ",
+ matches_num);
+ (void)fflush(el->el_outfile);
+ if (getc(stdin) != 'y')
+ match_display = 0;
+ (void)fprintf(el->el_outfile, "\n");
+ }
+
+ if (match_display) {
+ /*
+ * Interface of this function requires the
+ * strings be matches[1..num-1] for compat.
+ * We have matches_num strings not counting
+ * the prefix in matches[0], so we need to
+ * add 1 to matches_num for the call.
+ */
+ fn_display_match_list(el, matches,
+ matches_num+1, maxlen);
+ }
+ retval = CC_REDISPLAY;
+ } else if (matches[0][0]) {
+ /*
+ * There was some common match, but the name was
+ * not complete enough. Next tab will print possible
+ * completions.
+ */
+ el_beep(el);
+ } else {
+ /* lcd is not a valid object - further specification */
+ /* is needed */
+ el_beep(el);
+ retval = CC_NORM;
+ }
+
+ /* free elements of array and the array itself */
+ for (i = 0; matches[i]; i++)
+ el_free(matches[i]);
+ el_free(matches);
+ matches = NULL;
+ }
+ el_free(temp);
+ return retval;
+}
+
+/*
+ * el-compatible wrapper around rl_complete; needed for key binding
+ */
+/* ARGSUSED */
+unsigned char
+_el_fn_complete(EditLine *el, int ch __attribute__((__unused__)))
+{
+ return (unsigned char)fn_complete(el, NULL, NULL,
+ break_chars, NULL, NULL, (size_t)100,
+ NULL, NULL, NULL, NULL);
+}
diff --git a/third_party/heimdal/lib/libedit/src/filecomplete.h b/third_party/heimdal/lib/libedit/src/filecomplete.h
new file mode 100644
index 0000000..7e93b9e
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/filecomplete.h
@@ -0,0 +1,44 @@
+/* $NetBSD: filecomplete.h,v 1.10 2016/04/11 00:50:13 christos Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jaromir Dolecek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _FILECOMPLETE_H_
+#define _FILECOMPLETE_H_
+
+int fn_complete(EditLine *,
+ char *(*)(const char *, int),
+ char **(*)(const char *, int, int),
+ const wchar_t *, const wchar_t *, const char *(*)(const char *), size_t,
+ int *, int *, int *, int *);
+
+void fn_display_match_list(EditLine *, char **, size_t, size_t);
+char *fn_tilde_expand(const char *);
+char *fn_filename_completion_function(const char *, int);
+
+#endif
diff --git a/third_party/heimdal/lib/libedit/src/getline.c b/third_party/heimdal/lib/libedit/src/getline.c
new file mode 100644
index 0000000..379bcd9
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/getline.c
@@ -0,0 +1,128 @@
+/* Implementations of the getdelim() and getline() functions from POSIX 2008,
+ just in case your libc doesn't have them.
+
+ getdelim() reads from a stream until a specified delimiter is encountered.
+ getline() reads from a stream until a newline is encountered.
+
+ See: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
+
+ NOTE: It is always the caller's responsibility to free the line buffer, even
+ when an error occurs.
+
+ Copyright (c) 2011 James E. Ingram
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#ifndef HAVE_GETLINE
+ssize_t libedit_getline(char **lineptr, size_t *n, FILE *stream);
+#endif
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX 32767
+#endif
+
+#define _GETDELIM_GROWBY 4096 /* amount to grow line buffer by */
+#define _GETDELIM_MINLEN 4 /* minimum line buffer size */
+
+static ssize_t libedit_getdelim(char **restrict lineptr, size_t *restrict n, int delimiter,
+ FILE *restrict stream)
+{
+ char *buf, *pos;
+ int c;
+ ssize_t bytes;
+
+ if (lineptr == NULL || n == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (stream == NULL)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* resize (or allocate) the line buffer if necessary */
+ buf = *lineptr;
+ if (buf == NULL || *n < _GETDELIM_MINLEN)
+ {
+ buf = realloc(*lineptr, _GETDELIM_GROWBY);
+ if (buf == NULL)
+ {
+ /* ENOMEM */
+ return -1;
+ }
+ *n = _GETDELIM_GROWBY;
+ *lineptr = buf;
+ }
+
+ /* read characters until delimiter is found, end of file is reached, or an
+ error occurs. */
+ bytes = 0;
+ pos = buf;
+ while ((c = getc(stream)) != EOF)
+ {
+ if (bytes + 1 >= SSIZE_MAX)
+ {
+ errno = ERANGE;
+ return -1;
+ }
+ bytes++;
+ if (bytes >= *n - 1)
+ {
+ buf = realloc(*lineptr, *n + _GETDELIM_GROWBY);
+ if (buf == NULL)
+ {
+ /* ENOMEM */
+ return -1;
+ }
+ *n += _GETDELIM_GROWBY;
+ pos = buf + bytes - 1;
+ *lineptr = buf;
+ }
+
+ *pos++ = (char) c;
+ if (c == delimiter)
+ {
+ break;
+ }
+ }
+
+ if (ferror(stream) || (feof(stream) && (bytes == 0)))
+ {
+ /* EOF, or an error from getc(). */
+ return -1;
+ }
+
+ *pos = '\0';
+ return bytes;
+}
+
+ssize_t libedit_getline(char **restrict lineptr, size_t *restrict n,
+ FILE *restrict stream)
+{
+ return libedit_getdelim(lineptr, n, '\n', stream);
+}
diff --git a/third_party/heimdal/lib/libedit/src/hist.c b/third_party/heimdal/lib/libedit/src/hist.c
new file mode 100644
index 0000000..4f01ade
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/hist.c
@@ -0,0 +1,245 @@
+/* $NetBSD: hist.c,v 1.30 2016/11/07 15:30:18 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: hist.c,v 1.30 2016/11/07 15:30:18 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * hist.c: History access functions
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <vis.h>
+
+#include "el.h"
+
+/* hist_init():
+ * Initialization function.
+ */
+libedit_private int
+hist_init(EditLine *el)
+{
+
+ el->el_history.fun = NULL;
+ el->el_history.ref = NULL;
+ el->el_history.buf = el_malloc(EL_BUFSIZ * sizeof(*el->el_history.buf));
+ el->el_history.sz = EL_BUFSIZ;
+ if (el->el_history.buf == NULL)
+ return -1;
+ el->el_history.last = el->el_history.buf;
+ return 0;
+}
+
+
+/* hist_end():
+ * clean up history;
+ */
+libedit_private void
+hist_end(EditLine *el)
+{
+
+ el_free(el->el_history.buf);
+ el->el_history.buf = NULL;
+}
+
+
+/* hist_set():
+ * Set new history interface
+ */
+libedit_private int
+hist_set(EditLine *el, hist_fun_t fun, void *ptr)
+{
+
+ el->el_history.ref = ptr;
+ el->el_history.fun = fun;
+ return 0;
+}
+
+
+/* hist_get():
+ * Get a history line and update it in the buffer.
+ * eventno tells us the event to get.
+ */
+libedit_private el_action_t
+hist_get(EditLine *el)
+{
+ const wchar_t *hp;
+ int h;
+
+ if (el->el_history.eventno == 0) { /* if really the current line */
+ (void) wcsncpy(el->el_line.buffer, el->el_history.buf,
+ el->el_history.sz);
+ el->el_line.lastchar = el->el_line.buffer +
+ (el->el_history.last - el->el_history.buf);
+
+#ifdef KSHVI
+ if (el->el_map.type == MAP_VI)
+ el->el_line.cursor = el->el_line.buffer;
+ else
+#endif /* KSHVI */
+ el->el_line.cursor = el->el_line.lastchar;
+
+ return CC_REFRESH;
+ }
+ if (el->el_history.ref == NULL)
+ return CC_ERROR;
+
+ hp = HIST_FIRST(el);
+
+ if (hp == NULL)
+ return CC_ERROR;
+
+ for (h = 1; h < el->el_history.eventno; h++)
+ if ((hp = HIST_NEXT(el)) == NULL) {
+ el->el_history.eventno = h;
+ return CC_ERROR;
+ }
+ (void) wcsncpy(el->el_line.buffer, hp,
+ (size_t)(el->el_line.limit - el->el_line.buffer));
+ el->el_line.buffer[el->el_line.limit - el->el_line.buffer - 1] = '\0';
+ el->el_line.lastchar = el->el_line.buffer + wcslen(el->el_line.buffer);
+
+ if (el->el_line.lastchar > el->el_line.buffer
+ && el->el_line.lastchar[-1] == '\n')
+ el->el_line.lastchar--;
+ if (el->el_line.lastchar > el->el_line.buffer
+ && el->el_line.lastchar[-1] == ' ')
+ el->el_line.lastchar--;
+#ifdef KSHVI
+ if (el->el_map.type == MAP_VI)
+ el->el_line.cursor = el->el_line.buffer;
+ else
+#endif /* KSHVI */
+ el->el_line.cursor = el->el_line.lastchar;
+
+ return CC_REFRESH;
+}
+
+
+/* hist_command()
+ * process a history command
+ */
+libedit_private int
+hist_command(EditLine *el, int argc, const wchar_t **argv)
+{
+ const wchar_t *str;
+ int num;
+ HistEventW ev;
+
+ if (el->el_history.ref == NULL)
+ return -1;
+
+ if (argc == 1 || wcscmp(argv[1], L"list") == 0) {
+ size_t maxlen = 0;
+ char *buf = NULL;
+ int hno = 1;
+ /* List history entries */
+
+ for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el)) {
+ char *ptr =
+ ct_encode_string(str, &el->el_scratch);
+ size_t len = strlen(ptr);
+ if (len > 0 && ptr[len - 1] == '\n')
+ ptr[--len] = '\0';
+ len = len * 4 + 1;
+ if (len >= maxlen) {
+ maxlen = len + 1024;
+ char *nbuf = el_realloc(buf, maxlen);
+ if (nbuf == NULL) {
+ el_free(buf);
+ return -1;
+ }
+ buf = nbuf;
+ }
+ strvis(buf, ptr, VIS_NL);
+ (void) fprintf(el->el_outfile, "%d\t%s\n",
+ hno++, buf);
+ }
+ el_free(buf);
+ return 0;
+ }
+
+ if (argc != 3)
+ return -1;
+
+ num = (int)wcstol(argv[2], NULL, 0);
+
+ if (wcscmp(argv[1], L"size") == 0)
+ return history_w(el->el_history.ref, &ev, H_SETSIZE, num);
+
+ if (wcscmp(argv[1], L"unique") == 0)
+ return history_w(el->el_history.ref, &ev, H_SETUNIQUE, num);
+
+ return -1;
+}
+
+/* hist_enlargebuf()
+ * Enlarge history buffer to specified value. Called from el_enlargebufs().
+ * Return 0 for failure, 1 for success.
+ */
+libedit_private int
+/*ARGSUSED*/
+hist_enlargebuf(EditLine *el, size_t oldsz, size_t newsz)
+{
+ wchar_t *newbuf;
+
+ newbuf = el_realloc(el->el_history.buf, newsz * sizeof(*newbuf));
+ if (!newbuf)
+ return 0;
+
+ (void) memset(&newbuf[oldsz], '\0', (newsz - oldsz) * sizeof(*newbuf));
+
+ el->el_history.last = newbuf +
+ (el->el_history.last - el->el_history.buf);
+ el->el_history.buf = newbuf;
+ el->el_history.sz = newsz;
+
+ return 1;
+}
+
+libedit_private wchar_t *
+hist_convert(EditLine *el, int fn, void *arg)
+{
+ HistEventW ev;
+ if ((*(el)->el_history.fun)((el)->el_history.ref, &ev, fn, arg) == -1)
+ return NULL;
+ return ct_decode_string((const char *)(const void *)ev.str,
+ &el->el_scratch);
+}
diff --git a/third_party/heimdal/lib/libedit/src/hist.h b/third_party/heimdal/lib/libedit/src/hist.h
new file mode 100644
index 0000000..c58c5bf
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/hist.h
@@ -0,0 +1,79 @@
+/* $NetBSD: hist.h,v 1.22 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)hist.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.hist.c: History functions
+ */
+#ifndef _h_el_hist
+#define _h_el_hist
+
+typedef int (*hist_fun_t)(void *, HistEventW *, int, ...);
+
+typedef struct el_history_t {
+ wchar_t *buf; /* The history buffer */
+ size_t sz; /* Size of history buffer */
+ wchar_t *last; /* The last character */
+ int eventno; /* Event we are looking for */
+ void *ref; /* Argument for history fcns */
+ hist_fun_t fun; /* Event access */
+ HistEventW ev; /* Event cookie */
+} el_history_t;
+
+#define HIST_FUN_INTERNAL(el, fn, arg) \
+ ((((*(el)->el_history.fun) ((el)->el_history.ref, &(el)->el_history.ev, \
+ fn, arg)) == -1) ? NULL : (el)->el_history.ev.str)
+#define HIST_FUN(el, fn, arg) \
+ (((el)->el_flags & NARROW_HISTORY) ? hist_convert(el, fn, arg) : \
+ HIST_FUN_INTERNAL(el, fn, arg))
+
+#define HIST_NEXT(el) HIST_FUN(el, H_NEXT, NULL)
+#define HIST_FIRST(el) HIST_FUN(el, H_FIRST, NULL)
+#define HIST_LAST(el) HIST_FUN(el, H_LAST, NULL)
+#define HIST_PREV(el) HIST_FUN(el, H_PREV, NULL)
+#define HIST_SET(el, num) HIST_FUN(el, H_SET, num)
+#define HIST_LOAD(el, fname) HIST_FUN(el, H_LOAD fname)
+#define HIST_SAVE(el, fname) HIST_FUN(el, H_SAVE fname)
+#define HIST_SAVE_FP(el, fp) HIST_FUN(el, H_SAVE_FP fp)
+
+libedit_private int hist_init(EditLine *);
+libedit_private void hist_end(EditLine *);
+libedit_private el_action_t hist_get(EditLine *);
+libedit_private int hist_set(EditLine *, hist_fun_t, void *);
+libedit_private int hist_command(EditLine *, int, const wchar_t **);
+libedit_private int hist_enlargebuf(EditLine *, size_t, size_t);
+libedit_private wchar_t *hist_convert(EditLine *, int, void *);
+
+#endif /* _h_el_hist */
diff --git a/third_party/heimdal/lib/libedit/src/histedit.h b/third_party/heimdal/lib/libedit/src/histedit.h
new file mode 100644
index 0000000..9ea7189
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/histedit.h
@@ -0,0 +1,313 @@
+/* $NetBSD: histedit.h,v 1.56 2016/04/19 19:50:53 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)histedit.h 8.2 (Berkeley) 1/3/94
+ */
+
+/*
+ * histedit.h: Line editor and history interface.
+ */
+#ifndef _HISTEDIT_H_
+#define _HISTEDIT_H_
+
+#define LIBEDIT_MAJOR 2
+#define LIBEDIT_MINOR 11
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ==== Editing ====
+ */
+
+typedef struct editline EditLine;
+
+/*
+ * For user-defined function interface
+ */
+typedef struct lineinfo {
+ const char *buffer;
+ const char *cursor;
+ const char *lastchar;
+} LineInfo;
+
+/*
+ * EditLine editor function return codes.
+ * For user-defined function interface
+ */
+#define CC_NORM 0
+#define CC_NEWLINE 1
+#define CC_EOF 2
+#define CC_ARGHACK 3
+#define CC_REFRESH 4
+#define CC_CURSOR 5
+#define CC_ERROR 6
+#define CC_FATAL 7
+#define CC_REDISPLAY 8
+#define CC_REFRESH_BEEP 9
+
+/*
+ * Initialization, cleanup, and resetting
+ */
+EditLine *el_init(const char *, FILE *, FILE *, FILE *);
+EditLine *el_init_fd(const char *, FILE *, FILE *, FILE *,
+ int, int, int);
+void el_end(EditLine *);
+void el_reset(EditLine *);
+
+/*
+ * Get a line, a character or push a string back in the input queue
+ */
+const char *el_gets(EditLine *, int *);
+int el_getc(EditLine *, char *);
+void el_push(EditLine *, const char *);
+
+/*
+ * Beep!
+ */
+void el_beep(EditLine *);
+
+/*
+ * High level function internals control
+ * Parses argc, argv array and executes builtin editline commands
+ */
+int el_parse(EditLine *, int, const char **);
+
+/*
+ * Low level editline access functions
+ */
+int el_set(EditLine *, int, ...);
+int el_get(EditLine *, int, ...);
+unsigned char _el_fn_complete(EditLine *, int);
+
+/*
+ * el_set/el_get parameters
+ *
+ * When using el_wset/el_wget (as opposed to el_set/el_get):
+ * Char is wchar_t, otherwise it is char.
+ * prompt_func is el_wpfunc_t, otherwise it is el_pfunc_t .
+
+ * Prompt function prototypes are:
+ * typedef char *(*el_pfunct_t) (EditLine *);
+ * typedef wchar_t *(*el_wpfunct_t) (EditLine *);
+ *
+ * For operations that support set or set/get, the argument types listed are for
+ * the "set" operation. For "get", each listed type must be a pointer.
+ * E.g. EL_EDITMODE takes an int when set, but an int* when get.
+ *
+ * Operations that only support "get" have the correct argument types listed.
+ */
+#define EL_PROMPT 0 /* , prompt_func); set/get */
+#define EL_TERMINAL 1 /* , const char *); set/get */
+#define EL_EDITOR 2 /* , const Char *); set/get */
+#define EL_SIGNAL 3 /* , int); set/get */
+#define EL_BIND 4 /* , const Char *, ..., NULL); set */
+#define EL_TELLTC 5 /* , const Char *, ..., NULL); set */
+#define EL_SETTC 6 /* , const Char *, ..., NULL); set */
+#define EL_ECHOTC 7 /* , const Char *, ..., NULL); set */
+#define EL_SETTY 8 /* , const Char *, ..., NULL); set */
+#define EL_ADDFN 9 /* , const Char *, const Char, set */
+ /* el_func_t); */
+#define EL_HIST 10 /* , hist_fun_t, const void *); set */
+#define EL_EDITMODE 11 /* , int); set/get */
+#define EL_RPROMPT 12 /* , prompt_func); set/get */
+#define EL_GETCFN 13 /* , el_rfunc_t); set/get */
+#define EL_CLIENTDATA 14 /* , void *); set/get */
+#define EL_UNBUFFERED 15 /* , int); set/get */
+#define EL_PREP_TERM 16 /* , int); set */
+#define EL_GETTC 17 /* , const Char *, ..., NULL); get */
+#define EL_GETFP 18 /* , int, FILE **); get */
+#define EL_SETFP 19 /* , int, FILE *); set */
+#define EL_REFRESH 20 /* , void); set */
+#define EL_PROMPT_ESC 21 /* , prompt_func, Char); set/get */
+#define EL_RPROMPT_ESC 22 /* , prompt_func, Char); set/get */
+#define EL_RESIZE 23 /* , el_zfunc_t, void *); set */
+#define EL_ALIAS_TEXT 24 /* , el_afunc_t, void *); set */
+
+#define EL_BUILTIN_GETCFN (NULL)
+
+/*
+ * Source named file or $PWD/.editrc or $HOME/.editrc
+ */
+int el_source(EditLine *, const char *);
+
+/*
+ * Must be called when the terminal changes size; If EL_SIGNAL
+ * is set this is done automatically otherwise it is the responsibility
+ * of the application
+ */
+void el_resize(EditLine *);
+
+/*
+ * User-defined function interface.
+ */
+const LineInfo *el_line(EditLine *);
+int el_insertstr(EditLine *, const char *);
+void el_deletestr(EditLine *, int);
+
+
+/*
+ * ==== History ====
+ */
+
+typedef struct history History;
+
+typedef struct HistEvent {
+ int num;
+ const char *str;
+} HistEvent;
+
+/*
+ * History access functions.
+ */
+History * history_init(void);
+void history_end(History *);
+
+int history(History *, HistEvent *, int, ...);
+
+#define H_FUNC 0 /* , UTSL */
+#define H_SETSIZE 1 /* , const int); */
+#define H_GETSIZE 2 /* , void); */
+#define H_FIRST 3 /* , void); */
+#define H_LAST 4 /* , void); */
+#define H_PREV 5 /* , void); */
+#define H_NEXT 6 /* , void); */
+#define H_CURR 8 /* , const int); */
+#define H_SET 7 /* , int); */
+#define H_ADD 9 /* , const wchar_t *); */
+#define H_ENTER 10 /* , const wchar_t *); */
+#define H_APPEND 11 /* , const wchar_t *); */
+#define H_END 12 /* , void); */
+#define H_NEXT_STR 13 /* , const wchar_t *); */
+#define H_PREV_STR 14 /* , const wchar_t *); */
+#define H_NEXT_EVENT 15 /* , const int); */
+#define H_PREV_EVENT 16 /* , const int); */
+#define H_LOAD 17 /* , const char *); */
+#define H_SAVE 18 /* , const char *); */
+#define H_CLEAR 19 /* , void); */
+#define H_SETUNIQUE 20 /* , int); */
+#define H_GETUNIQUE 21 /* , void); */
+#define H_DEL 22 /* , int); */
+#define H_NEXT_EVDATA 23 /* , const int, histdata_t *); */
+#define H_DELDATA 24 /* , int, histdata_t *);*/
+#define H_REPLACE 25 /* , const char *, histdata_t); */
+#define H_SAVE_FP 26 /* , FILE *); */
+
+
+
+/*
+ * ==== Tokenization ====
+ */
+
+typedef struct tokenizer Tokenizer;
+
+/*
+ * String tokenization functions, using simplified sh(1) quoting rules
+ */
+Tokenizer *tok_init(const char *);
+void tok_end(Tokenizer *);
+void tok_reset(Tokenizer *);
+int tok_line(Tokenizer *, const LineInfo *,
+ int *, const char ***, int *, int *);
+int tok_str(Tokenizer *, const char *,
+ int *, const char ***);
+
+/*
+ * Begin Wide Character Support
+ */
+#include <wchar.h>
+#include <wctype.h>
+
+/*
+ * ==== Editing ====
+ */
+typedef struct lineinfow {
+ const wchar_t *buffer;
+ const wchar_t *cursor;
+ const wchar_t *lastchar;
+} LineInfoW;
+
+typedef int (*el_rfunc_t)(EditLine *, wchar_t *);
+
+const wchar_t *el_wgets(EditLine *, int *);
+int el_wgetc(EditLine *, wchar_t *);
+void el_wpush(EditLine *, const wchar_t *);
+
+int el_wparse(EditLine *, int, const wchar_t **);
+
+int el_wset(EditLine *, int, ...);
+int el_wget(EditLine *, int, ...);
+
+int el_cursor(EditLine *, int);
+const LineInfoW *el_wline(EditLine *);
+int el_winsertstr(EditLine *, const wchar_t *);
+#define el_wdeletestr el_deletestr
+
+/*
+ * ==== History ====
+ */
+typedef struct histeventW {
+ int num;
+ const wchar_t *str;
+} HistEventW;
+
+typedef struct historyW HistoryW;
+
+HistoryW * history_winit(void);
+void history_wend(HistoryW *);
+
+int history_w(HistoryW *, HistEventW *, int, ...);
+
+/*
+ * ==== Tokenization ====
+ */
+typedef struct tokenizerW TokenizerW;
+
+/* Wide character tokenizer support */
+TokenizerW *tok_winit(const wchar_t *);
+void tok_wend(TokenizerW *);
+void tok_wreset(TokenizerW *);
+int tok_wline(TokenizerW *, const LineInfoW *,
+ int *, const wchar_t ***, int *, int *);
+int tok_wstr(TokenizerW *, const wchar_t *,
+ int *, const wchar_t ***);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HISTEDIT_H_ */
diff --git a/third_party/heimdal/lib/libedit/src/history.c b/third_party/heimdal/lib/libedit/src/history.c
new file mode 100644
index 0000000..41d1014
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/history.c
@@ -0,0 +1,1157 @@
+/* $NetBSD: history.c,v 1.57 2016/04/11 18:56:31 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: history.c,v 1.57 2016/04/11 18:56:31 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * hist.c: TYPE(History) access functions
+ */
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vis.h>
+
+static const char hist_cookie[] = "_HiStOrY_V2_\n";
+
+#include "histedit.h"
+
+
+#ifdef NARROWCHAR
+
+#define Char char
+#define FUN(prefix, rest) prefix ## _ ## rest
+#define FUNW(type) type
+#define TYPE(type) type
+#define STR(x) x
+
+#define Strlen(s) strlen(s)
+#define Strdup(s) strdup(s)
+#define Strcmp(d, s) strcmp(d, s)
+#define Strncmp(d, s, n) strncmp(d, s, n)
+#define Strncpy(d, s, n) strncpy(d, s, n)
+#define Strncat(d, s, n) strncat(d, s, n)
+#define ct_decode_string(s, b) (s)
+#define ct_encode_string(s, b) (s)
+
+#else
+#include "chartype.h"
+
+#define Char wchar_t
+#define FUN(prefix, rest) prefix ## _w ## rest
+#define FUNW(type) type ## _w
+#define TYPE(type) type ## W
+#define STR(x) L ## x
+
+#define Strlen(s) wcslen(s)
+#define Strdup(s) wcsdup(s)
+#define Strcmp(d, s) wcscmp(d, s)
+#define Strncmp(d, s, n) wcsncmp(d, s, n)
+#define Strncpy(d, s, n) wcsncpy(d, s, n)
+#define Strncat(d, s, n) wcsncat(d, s, n)
+
+#endif
+
+
+typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
+typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
+typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
+typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
+
+struct TYPE(history) {
+ void *h_ref; /* Argument for history fcns */
+ int h_ent; /* Last entry point for history */
+ history_gfun_t h_first; /* Get the first element */
+ history_gfun_t h_next; /* Get the next element */
+ history_gfun_t h_last; /* Get the last element */
+ history_gfun_t h_prev; /* Get the previous element */
+ history_gfun_t h_curr; /* Get the current element */
+ history_sfun_t h_set; /* Set the current element */
+ history_sfun_t h_del; /* Set the given element */
+ history_vfun_t h_clear; /* Clear the history list */
+ history_efun_t h_enter; /* Add an element */
+ history_efun_t h_add; /* Append to an element */
+};
+
+#define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
+#define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
+#define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
+#define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
+#define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
+#define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
+#define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
+#define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
+#define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
+#define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
+
+#define h_strdup(a) Strdup(a)
+#define h_malloc(a) malloc(a)
+#define h_realloc(a, b) realloc((a), (b))
+#define h_free(a) free(a)
+
+typedef struct {
+ int num;
+ Char *str;
+} HistEventPrivate;
+
+
+static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
+static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
+static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
+static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
+static int history_set_fun(TYPE(History) *, TYPE(History) *);
+static int history_load(TYPE(History) *, const char *);
+static int history_save(TYPE(History) *, const char *);
+static int history_save_fp(TYPE(History) *, FILE *);
+static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
+static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
+static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
+ const Char *);
+static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
+ const Char *);
+
+
+/***********************************************************************/
+
+/*
+ * Builtin- history implementation
+ */
+typedef struct hentry_t {
+ TYPE(HistEvent) ev; /* What we return */
+ void *data; /* data */
+ struct hentry_t *next; /* Next entry */
+ struct hentry_t *prev; /* Previous entry */
+} hentry_t;
+
+typedef struct history_t {
+ hentry_t list; /* Fake list header element */
+ hentry_t *cursor; /* Current element in the list */
+ int max; /* Maximum number of events */
+ int cur; /* Current number of events */
+ int eventid; /* For generation of unique event id */
+ int flags; /* TYPE(History) flags */
+#define H_UNIQUE 1 /* Store only unique elements */
+} history_t;
+
+static int history_def_next(void *, TYPE(HistEvent) *);
+static int history_def_first(void *, TYPE(HistEvent) *);
+static int history_def_prev(void *, TYPE(HistEvent) *);
+static int history_def_last(void *, TYPE(HistEvent) *);
+static int history_def_curr(void *, TYPE(HistEvent) *);
+static int history_def_set(void *, TYPE(HistEvent) *, const int);
+static void history_def_clear(void *, TYPE(HistEvent) *);
+static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
+static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
+static int history_def_del(void *, TYPE(HistEvent) *, const int);
+
+static int history_def_init(void **, TYPE(HistEvent) *, int);
+static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
+static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
+
+static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
+static int history_set_nth(void *, TYPE(HistEvent) *, int);
+
+#define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
+#define history_def_getsize(p) (((history_t *)p)->cur)
+#define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
+#define history_def_setunique(p, uni) \
+ if (uni) \
+ (((history_t *)p)->flags) |= H_UNIQUE; \
+ else \
+ (((history_t *)p)->flags) &= ~H_UNIQUE
+
+#define he_strerror(code) he_errlist[code]
+#define he_seterrev(evp, code) {\
+ evp->num = code;\
+ evp->str = he_strerror(code);\
+ }
+
+/* error messages */
+static const Char *const he_errlist[] = {
+ STR("OK"),
+ STR("unknown error"),
+ STR("malloc() failed"),
+ STR("first event not found"),
+ STR("last event not found"),
+ STR("empty list"),
+ STR("no next event"),
+ STR("no previous event"),
+ STR("current event is invalid"),
+ STR("event not found"),
+ STR("can't read history from file"),
+ STR("can't write history"),
+ STR("required parameter(s) not supplied"),
+ STR("history size negative"),
+ STR("function not allowed with other history-functions-set the default"),
+ STR("bad parameters")
+};
+/* error codes */
+#define _HE_OK 0
+#define _HE_UNKNOWN 1
+#define _HE_MALLOC_FAILED 2
+#define _HE_FIRST_NOTFOUND 3
+#define _HE_LAST_NOTFOUND 4
+#define _HE_EMPTY_LIST 5
+#define _HE_END_REACHED 6
+#define _HE_START_REACHED 7
+#define _HE_CURR_INVALID 8
+#define _HE_NOT_FOUND 9
+#define _HE_HIST_READ 10
+#define _HE_HIST_WRITE 11
+#define _HE_PARAM_MISSING 12
+#define _HE_SIZE_NEGATIVE 13
+#define _HE_NOT_ALLOWED 14
+#define _HE_BAD_PARAM 15
+
+/* history_def_first():
+ * Default function to return the first event in the history.
+ */
+static int
+history_def_first(void *p, TYPE(HistEvent) *ev)
+{
+ history_t *h = (history_t *) p;
+
+ h->cursor = h->list.next;
+ if (h->cursor != &h->list)
+ *ev = h->cursor->ev;
+ else {
+ he_seterrev(ev, _HE_FIRST_NOTFOUND);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* history_def_last():
+ * Default function to return the last event in the history.
+ */
+static int
+history_def_last(void *p, TYPE(HistEvent) *ev)
+{
+ history_t *h = (history_t *) p;
+
+ h->cursor = h->list.prev;
+ if (h->cursor != &h->list)
+ *ev = h->cursor->ev;
+ else {
+ he_seterrev(ev, _HE_LAST_NOTFOUND);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* history_def_next():
+ * Default function to return the next event in the history.
+ */
+static int
+history_def_next(void *p, TYPE(HistEvent) *ev)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cursor == &h->list) {
+ he_seterrev(ev, _HE_EMPTY_LIST);
+ return -1;
+ }
+
+ if (h->cursor->next == &h->list) {
+ he_seterrev(ev, _HE_END_REACHED);
+ return -1;
+ }
+
+ h->cursor = h->cursor->next;
+ *ev = h->cursor->ev;
+
+ return 0;
+}
+
+
+/* history_def_prev():
+ * Default function to return the previous event in the history.
+ */
+static int
+history_def_prev(void *p, TYPE(HistEvent) *ev)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cursor == &h->list) {
+ he_seterrev(ev,
+ (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
+ return -1;
+ }
+
+ if (h->cursor->prev == &h->list) {
+ he_seterrev(ev, _HE_START_REACHED);
+ return -1;
+ }
+
+ h->cursor = h->cursor->prev;
+ *ev = h->cursor->ev;
+
+ return 0;
+}
+
+
+/* history_def_curr():
+ * Default function to return the current event in the history.
+ */
+static int
+history_def_curr(void *p, TYPE(HistEvent) *ev)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cursor != &h->list)
+ *ev = h->cursor->ev;
+ else {
+ he_seterrev(ev,
+ (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* history_def_set():
+ * Default function to set the current event in the history to the
+ * given one.
+ */
+static int
+history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cur == 0) {
+ he_seterrev(ev, _HE_EMPTY_LIST);
+ return -1;
+ }
+ if (h->cursor == &h->list || h->cursor->ev.num != n) {
+ for (h->cursor = h->list.next; h->cursor != &h->list;
+ h->cursor = h->cursor->next)
+ if (h->cursor->ev.num == n)
+ break;
+ }
+ if (h->cursor == &h->list) {
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return -1;
+ }
+ return 0;
+}
+
+
+/* history_set_nth():
+ * Default function to set the current event in the history to the
+ * n-th one.
+ */
+static int
+history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cur == 0) {
+ he_seterrev(ev, _HE_EMPTY_LIST);
+ return -1;
+ }
+ for (h->cursor = h->list.prev; h->cursor != &h->list;
+ h->cursor = h->cursor->prev)
+ if (n-- <= 0)
+ break;
+ if (h->cursor == &h->list) {
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return -1;
+ }
+ return 0;
+}
+
+
+/* history_def_add():
+ * Append string to element
+ */
+static int
+history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
+{
+ history_t *h = (history_t *) p;
+ size_t len;
+ Char *s;
+ HistEventPrivate *evp = (void *)&h->cursor->ev;
+
+ if (h->cursor == &h->list)
+ return history_def_enter(p, ev, str);
+ len = Strlen(evp->str) + Strlen(str) + 1;
+ s = h_malloc(len * sizeof(*s));
+ if (s == NULL) {
+ he_seterrev(ev, _HE_MALLOC_FAILED);
+ return -1;
+ }
+ (void) Strncpy(s, h->cursor->ev.str, len);
+ s[len - 1] = '\0';
+ (void) Strncat(s, str, len - Strlen(s) - 1);
+ h_free(evp->str);
+ evp->str = s;
+ *ev = h->cursor->ev;
+ return 0;
+}
+
+
+static int
+history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
+ int num, void **data)
+{
+ if (history_set_nth(h, ev, num) != 0)
+ return -1;
+ /* magic value to skip delete (just set to n-th history) */
+ if (data == (void **)-1)
+ return 0;
+ ev->str = Strdup(h->cursor->ev.str);
+ ev->num = h->cursor->ev.num;
+ if (data)
+ *data = h->cursor->data;
+ history_def_delete(h, ev, h->cursor);
+ return 0;
+}
+
+
+/* history_def_del():
+ * Delete element hp of the h list
+ */
+/* ARGSUSED */
+static int
+history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
+ const int num)
+{
+ history_t *h = (history_t *) p;
+ if (history_def_set(h, ev, num) != 0)
+ return -1;
+ ev->str = Strdup(h->cursor->ev.str);
+ ev->num = h->cursor->ev.num;
+ history_def_delete(h, ev, h->cursor);
+ return 0;
+}
+
+
+/* history_def_delete():
+ * Delete element hp of the h list
+ */
+/* ARGSUSED */
+static void
+history_def_delete(history_t *h,
+ TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
+{
+ HistEventPrivate *evp = (void *)&hp->ev;
+ if (hp == &h->list)
+ abort();
+ if (h->cursor == hp) {
+ h->cursor = hp->prev;
+ if (h->cursor == &h->list)
+ h->cursor = hp->next;
+ }
+ hp->prev->next = hp->next;
+ hp->next->prev = hp->prev;
+ h_free(evp->str);
+ h_free(hp);
+ h->cur--;
+}
+
+
+/* history_def_insert():
+ * Insert element with string str in the h list
+ */
+static int
+history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
+{
+ hentry_t *c;
+
+ c = h_malloc(sizeof(*c));
+ if (c == NULL)
+ goto oomem;
+ if ((c->ev.str = h_strdup(str)) == NULL) {
+ h_free(c);
+ goto oomem;
+ }
+ c->data = NULL;
+ c->ev.num = ++h->eventid;
+ c->next = h->list.next;
+ c->prev = &h->list;
+ h->list.next->prev = c;
+ h->list.next = c;
+ h->cur++;
+ h->cursor = c;
+
+ *ev = c->ev;
+ return 0;
+oomem:
+ he_seterrev(ev, _HE_MALLOC_FAILED);
+ return -1;
+}
+
+
+/* history_def_enter():
+ * Default function to enter an item in the history
+ */
+static int
+history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
+{
+ history_t *h = (history_t *) p;
+
+ if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
+ Strcmp(h->list.next->ev.str, str) == 0)
+ return 0;
+
+ if (history_def_insert(h, ev, str) == -1)
+ return -1; /* error, keep error message */
+
+ /*
+ * Always keep at least one entry.
+ * This way we don't have to check for the empty list.
+ */
+ while (h->cur > h->max && h->cur > 0)
+ history_def_delete(h, ev, h->list.prev);
+
+ return 1;
+}
+
+
+/* history_def_init():
+ * Default history initialization function
+ */
+/* ARGSUSED */
+static int
+history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
+{
+ history_t *h = (history_t *) h_malloc(sizeof(*h));
+ if (h == NULL)
+ return -1;
+
+ if (n <= 0)
+ n = 0;
+ h->eventid = 0;
+ h->cur = 0;
+ h->max = n;
+ h->list.next = h->list.prev = &h->list;
+ h->list.ev.str = NULL;
+ h->list.ev.num = 0;
+ h->cursor = &h->list;
+ h->flags = 0;
+ *p = h;
+ return 0;
+}
+
+
+/* history_def_clear():
+ * Default history cleanup function
+ */
+static void
+history_def_clear(void *p, TYPE(HistEvent) *ev)
+{
+ history_t *h = (history_t *) p;
+
+ while (h->list.prev != &h->list)
+ history_def_delete(h, ev, h->list.prev);
+ h->cursor = &h->list;
+ h->eventid = 0;
+ h->cur = 0;
+}
+
+
+
+
+/************************************************************************/
+
+/* history_init():
+ * Initialization function.
+ */
+TYPE(History) *
+FUN(history,init)(void)
+{
+ TYPE(HistEvent) ev;
+ TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
+ if (h == NULL)
+ return NULL;
+
+ if (history_def_init(&h->h_ref, &ev, 0) == -1) {
+ h_free(h);
+ return NULL;
+ }
+ h->h_ent = -1;
+ h->h_next = history_def_next;
+ h->h_first = history_def_first;
+ h->h_last = history_def_last;
+ h->h_prev = history_def_prev;
+ h->h_curr = history_def_curr;
+ h->h_set = history_def_set;
+ h->h_clear = history_def_clear;
+ h->h_enter = history_def_enter;
+ h->h_add = history_def_add;
+ h->h_del = history_def_del;
+
+ return h;
+}
+
+
+/* history_end():
+ * clean up history;
+ */
+void
+FUN(history,end)(TYPE(History) *h)
+{
+ TYPE(HistEvent) ev;
+
+ if (h->h_next == history_def_next)
+ history_def_clear(h->h_ref, &ev);
+ h_free(h->h_ref);
+ h_free(h);
+}
+
+
+
+/* history_setsize():
+ * Set history number of events
+ */
+static int
+history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
+{
+
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return -1;
+ }
+ if (num < 0) {
+ he_seterrev(ev, _HE_BAD_PARAM);
+ return -1;
+ }
+ history_def_setsize(h->h_ref, num);
+ return 0;
+}
+
+
+/* history_getsize():
+ * Get number of events currently in history
+ */
+static int
+history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
+{
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return -1;
+ }
+ ev->num = history_def_getsize(h->h_ref);
+ if (ev->num < -1) {
+ he_seterrev(ev, _HE_SIZE_NEGATIVE);
+ return -1;
+ }
+ return 0;
+}
+
+
+/* history_setunique():
+ * Set if adjacent equal events should not be entered in history.
+ */
+static int
+history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
+{
+
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return -1;
+ }
+ history_def_setunique(h->h_ref, uni);
+ return 0;
+}
+
+
+/* history_getunique():
+ * Get if adjacent equal events should not be entered in history.
+ */
+static int
+history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
+{
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return -1;
+ }
+ ev->num = history_def_getunique(h->h_ref);
+ return 0;
+}
+
+
+/* history_set_fun():
+ * Set history functions
+ */
+static int
+history_set_fun(TYPE(History) *h, TYPE(History) *nh)
+{
+ TYPE(HistEvent) ev;
+
+ if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
+ nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
+ nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
+ nh->h_del == NULL || nh->h_ref == NULL) {
+ if (h->h_next != history_def_next) {
+ if (history_def_init(&h->h_ref, &ev, 0) == -1)
+ return -1;
+ h->h_first = history_def_first;
+ h->h_next = history_def_next;
+ h->h_last = history_def_last;
+ h->h_prev = history_def_prev;
+ h->h_curr = history_def_curr;
+ h->h_set = history_def_set;
+ h->h_clear = history_def_clear;
+ h->h_enter = history_def_enter;
+ h->h_add = history_def_add;
+ h->h_del = history_def_del;
+ }
+ return -1;
+ }
+ if (h->h_next == history_def_next)
+ history_def_clear(h->h_ref, &ev);
+
+ h->h_ent = -1;
+ h->h_first = nh->h_first;
+ h->h_next = nh->h_next;
+ h->h_last = nh->h_last;
+ h->h_prev = nh->h_prev;
+ h->h_curr = nh->h_curr;
+ h->h_set = nh->h_set;
+ h->h_clear = nh->h_clear;
+ h->h_enter = nh->h_enter;
+ h->h_add = nh->h_add;
+ h->h_del = nh->h_del;
+
+ return 0;
+}
+
+
+/* history_load():
+ * TYPE(History) load function
+ */
+static int
+history_load(TYPE(History) *h, const char *fname)
+{
+ FILE *fp;
+ char *line;
+ size_t llen;
+ ssize_t sz;
+ size_t max_size;
+ char *ptr;
+ int i = -1;
+ TYPE(HistEvent) ev;
+#ifndef NARROWCHAR
+ static ct_buffer_t conv;
+#endif
+
+ if ((fp = fopen(fname, "r")) == NULL)
+ return i;
+
+ line = NULL;
+ llen = 0;
+ if ((sz = getline(&line, &llen, fp)) == -1)
+ goto done;
+
+ if (strncmp(line, hist_cookie, (size_t)sz) != 0)
+ goto done;
+
+ ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
+ if (ptr == NULL)
+ goto done;
+ for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
+ if (sz > 0 && line[sz - 1] == '\n')
+ line[--sz] = '\0';
+ if (max_size < (size_t)sz) {
+ char *nptr;
+ max_size = ((size_t)sz + 1024) & (size_t)~1023;
+ nptr = h_realloc(ptr, max_size * sizeof(*ptr));
+ if (nptr == NULL) {
+ i = -1;
+ goto oomem;
+ }
+ ptr = nptr;
+ }
+ (void) strunvis(ptr, line);
+ if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) {
+ i = -1;
+ goto oomem;
+ }
+ }
+oomem:
+ h_free(ptr);
+done:
+ free(line);
+ (void) fclose(fp);
+ return i;
+}
+
+
+/* history_save_fp():
+ * TYPE(History) save function
+ */
+static int
+history_save_fp(TYPE(History) *h, FILE *fp)
+{
+ TYPE(HistEvent) ev;
+ int i = -1, retval;
+ size_t len, max_size;
+ char *ptr;
+ const char *str;
+#ifndef NARROWCHAR
+ static ct_buffer_t conv;
+#endif
+
+ if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
+ goto done;
+ if (fputs(hist_cookie, fp) == EOF)
+ goto done;
+ ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
+ if (ptr == NULL)
+ goto done;
+ for (i = 0, retval = HLAST(h, &ev);
+ retval != -1;
+ retval = HPREV(h, &ev), i++) {
+ str = ct_encode_string(ev.str, &conv);
+ len = strlen(str) * 4 + 1;
+ if (len > max_size) {
+ char *nptr;
+ max_size = (len + 1024) & (size_t)~1023;
+ nptr = h_realloc(ptr, max_size * sizeof(*ptr));
+ if (nptr == NULL) {
+ i = -1;
+ goto oomem;
+ }
+ ptr = nptr;
+ }
+ (void) strvis(ptr, str, VIS_WHITE);
+ (void) fprintf(fp, "%s\n", ptr);
+ }
+oomem:
+ h_free(ptr);
+done:
+ return i;
+}
+
+
+/* history_save():
+ * History save function
+ */
+static int
+history_save(TYPE(History) *h, const char *fname)
+{
+ FILE *fp;
+ int i;
+
+ if ((fp = fopen(fname, "w")) == NULL)
+ return -1;
+
+ i = history_save_fp(h, fp);
+
+ (void) fclose(fp);
+ return i;
+}
+
+
+/* history_prev_event():
+ * Find the previous event, with number given
+ */
+static int
+history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
+{
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
+ if (ev->num == num)
+ return 0;
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return -1;
+}
+
+
+static int
+history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
+{
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
+ if (ev->num == num) {
+ if (d)
+ *d = ((history_t *)h->h_ref)->cursor->data;
+ return 0;
+ }
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return -1;
+}
+
+
+/* history_next_event():
+ * Find the next event, with number given
+ */
+static int
+history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
+{
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
+ if (ev->num == num)
+ return 0;
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return -1;
+}
+
+
+/* history_prev_string():
+ * Find the previous event beginning with string
+ */
+static int
+history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
+{
+ size_t len = Strlen(str);
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
+ if (Strncmp(str, ev->str, len) == 0)
+ return 0;
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return -1;
+}
+
+
+/* history_next_string():
+ * Find the next event beginning with string
+ */
+static int
+history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
+{
+ size_t len = Strlen(str);
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
+ if (Strncmp(str, ev->str, len) == 0)
+ return 0;
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return -1;
+}
+
+
+/* history():
+ * User interface to history functions.
+ */
+int
+FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
+{
+ va_list va;
+ const Char *str;
+ int retval;
+
+ va_start(va, fun);
+
+ he_seterrev(ev, _HE_OK);
+
+ switch (fun) {
+ case H_GETSIZE:
+ retval = history_getsize(h, ev);
+ break;
+
+ case H_SETSIZE:
+ retval = history_setsize(h, ev, va_arg(va, int));
+ break;
+
+ case H_GETUNIQUE:
+ retval = history_getunique(h, ev);
+ break;
+
+ case H_SETUNIQUE:
+ retval = history_setunique(h, ev, va_arg(va, int));
+ break;
+
+ case H_ADD:
+ str = va_arg(va, const Char *);
+ retval = HADD(h, ev, str);
+ break;
+
+ case H_DEL:
+ retval = HDEL(h, ev, va_arg(va, const int));
+ break;
+
+ case H_ENTER:
+ str = va_arg(va, const Char *);
+ if ((retval = HENTER(h, ev, str)) != -1)
+ h->h_ent = ev->num;
+ break;
+
+ case H_APPEND:
+ str = va_arg(va, const Char *);
+ if ((retval = HSET(h, ev, h->h_ent)) != -1)
+ retval = HADD(h, ev, str);
+ break;
+
+ case H_FIRST:
+ retval = HFIRST(h, ev);
+ break;
+
+ case H_NEXT:
+ retval = HNEXT(h, ev);
+ break;
+
+ case H_LAST:
+ retval = HLAST(h, ev);
+ break;
+
+ case H_PREV:
+ retval = HPREV(h, ev);
+ break;
+
+ case H_CURR:
+ retval = HCURR(h, ev);
+ break;
+
+ case H_SET:
+ retval = HSET(h, ev, va_arg(va, const int));
+ break;
+
+ case H_CLEAR:
+ HCLEAR(h, ev);
+ retval = 0;
+ break;
+
+ case H_LOAD:
+ retval = history_load(h, va_arg(va, const char *));
+ if (retval == -1)
+ he_seterrev(ev, _HE_HIST_READ);
+ break;
+
+ case H_SAVE:
+ retval = history_save(h, va_arg(va, const char *));
+ if (retval == -1)
+ he_seterrev(ev, _HE_HIST_WRITE);
+ break;
+
+ case H_SAVE_FP:
+ retval = history_save_fp(h, va_arg(va, FILE *));
+ if (retval == -1)
+ he_seterrev(ev, _HE_HIST_WRITE);
+ break;
+
+ case H_PREV_EVENT:
+ retval = history_prev_event(h, ev, va_arg(va, int));
+ break;
+
+ case H_NEXT_EVENT:
+ retval = history_next_event(h, ev, va_arg(va, int));
+ break;
+
+ case H_PREV_STR:
+ retval = history_prev_string(h, ev, va_arg(va, const Char *));
+ break;
+
+ case H_NEXT_STR:
+ retval = history_next_string(h, ev, va_arg(va, const Char *));
+ break;
+
+ case H_FUNC:
+ {
+ TYPE(History) hf;
+
+ hf.h_ref = va_arg(va, void *);
+ h->h_ent = -1;
+ hf.h_first = va_arg(va, history_gfun_t);
+ hf.h_next = va_arg(va, history_gfun_t);
+ hf.h_last = va_arg(va, history_gfun_t);
+ hf.h_prev = va_arg(va, history_gfun_t);
+ hf.h_curr = va_arg(va, history_gfun_t);
+ hf.h_set = va_arg(va, history_sfun_t);
+ hf.h_clear = va_arg(va, history_vfun_t);
+ hf.h_enter = va_arg(va, history_efun_t);
+ hf.h_add = va_arg(va, history_efun_t);
+ hf.h_del = va_arg(va, history_sfun_t);
+
+ if ((retval = history_set_fun(h, &hf)) == -1)
+ he_seterrev(ev, _HE_PARAM_MISSING);
+ break;
+ }
+
+ case H_END:
+ FUN(history,end)(h);
+ retval = 0;
+ break;
+
+ case H_NEXT_EVDATA:
+ {
+ int num = va_arg(va, int);
+ void **d = va_arg(va, void **);
+ retval = history_next_evdata(h, ev, num, d);
+ break;
+ }
+
+ case H_DELDATA:
+ {
+ int num = va_arg(va, int);
+ void **d = va_arg(va, void **);
+ retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
+ break;
+ }
+
+ case H_REPLACE: /* only use after H_NEXT_EVDATA */
+ {
+ const Char *line = va_arg(va, const Char *);
+ void *d = va_arg(va, void *);
+ const Char *s;
+ if(!line || !(s = Strdup(line))) {
+ retval = -1;
+ break;
+ }
+ ((history_t *)h->h_ref)->cursor->ev.str = s;
+ ((history_t *)h->h_ref)->cursor->data = d;
+ retval = 0;
+ break;
+ }
+
+ default:
+ retval = -1;
+ he_seterrev(ev, _HE_UNKNOWN);
+ break;
+ }
+ va_end(va);
+ return retval;
+}
diff --git a/third_party/heimdal/lib/libedit/src/historyn.c b/third_party/heimdal/lib/libedit/src/historyn.c
new file mode 100644
index 0000000..59130de
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/historyn.c
@@ -0,0 +1,3 @@
+#include "config.h"
+#define NARROWCHAR
+#include "history.c"
diff --git a/third_party/heimdal/lib/libedit/src/keymacro.c b/third_party/heimdal/lib/libedit/src/keymacro.c
new file mode 100644
index 0000000..13d2089
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/keymacro.c
@@ -0,0 +1,669 @@
+/* $NetBSD: keymacro.c,v 1.23 2016/05/24 15:00:45 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: keymacro.c,v 1.23 2016/05/24 15:00:45 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * keymacro.c: This module contains the procedures for maintaining
+ * the extended-key map.
+ *
+ * An extended-key (key) is a sequence of keystrokes introduced
+ * with a sequence introducer and consisting of an arbitrary
+ * number of characters. This module maintains a map (the
+ * el->el_keymacro.map)
+ * to convert these extended-key sequences into input strs
+ * (XK_STR) or editor functions (XK_CMD).
+ *
+ * Warning:
+ * If key is a substr of some other keys, then the longer
+ * keys are lost!! That is, if the keys "abcd" and "abcef"
+ * are in el->el_keymacro.map, adding the key "abc" will cause
+ * the first two definitions to be lost.
+ *
+ * Restrictions:
+ * -------------
+ * 1) It is not possible to have one key that is a
+ * substr of another.
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "el.h"
+#include "fcns.h"
+
+/*
+ * The Nodes of the el->el_keymacro.map. The el->el_keymacro.map is a
+ * linked list of these node elements
+ */
+struct keymacro_node_t {
+ wchar_t ch; /* single character of key */
+ int type; /* node type */
+ keymacro_value_t val; /* command code or pointer to str, */
+ /* if this is a leaf */
+ struct keymacro_node_t *next; /* ptr to next char of this key */
+ struct keymacro_node_t *sibling;/* ptr to another key with same prefix*/
+};
+
+static int node_trav(EditLine *, keymacro_node_t *, wchar_t *,
+ keymacro_value_t *);
+static int node__try(EditLine *, keymacro_node_t *,
+ const wchar_t *, keymacro_value_t *, int);
+static keymacro_node_t *node__get(wint_t);
+static void node__free(keymacro_node_t *);
+static void node__put(EditLine *, keymacro_node_t *);
+static int node__delete(EditLine *, keymacro_node_t **,
+ const wchar_t *);
+static int node_lookup(EditLine *, const wchar_t *,
+ keymacro_node_t *, size_t);
+static int node_enum(EditLine *, keymacro_node_t *, size_t);
+
+#define KEY_BUFSIZ EL_BUFSIZ
+
+
+/* keymacro_init():
+ * Initialize the key maps
+ */
+libedit_private int
+keymacro_init(EditLine *el)
+{
+
+ el->el_keymacro.buf = el_malloc(KEY_BUFSIZ *
+ sizeof(*el->el_keymacro.buf));
+ if (el->el_keymacro.buf == NULL)
+ return -1;
+ el->el_keymacro.map = NULL;
+ keymacro_reset(el);
+ return 0;
+}
+
+/* keymacro_end():
+ * Free the key maps
+ */
+libedit_private void
+keymacro_end(EditLine *el)
+{
+
+ el_free(el->el_keymacro.buf);
+ el->el_keymacro.buf = NULL;
+ node__free(el->el_keymacro.map);
+}
+
+
+/* keymacro_map_cmd():
+ * Associate cmd with a key value
+ */
+libedit_private keymacro_value_t *
+keymacro_map_cmd(EditLine *el, int cmd)
+{
+
+ el->el_keymacro.val.cmd = (el_action_t) cmd;
+ return &el->el_keymacro.val;
+}
+
+
+/* keymacro_map_str():
+ * Associate str with a key value
+ */
+libedit_private keymacro_value_t *
+keymacro_map_str(EditLine *el, wchar_t *str)
+{
+
+ el->el_keymacro.val.str = str;
+ return &el->el_keymacro.val;
+}
+
+
+/* keymacro_reset():
+ * Takes all nodes on el->el_keymacro.map and puts them on free list.
+ * Then initializes el->el_keymacro.map with arrow keys
+ * [Always bind the ansi arrow keys?]
+ */
+libedit_private void
+keymacro_reset(EditLine *el)
+{
+
+ node__put(el, el->el_keymacro.map);
+ el->el_keymacro.map = NULL;
+ return;
+}
+
+
+/* keymacro_get():
+ * Calls the recursive function with entry point el->el_keymacro.map
+ * Looks up *ch in map and then reads characters until a
+ * complete match is found or a mismatch occurs. Returns the
+ * type of the match found (XK_STR or XK_CMD).
+ * Returns NULL in val.str and XK_STR for no match.
+ * Returns XK_NOD for end of file or read error.
+ * The last character read is returned in *ch.
+ */
+libedit_private int
+keymacro_get(EditLine *el, wchar_t *ch, keymacro_value_t *val)
+{
+
+ return node_trav(el, el->el_keymacro.map, ch, val);
+}
+
+
+/* keymacro_add():
+ * Adds key to the el->el_keymacro.map and associates the value in
+ * val with it. If key is already is in el->el_keymacro.map, the new
+ * code is applied to the existing key. Ntype specifies if code is a
+ * command, an out str or a unix command.
+ */
+libedit_private void
+keymacro_add(EditLine *el, const wchar_t *key, keymacro_value_t *val,
+ int ntype)
+{
+
+ if (key[0] == '\0') {
+ (void) fprintf(el->el_errfile,
+ "keymacro_add: Null extended-key not allowed.\n");
+ return;
+ }
+ if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
+ (void) fprintf(el->el_errfile,
+ "keymacro_add: sequence-lead-in command not allowed\n");
+ return;
+ }
+ if (el->el_keymacro.map == NULL)
+ /* tree is initially empty. Set up new node to match key[0] */
+ el->el_keymacro.map = node__get(key[0]);
+ /* it is properly initialized */
+
+ /* Now recurse through el->el_keymacro.map */
+ (void) node__try(el, el->el_keymacro.map, key, val, ntype);
+ return;
+}
+
+
+/* keymacro_clear():
+ *
+ */
+libedit_private void
+keymacro_clear(EditLine *el, el_action_t *map, const wchar_t *in)
+{
+ if (*in > N_KEYS) /* can't be in the map */
+ return;
+ if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) &&
+ ((map == el->el_map.key &&
+ el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) ||
+ (map == el->el_map.alt &&
+ el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN)))
+ (void) keymacro_delete(el, in);
+}
+
+
+/* keymacro_delete():
+ * Delete the key and all longer keys staring with key, if
+ * they exists.
+ */
+libedit_private int
+keymacro_delete(EditLine *el, const wchar_t *key)
+{
+
+ if (key[0] == '\0') {
+ (void) fprintf(el->el_errfile,
+ "keymacro_delete: Null extended-key not allowed.\n");
+ return -1;
+ }
+ if (el->el_keymacro.map == NULL)
+ return 0;
+
+ (void) node__delete(el, &el->el_keymacro.map, key);
+ return 0;
+}
+
+
+/* keymacro_print():
+ * Print the binding associated with key key.
+ * Print entire el->el_keymacro.map if null
+ */
+libedit_private void
+keymacro_print(EditLine *el, const wchar_t *key)
+{
+
+ /* do nothing if el->el_keymacro.map is empty and null key specified */
+ if (el->el_keymacro.map == NULL && *key == 0)
+ return;
+
+ el->el_keymacro.buf[0] = '"';
+ if (node_lookup(el, key, el->el_keymacro.map, (size_t)1) <= -1)
+ /* key is not bound */
+ (void) fprintf(el->el_errfile, "Unbound extended key \"%ls"
+ "\"\n", key);
+ return;
+}
+
+
+/* node_trav():
+ * recursively traverses node in tree until match or mismatch is
+ * found. May read in more characters.
+ */
+static int
+node_trav(EditLine *el, keymacro_node_t *ptr, wchar_t *ch,
+ keymacro_value_t *val)
+{
+
+ if (ptr->ch == *ch) {
+ /* match found */
+ if (ptr->next) {
+ /* key not complete so get next char */
+ if (el_wgetc(el, ch) != 1)
+ return XK_NOD;
+ return node_trav(el, ptr->next, ch, val);
+ } else {
+ *val = ptr->val;
+ if (ptr->type != XK_CMD)
+ *ch = '\0';
+ return ptr->type;
+ }
+ } else {
+ /* no match found here */
+ if (ptr->sibling) {
+ /* try next sibling */
+ return node_trav(el, ptr->sibling, ch, val);
+ } else {
+ /* no next sibling -- mismatch */
+ val->str = NULL;
+ return XK_STR;
+ }
+ }
+}
+
+
+/* node__try():
+ * Find a node that matches *str or allocate a new one
+ */
+static int
+node__try(EditLine *el, keymacro_node_t *ptr, const wchar_t *str,
+ keymacro_value_t *val, int ntype)
+{
+
+ if (ptr->ch != *str) {
+ keymacro_node_t *xm;
+
+ for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
+ if (xm->sibling->ch == *str)
+ break;
+ if (xm->sibling == NULL)
+ xm->sibling = node__get(*str); /* setup new node */
+ ptr = xm->sibling;
+ }
+ if (*++str == '\0') {
+ /* we're there */
+ if (ptr->next != NULL) {
+ node__put(el, ptr->next);
+ /* lose longer keys with this prefix */
+ ptr->next = NULL;
+ }
+ switch (ptr->type) {
+ case XK_CMD:
+ case XK_NOD:
+ break;
+ case XK_STR:
+ if (ptr->val.str)
+ el_free(ptr->val.str);
+ break;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n",
+ ptr->type));
+ break;
+ }
+
+ switch (ptr->type = ntype) {
+ case XK_CMD:
+ ptr->val = *val;
+ break;
+ case XK_STR:
+ if ((ptr->val.str = wcsdup(val->str)) == NULL)
+ return -1;
+ break;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
+ break;
+ }
+ } else {
+ /* still more chars to go */
+ if (ptr->next == NULL)
+ ptr->next = node__get(*str); /* setup new node */
+ (void) node__try(el, ptr->next, str, val, ntype);
+ }
+ return 0;
+}
+
+
+/* node__delete():
+ * Delete node that matches str
+ */
+static int
+node__delete(EditLine *el, keymacro_node_t **inptr, const wchar_t *str)
+{
+ keymacro_node_t *ptr;
+ keymacro_node_t *prev_ptr = NULL;
+
+ ptr = *inptr;
+
+ if (ptr->ch != *str) {
+ keymacro_node_t *xm;
+
+ for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
+ if (xm->sibling->ch == *str)
+ break;
+ if (xm->sibling == NULL)
+ return 0;
+ prev_ptr = xm;
+ ptr = xm->sibling;
+ }
+ if (*++str == '\0') {
+ /* we're there */
+ if (prev_ptr == NULL)
+ *inptr = ptr->sibling;
+ else
+ prev_ptr->sibling = ptr->sibling;
+ ptr->sibling = NULL;
+ node__put(el, ptr);
+ return 1;
+ } else if (ptr->next != NULL &&
+ node__delete(el, &ptr->next, str) == 1) {
+ if (ptr->next != NULL)
+ return 0;
+ if (prev_ptr == NULL)
+ *inptr = ptr->sibling;
+ else
+ prev_ptr->sibling = ptr->sibling;
+ ptr->sibling = NULL;
+ node__put(el, ptr);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/* node__put():
+ * Puts a tree of nodes onto free list using free(3).
+ */
+static void
+node__put(EditLine *el, keymacro_node_t *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ if (ptr->next != NULL) {
+ node__put(el, ptr->next);
+ ptr->next = NULL;
+ }
+ node__put(el, ptr->sibling);
+
+ switch (ptr->type) {
+ case XK_CMD:
+ case XK_NOD:
+ break;
+ case XK_STR:
+ if (ptr->val.str != NULL)
+ el_free(ptr->val.str);
+ break;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type));
+ break;
+ }
+ el_free(ptr);
+}
+
+
+/* node__get():
+ * Returns pointer to a keymacro_node_t for ch.
+ */
+static keymacro_node_t *
+node__get(wint_t ch)
+{
+ keymacro_node_t *ptr;
+
+ ptr = el_malloc(sizeof(*ptr));
+ if (ptr == NULL)
+ return NULL;
+ ptr->ch = ch;
+ ptr->type = XK_NOD;
+ ptr->val.str = NULL;
+ ptr->next = NULL;
+ ptr->sibling = NULL;
+ return ptr;
+}
+
+static void
+node__free(keymacro_node_t *k)
+{
+ if (k == NULL)
+ return;
+ node__free(k->sibling);
+ node__free(k->next);
+ el_free(k);
+}
+
+/* node_lookup():
+ * look for the str starting at node ptr.
+ * Print if last node
+ */
+static int
+node_lookup(EditLine *el, const wchar_t *str, keymacro_node_t *ptr,
+ size_t cnt)
+{
+ ssize_t used;
+
+ if (ptr == NULL)
+ return -1; /* cannot have null ptr */
+
+ if (!str || *str == 0) {
+ /* no more chars in str. node_enum from here. */
+ (void) node_enum(el, ptr, cnt);
+ return 0;
+ } else {
+ /* If match put this char into el->el_keymacro.buf. Recurse */
+ if (ptr->ch == *str) {
+ /* match found */
+ used = ct_visual_char(el->el_keymacro.buf + cnt,
+ KEY_BUFSIZ - cnt, ptr->ch);
+ if (used == -1)
+ return -1; /* ran out of buffer space */
+ if (ptr->next != NULL)
+ /* not yet at leaf */
+ return (node_lookup(el, str + 1, ptr->next,
+ (size_t)used + cnt));
+ else {
+ /* next node is null so key should be complete */
+ if (str[1] == 0) {
+ size_t px = cnt + (size_t)used;
+ el->el_keymacro.buf[px] = '"';
+ el->el_keymacro.buf[px + 1] = '\0';
+ keymacro_kprint(el, el->el_keymacro.buf,
+ &ptr->val, ptr->type);
+ return 0;
+ } else
+ return -1;
+ /* mismatch -- str still has chars */
+ }
+ } else {
+ /* no match found try sibling */
+ if (ptr->sibling)
+ return (node_lookup(el, str, ptr->sibling,
+ cnt));
+ else
+ return -1;
+ }
+ }
+}
+
+
+/* node_enum():
+ * Traverse the node printing the characters it is bound in buffer
+ */
+static int
+node_enum(EditLine *el, keymacro_node_t *ptr, size_t cnt)
+{
+ ssize_t used;
+
+ if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */
+ el->el_keymacro.buf[++cnt] = '"';
+ el->el_keymacro.buf[++cnt] = '\0';
+ (void) fprintf(el->el_errfile,
+ "Some extended keys too long for internal print buffer");
+ (void) fprintf(el->el_errfile, " \"%ls...\"\n",
+ el->el_keymacro.buf);
+ return 0;
+ }
+ if (ptr == NULL) {
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile,
+ "node_enum: BUG!! Null ptr passed\n!");
+#endif
+ return -1;
+ }
+ /* put this char at end of str */
+ used = ct_visual_char(el->el_keymacro.buf + cnt, KEY_BUFSIZ - cnt,
+ ptr->ch);
+ if (ptr->next == NULL) {
+ /* print this key and function */
+ el->el_keymacro.buf[cnt + (size_t)used ] = '"';
+ el->el_keymacro.buf[cnt + (size_t)used + 1] = '\0';
+ keymacro_kprint(el, el->el_keymacro.buf, &ptr->val, ptr->type);
+ } else
+ (void) node_enum(el, ptr->next, cnt + (size_t)used);
+
+ /* go to sibling if there is one */
+ if (ptr->sibling)
+ (void) node_enum(el, ptr->sibling, cnt);
+ return 0;
+}
+
+
+/* keymacro_kprint():
+ * Print the specified key and its associated
+ * function specified by val
+ */
+libedit_private void
+keymacro_kprint(EditLine *el, const wchar_t *key, keymacro_value_t *val,
+ int ntype)
+{
+ el_bindings_t *fp;
+ char unparsbuf[EL_BUFSIZ];
+ static const char fmt[] = "%-15s-> %s\n";
+
+ if (val != NULL)
+ switch (ntype) {
+ case XK_STR:
+ (void) keymacro__decode_str(val->str, unparsbuf,
+ sizeof(unparsbuf),
+ ntype == XK_STR ? "\"\"" : "[]");
+ (void) fprintf(el->el_outfile, fmt,
+ ct_encode_string(key, &el->el_scratch), unparsbuf);
+ break;
+ case XK_CMD:
+ for (fp = el->el_map.help; fp->name; fp++)
+ if (val->cmd == fp->func) {
+ wcstombs(unparsbuf, fp->name, sizeof(unparsbuf));
+ unparsbuf[sizeof(unparsbuf) -1] = '\0';
+ (void) fprintf(el->el_outfile, fmt,
+ ct_encode_string(key, &el->el_scratch), unparsbuf);
+ break;
+ }
+#ifdef DEBUG_KEY
+ if (fp->name == NULL)
+ (void) fprintf(el->el_outfile,
+ "BUG! Command not found.\n");
+#endif
+
+ break;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
+ break;
+ }
+ else
+ (void) fprintf(el->el_outfile, fmt, ct_encode_string(key,
+ &el->el_scratch), "no input");
+}
+
+
+#define ADDC(c) \
+ if (b < eb) \
+ *b++ = c; \
+ else \
+ b++
+/* keymacro__decode_str():
+ * Make a printable version of the ey
+ */
+libedit_private size_t
+keymacro__decode_str(const wchar_t *str, char *buf, size_t len,
+ const char *sep)
+{
+ char *b = buf, *eb = b + len;
+ const wchar_t *p;
+
+ b = buf;
+ if (sep[0] != '\0') {
+ ADDC(sep[0]);
+ }
+ if (*str == '\0') {
+ ADDC('^');
+ ADDC('@');
+ goto add_endsep;
+ }
+ for (p = str; *p != 0; p++) {
+ wchar_t dbuf[VISUAL_WIDTH_MAX];
+ wchar_t *p2 = dbuf;
+ ssize_t l = ct_visual_char(dbuf, VISUAL_WIDTH_MAX, *p);
+ while (l-- > 0) {
+ ssize_t n = ct_encode_char(b, (size_t)(eb - b), *p2++);
+ if (n == -1) /* ran out of space */
+ goto add_endsep;
+ else
+ b += n;
+ }
+ }
+add_endsep:
+ if (sep[0] != '\0' && sep[1] != '\0') {
+ ADDC(sep[1]);
+ }
+ ADDC('\0');
+ if ((size_t)(b - buf) >= len)
+ buf[len - 1] = '\0';
+ return (size_t)(b - buf);
+}
diff --git a/third_party/heimdal/lib/libedit/src/keymacro.h b/third_party/heimdal/lib/libedit/src/keymacro.h
new file mode 100644
index 0000000..0653bbe
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/keymacro.h
@@ -0,0 +1,76 @@
+/* $NetBSD: keymacro.h,v 1.6 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)key.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.keymacro.h: Key macro header
+ */
+#ifndef _h_el_keymacro
+#define _h_el_keymacro
+
+typedef union keymacro_value_t {
+ el_action_t cmd; /* If it is a command the # */
+ wchar_t *str; /* If it is a string... */
+} keymacro_value_t;
+
+typedef struct keymacro_node_t keymacro_node_t;
+
+typedef struct el_keymacro_t {
+ wchar_t *buf; /* Key print buffer */
+ keymacro_node_t *map; /* Key map */
+ keymacro_value_t val; /* Local conversion buffer */
+} el_keymacro_t;
+
+#define XK_CMD 0
+#define XK_STR 1
+#define XK_NOD 2
+
+libedit_private int keymacro_init(EditLine *);
+libedit_private void keymacro_end(EditLine *);
+libedit_private keymacro_value_t *keymacro_map_cmd(EditLine *, int);
+libedit_private keymacro_value_t *keymacro_map_str(EditLine *, wchar_t *);
+libedit_private void keymacro_reset(EditLine *);
+libedit_private int keymacro_get(EditLine *, wchar_t *, keymacro_value_t *);
+libedit_private void keymacro_add(EditLine *, const wchar_t *,
+ keymacro_value_t *, int);
+libedit_private void keymacro_clear(EditLine *, el_action_t *, const wchar_t *);
+libedit_private int keymacro_delete(EditLine *, const wchar_t *);
+libedit_private void keymacro_print(EditLine *, const wchar_t *);
+libedit_private void keymacro_kprint(EditLine *, const wchar_t *,
+ keymacro_value_t *, int);
+libedit_private size_t keymacro__decode_str(const wchar_t *, char *, size_t,
+ const char *);
+
+#endif /* _h_el_keymacro */
diff --git a/third_party/heimdal/lib/libedit/src/makelist b/third_party/heimdal/lib/libedit/src/makelist
new file mode 100644
index 0000000..c8db945
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/makelist
@@ -0,0 +1,177 @@
+#!/bin/sh -
+# $NetBSD: makelist,v 1.29 2016/05/09 21:46:56 christos Exp $
+#
+# Copyright (c) 1992, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Christos Zoulas of Cornell University.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)makelist 5.3 (Berkeley) 6/4/93
+
+# makelist.sh: Automatically generate header files...
+
+if [ "x$AWK" = "x" ]
+then
+ AWK=awk
+fi
+USAGE="Usage: $0 -h|-fc|-fh|-bh <filenames>"
+
+if [ "x$1" = "x" ]
+then
+ echo $USAGE 1>&2
+ exit 1
+fi
+
+FLAG="$1"
+shift
+
+FILES="$@"
+
+case $FLAG in
+
+-h)
+ set - `echo $FILES | sed -e 's/\\./_/g'`
+ hdr="_h_`basename $1`"
+ cat $FILES | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("#ifndef %s\n#define %s\n", "'$hdr'", "'$hdr'");
+ }
+ /\(\):/ {
+ pr = substr($2, 1, 2);
+ if (pr == "vi" || pr == "em" || pr == "ed") {
+ name = substr($2, 1, length($2) - 3);
+#
+# XXX: need a space between name and prototype so that -fc and -fh
+# parsing is much easier
+#
+ printf("libedit_private el_action_t\t%s (EditLine *, wint_t);\n",
+ name);
+ }
+ }
+ END {
+ printf("#endif /* %s */\n", "'$hdr'");
+ }'
+ ;;
+
+# generate help.h from various .c files
+#
+-bh)
+ cat $FILES | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("static const struct el_bindings_t el_func_help[] = {\n");
+ low = "abcdefghijklmnopqrstuvwxyz_";
+ high = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_";
+ for (i = 1; i <= length(low); i++)
+ tr[substr(low, i, 1)] = substr(high, i, 1);
+ }
+ /\(\):/ {
+ pr = substr($2, 1, 2);
+ if (pr == "vi" || pr == "em" || pr == "ed") {
+ name = substr($2, 1, length($2) - 3);
+ uname = "";
+ fname = "";
+ for (i = 1; i <= length(name); i++) {
+ s = substr(name, i, 1);
+ uname = uname tr[s];
+ if (s == "_")
+ s = "-";
+ fname = fname s;
+ }
+
+ printf(" { %-30.30s %-30.30s\n","L\"" fname "\",", uname ",");
+ ok = 1;
+ }
+ }
+ /^ \*/ {
+ if (ok) {
+ printf(" L\"");
+ for (i = 2; i < NF; i++)
+ printf("%s ", $i);
+ printf("%s\" },\n", $i);
+ ok = 0;
+ }
+ }
+ END {
+ printf("};\n");
+ }'
+ ;;
+
+# generate fcns.h from various .h files
+#
+-fh)
+ cat $FILES | $AWK '/el_action_t/ { print $3 }' | \
+ sort | tr '[a-z]' '[A-Z]' | tr -d ' ' | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ count = 0;
+ }
+ {
+ printf("#define\t%-30.30s\t%3d\n", $1, count++);
+ }
+ END {
+ printf("#define\t%-30.30s\t%3d\n", "EL_NUM_FCNS", count);
+ }'
+ ;;
+
+# generate func.h from various .h files
+#
+-fc)
+ cat $FILES | $AWK '/el_action_t/ { print $3 }' | sort | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("static const el_func_t el_func[] = {");
+ maxlen = 80;
+ needn = 1;
+ len = 0;
+ }
+ {
+ clen = 25 + 2;
+ len += clen;
+ if (len >= maxlen)
+ needn = 1;
+ if (needn) {
+ printf("\n ");
+ needn = 0;
+ len = 4 + clen;
+ }
+ s = $1 ",";
+ printf("%-26.26s ", s);
+ }
+ END {
+ printf("\n};\n");
+ }'
+ ;;
+
+*)
+ echo $USAGE 1>&2
+ exit 1
+ ;;
+
+esac
diff --git a/third_party/heimdal/lib/libedit/src/map.c b/third_party/heimdal/lib/libedit/src/map.c
new file mode 100644
index 0000000..f72d272
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/map.c
@@ -0,0 +1,1427 @@
+/* $NetBSD: map.c,v 1.51 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: map.c,v 1.51 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * map.c: Editor function definitions
+ */
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "el.h"
+#include "common.h"
+#include "emacs.h"
+#include "vi.h"
+#include "fcns.h"
+#include "func.h"
+#include "help.h"
+#include "parse.h"
+
+static void map_print_key(EditLine *, el_action_t *, const wchar_t *);
+static void map_print_some_keys(EditLine *, el_action_t *, wint_t, wint_t);
+static void map_print_all_keys(EditLine *);
+static void map_init_nls(EditLine *);
+static void map_init_meta(EditLine *);
+
+/* keymap tables ; should be N_KEYS*sizeof(KEYCMD) bytes long */
+
+
+static const el_action_t el_map_emacs[] = {
+ /* 0 */ EM_SET_MARK, /* ^@ */
+ /* 1 */ ED_MOVE_TO_BEG, /* ^A */
+ /* 2 */ ED_PREV_CHAR, /* ^B */
+ /* 3 */ ED_IGNORE, /* ^C */
+ /* 4 */ EM_DELETE_OR_LIST, /* ^D */
+ /* 5 */ ED_MOVE_TO_END, /* ^E */
+ /* 6 */ ED_NEXT_CHAR, /* ^F */
+ /* 7 */ ED_UNASSIGNED, /* ^G */
+ /* 8 */ EM_DELETE_PREV_CHAR, /* ^H */
+ /* 9 */ ED_UNASSIGNED, /* ^I */
+ /* 10 */ ED_NEWLINE, /* ^J */
+ /* 11 */ ED_KILL_LINE, /* ^K */
+ /* 12 */ ED_CLEAR_SCREEN, /* ^L */
+ /* 13 */ ED_NEWLINE, /* ^M */
+ /* 14 */ ED_NEXT_HISTORY, /* ^N */
+ /* 15 */ ED_IGNORE, /* ^O */
+ /* 16 */ ED_PREV_HISTORY, /* ^P */
+ /* 17 */ ED_IGNORE, /* ^Q */
+ /* 18 */ ED_REDISPLAY, /* ^R */
+ /* 19 */ ED_IGNORE, /* ^S */
+ /* 20 */ ED_TRANSPOSE_CHARS, /* ^T */
+ /* 21 */ EM_KILL_LINE, /* ^U */
+ /* 22 */ ED_QUOTED_INSERT, /* ^V */
+ /* 23 */ EM_KILL_REGION, /* ^W */
+ /* 24 */ ED_SEQUENCE_LEAD_IN, /* ^X */
+ /* 25 */ EM_YANK, /* ^Y */
+ /* 26 */ ED_IGNORE, /* ^Z */
+ /* 27 */ EM_META_NEXT, /* ^[ */
+ /* 28 */ ED_IGNORE, /* ^\ */
+ /* 29 */ ED_IGNORE, /* ^] */
+ /* 30 */ ED_UNASSIGNED, /* ^^ */
+ /* 31 */ ED_UNASSIGNED, /* ^_ */
+ /* 32 */ ED_INSERT, /* SPACE */
+ /* 33 */ ED_INSERT, /* ! */
+ /* 34 */ ED_INSERT, /* " */
+ /* 35 */ ED_INSERT, /* # */
+ /* 36 */ ED_INSERT, /* $ */
+ /* 37 */ ED_INSERT, /* % */
+ /* 38 */ ED_INSERT, /* & */
+ /* 39 */ ED_INSERT, /* ' */
+ /* 40 */ ED_INSERT, /* ( */
+ /* 41 */ ED_INSERT, /* ) */
+ /* 42 */ ED_INSERT, /* * */
+ /* 43 */ ED_INSERT, /* + */
+ /* 44 */ ED_INSERT, /* , */
+ /* 45 */ ED_INSERT, /* - */
+ /* 46 */ ED_INSERT, /* . */
+ /* 47 */ ED_INSERT, /* / */
+ /* 48 */ ED_DIGIT, /* 0 */
+ /* 49 */ ED_DIGIT, /* 1 */
+ /* 50 */ ED_DIGIT, /* 2 */
+ /* 51 */ ED_DIGIT, /* 3 */
+ /* 52 */ ED_DIGIT, /* 4 */
+ /* 53 */ ED_DIGIT, /* 5 */
+ /* 54 */ ED_DIGIT, /* 6 */
+ /* 55 */ ED_DIGIT, /* 7 */
+ /* 56 */ ED_DIGIT, /* 8 */
+ /* 57 */ ED_DIGIT, /* 9 */
+ /* 58 */ ED_INSERT, /* : */
+ /* 59 */ ED_INSERT, /* ; */
+ /* 60 */ ED_INSERT, /* < */
+ /* 61 */ ED_INSERT, /* = */
+ /* 62 */ ED_INSERT, /* > */
+ /* 63 */ ED_INSERT, /* ? */
+ /* 64 */ ED_INSERT, /* @ */
+ /* 65 */ ED_INSERT, /* A */
+ /* 66 */ ED_INSERT, /* B */
+ /* 67 */ ED_INSERT, /* C */
+ /* 68 */ ED_INSERT, /* D */
+ /* 69 */ ED_INSERT, /* E */
+ /* 70 */ ED_INSERT, /* F */
+ /* 71 */ ED_INSERT, /* G */
+ /* 72 */ ED_INSERT, /* H */
+ /* 73 */ ED_INSERT, /* I */
+ /* 74 */ ED_INSERT, /* J */
+ /* 75 */ ED_INSERT, /* K */
+ /* 76 */ ED_INSERT, /* L */
+ /* 77 */ ED_INSERT, /* M */
+ /* 78 */ ED_INSERT, /* N */
+ /* 79 */ ED_INSERT, /* O */
+ /* 80 */ ED_INSERT, /* P */
+ /* 81 */ ED_INSERT, /* Q */
+ /* 82 */ ED_INSERT, /* R */
+ /* 83 */ ED_INSERT, /* S */
+ /* 84 */ ED_INSERT, /* T */
+ /* 85 */ ED_INSERT, /* U */
+ /* 86 */ ED_INSERT, /* V */
+ /* 87 */ ED_INSERT, /* W */
+ /* 88 */ ED_INSERT, /* X */
+ /* 89 */ ED_INSERT, /* Y */
+ /* 90 */ ED_INSERT, /* Z */
+ /* 91 */ ED_INSERT, /* [ */
+ /* 92 */ ED_INSERT, /* \ */
+ /* 93 */ ED_INSERT, /* ] */
+ /* 94 */ ED_INSERT, /* ^ */
+ /* 95 */ ED_INSERT, /* _ */
+ /* 96 */ ED_INSERT, /* ` */
+ /* 97 */ ED_INSERT, /* a */
+ /* 98 */ ED_INSERT, /* b */
+ /* 99 */ ED_INSERT, /* c */
+ /* 100 */ ED_INSERT, /* d */
+ /* 101 */ ED_INSERT, /* e */
+ /* 102 */ ED_INSERT, /* f */
+ /* 103 */ ED_INSERT, /* g */
+ /* 104 */ ED_INSERT, /* h */
+ /* 105 */ ED_INSERT, /* i */
+ /* 106 */ ED_INSERT, /* j */
+ /* 107 */ ED_INSERT, /* k */
+ /* 108 */ ED_INSERT, /* l */
+ /* 109 */ ED_INSERT, /* m */
+ /* 110 */ ED_INSERT, /* n */
+ /* 111 */ ED_INSERT, /* o */
+ /* 112 */ ED_INSERT, /* p */
+ /* 113 */ ED_INSERT, /* q */
+ /* 114 */ ED_INSERT, /* r */
+ /* 115 */ ED_INSERT, /* s */
+ /* 116 */ ED_INSERT, /* t */
+ /* 117 */ ED_INSERT, /* u */
+ /* 118 */ ED_INSERT, /* v */
+ /* 119 */ ED_INSERT, /* w */
+ /* 120 */ ED_INSERT, /* x */
+ /* 121 */ ED_INSERT, /* y */
+ /* 122 */ ED_INSERT, /* z */
+ /* 123 */ ED_INSERT, /* { */
+ /* 124 */ ED_INSERT, /* | */
+ /* 125 */ ED_INSERT, /* } */
+ /* 126 */ ED_INSERT, /* ~ */
+ /* 127 */ EM_DELETE_PREV_CHAR, /* ^? */
+ /* 128 */ ED_UNASSIGNED, /* M-^@ */
+ /* 129 */ ED_UNASSIGNED, /* M-^A */
+ /* 130 */ ED_UNASSIGNED, /* M-^B */
+ /* 131 */ ED_UNASSIGNED, /* M-^C */
+ /* 132 */ ED_UNASSIGNED, /* M-^D */
+ /* 133 */ ED_UNASSIGNED, /* M-^E */
+ /* 134 */ ED_UNASSIGNED, /* M-^F */
+ /* 135 */ ED_UNASSIGNED, /* M-^G */
+ /* 136 */ ED_DELETE_PREV_WORD, /* M-^H */
+ /* 137 */ ED_UNASSIGNED, /* M-^I */
+ /* 138 */ ED_UNASSIGNED, /* M-^J */
+ /* 139 */ ED_UNASSIGNED, /* M-^K */
+ /* 140 */ ED_CLEAR_SCREEN, /* M-^L */
+ /* 141 */ ED_UNASSIGNED, /* M-^M */
+ /* 142 */ ED_UNASSIGNED, /* M-^N */
+ /* 143 */ ED_UNASSIGNED, /* M-^O */
+ /* 144 */ ED_UNASSIGNED, /* M-^P */
+ /* 145 */ ED_UNASSIGNED, /* M-^Q */
+ /* 146 */ ED_UNASSIGNED, /* M-^R */
+ /* 147 */ ED_UNASSIGNED, /* M-^S */
+ /* 148 */ ED_UNASSIGNED, /* M-^T */
+ /* 149 */ ED_UNASSIGNED, /* M-^U */
+ /* 150 */ ED_UNASSIGNED, /* M-^V */
+ /* 151 */ ED_UNASSIGNED, /* M-^W */
+ /* 152 */ ED_UNASSIGNED, /* M-^X */
+ /* 153 */ ED_UNASSIGNED, /* M-^Y */
+ /* 154 */ ED_UNASSIGNED, /* M-^Z */
+ /* 155 */ ED_UNASSIGNED, /* M-^[ */
+ /* 156 */ ED_UNASSIGNED, /* M-^\ */
+ /* 157 */ ED_UNASSIGNED, /* M-^] */
+ /* 158 */ ED_UNASSIGNED, /* M-^^ */
+ /* 159 */ EM_COPY_PREV_WORD, /* M-^_ */
+ /* 160 */ ED_UNASSIGNED, /* M-SPACE */
+ /* 161 */ ED_UNASSIGNED, /* M-! */
+ /* 162 */ ED_UNASSIGNED, /* M-" */
+ /* 163 */ ED_UNASSIGNED, /* M-# */
+ /* 164 */ ED_UNASSIGNED, /* M-$ */
+ /* 165 */ ED_UNASSIGNED, /* M-% */
+ /* 166 */ ED_UNASSIGNED, /* M-& */
+ /* 167 */ ED_UNASSIGNED, /* M-' */
+ /* 168 */ ED_UNASSIGNED, /* M-( */
+ /* 169 */ ED_UNASSIGNED, /* M-) */
+ /* 170 */ ED_UNASSIGNED, /* M-* */
+ /* 171 */ ED_UNASSIGNED, /* M-+ */
+ /* 172 */ ED_UNASSIGNED, /* M-, */
+ /* 173 */ ED_UNASSIGNED, /* M-- */
+ /* 174 */ ED_UNASSIGNED, /* M-. */
+ /* 175 */ ED_UNASSIGNED, /* M-/ */
+ /* 176 */ ED_ARGUMENT_DIGIT, /* M-0 */
+ /* 177 */ ED_ARGUMENT_DIGIT, /* M-1 */
+ /* 178 */ ED_ARGUMENT_DIGIT, /* M-2 */
+ /* 179 */ ED_ARGUMENT_DIGIT, /* M-3 */
+ /* 180 */ ED_ARGUMENT_DIGIT, /* M-4 */
+ /* 181 */ ED_ARGUMENT_DIGIT, /* M-5 */
+ /* 182 */ ED_ARGUMENT_DIGIT, /* M-6 */
+ /* 183 */ ED_ARGUMENT_DIGIT, /* M-7 */
+ /* 184 */ ED_ARGUMENT_DIGIT, /* M-8 */
+ /* 185 */ ED_ARGUMENT_DIGIT, /* M-9 */
+ /* 186 */ ED_UNASSIGNED, /* M-: */
+ /* 187 */ ED_UNASSIGNED, /* M-; */
+ /* 188 */ ED_UNASSIGNED, /* M-< */
+ /* 189 */ ED_UNASSIGNED, /* M-= */
+ /* 190 */ ED_UNASSIGNED, /* M-> */
+ /* 191 */ ED_UNASSIGNED, /* M-? */
+ /* 192 */ ED_UNASSIGNED, /* M-@ */
+ /* 193 */ ED_UNASSIGNED, /* M-A */
+ /* 194 */ ED_PREV_WORD, /* M-B */
+ /* 195 */ EM_CAPITOL_CASE, /* M-C */
+ /* 196 */ EM_DELETE_NEXT_WORD, /* M-D */
+ /* 197 */ ED_UNASSIGNED, /* M-E */
+ /* 198 */ EM_NEXT_WORD, /* M-F */
+ /* 199 */ ED_UNASSIGNED, /* M-G */
+ /* 200 */ ED_UNASSIGNED, /* M-H */
+ /* 201 */ ED_UNASSIGNED, /* M-I */
+ /* 202 */ ED_UNASSIGNED, /* M-J */
+ /* 203 */ ED_UNASSIGNED, /* M-K */
+ /* 204 */ EM_LOWER_CASE, /* M-L */
+ /* 205 */ ED_UNASSIGNED, /* M-M */
+ /* 206 */ ED_SEARCH_NEXT_HISTORY, /* M-N */
+ /* 207 */ ED_SEQUENCE_LEAD_IN, /* M-O */
+ /* 208 */ ED_SEARCH_PREV_HISTORY, /* M-P */
+ /* 209 */ ED_UNASSIGNED, /* M-Q */
+ /* 210 */ ED_UNASSIGNED, /* M-R */
+ /* 211 */ ED_UNASSIGNED, /* M-S */
+ /* 212 */ ED_UNASSIGNED, /* M-T */
+ /* 213 */ EM_UPPER_CASE, /* M-U */
+ /* 214 */ ED_UNASSIGNED, /* M-V */
+ /* 215 */ EM_COPY_REGION, /* M-W */
+ /* 216 */ ED_COMMAND, /* M-X */
+ /* 217 */ ED_UNASSIGNED, /* M-Y */
+ /* 218 */ ED_UNASSIGNED, /* M-Z */
+ /* 219 */ ED_SEQUENCE_LEAD_IN, /* M-[ */
+ /* 220 */ ED_UNASSIGNED, /* M-\ */
+ /* 221 */ ED_UNASSIGNED, /* M-] */
+ /* 222 */ ED_UNASSIGNED, /* M-^ */
+ /* 223 */ ED_UNASSIGNED, /* M-_ */
+ /* 223 */ ED_UNASSIGNED, /* M-` */
+ /* 224 */ ED_UNASSIGNED, /* M-a */
+ /* 225 */ ED_PREV_WORD, /* M-b */
+ /* 226 */ EM_CAPITOL_CASE, /* M-c */
+ /* 227 */ EM_DELETE_NEXT_WORD, /* M-d */
+ /* 228 */ ED_UNASSIGNED, /* M-e */
+ /* 229 */ EM_NEXT_WORD, /* M-f */
+ /* 230 */ ED_UNASSIGNED, /* M-g */
+ /* 231 */ ED_UNASSIGNED, /* M-h */
+ /* 232 */ ED_UNASSIGNED, /* M-i */
+ /* 233 */ ED_UNASSIGNED, /* M-j */
+ /* 234 */ ED_UNASSIGNED, /* M-k */
+ /* 235 */ EM_LOWER_CASE, /* M-l */
+ /* 236 */ ED_UNASSIGNED, /* M-m */
+ /* 237 */ ED_SEARCH_NEXT_HISTORY, /* M-n */
+ /* 238 */ ED_UNASSIGNED, /* M-o */
+ /* 239 */ ED_SEARCH_PREV_HISTORY, /* M-p */
+ /* 240 */ ED_UNASSIGNED, /* M-q */
+ /* 241 */ ED_UNASSIGNED, /* M-r */
+ /* 242 */ ED_UNASSIGNED, /* M-s */
+ /* 243 */ ED_UNASSIGNED, /* M-t */
+ /* 244 */ EM_UPPER_CASE, /* M-u */
+ /* 245 */ ED_UNASSIGNED, /* M-v */
+ /* 246 */ EM_COPY_REGION, /* M-w */
+ /* 247 */ ED_COMMAND, /* M-x */
+ /* 248 */ ED_UNASSIGNED, /* M-y */
+ /* 249 */ ED_UNASSIGNED, /* M-z */
+ /* 250 */ ED_UNASSIGNED, /* M-{ */
+ /* 251 */ ED_UNASSIGNED, /* M-| */
+ /* 252 */ ED_UNASSIGNED, /* M-} */
+ /* 253 */ ED_UNASSIGNED, /* M-~ */
+ /* 254 */ ED_DELETE_PREV_WORD /* M-^? */
+ /* 255 */
+};
+
+
+/*
+ * keymap table for vi. Each index into above tbl; should be
+ * N_KEYS entries long. Vi mode uses a sticky-extend to do command mode:
+ * insert mode characters are in the normal keymap, and command mode
+ * in the extended keymap.
+ */
+static const el_action_t el_map_vi_insert[] = {
+#ifdef KSHVI
+ /* 0 */ ED_UNASSIGNED, /* ^@ */
+ /* 1 */ ED_INSERT, /* ^A */
+ /* 2 */ ED_INSERT, /* ^B */
+ /* 3 */ ED_INSERT, /* ^C */
+ /* 4 */ VI_LIST_OR_EOF, /* ^D */
+ /* 5 */ ED_INSERT, /* ^E */
+ /* 6 */ ED_INSERT, /* ^F */
+ /* 7 */ ED_INSERT, /* ^G */
+ /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */
+ /* 9 */ ED_INSERT, /* ^I */ /* Tab Key */
+ /* 10 */ ED_NEWLINE, /* ^J */
+ /* 11 */ ED_INSERT, /* ^K */
+ /* 12 */ ED_INSERT, /* ^L */
+ /* 13 */ ED_NEWLINE, /* ^M */
+ /* 14 */ ED_INSERT, /* ^N */
+ /* 15 */ ED_INSERT, /* ^O */
+ /* 16 */ ED_INSERT, /* ^P */
+ /* 17 */ ED_IGNORE, /* ^Q */
+ /* 18 */ ED_INSERT, /* ^R */
+ /* 19 */ ED_IGNORE, /* ^S */
+ /* 20 */ ED_INSERT, /* ^T */
+ /* 21 */ VI_KILL_LINE_PREV, /* ^U */
+ /* 22 */ ED_QUOTED_INSERT, /* ^V */
+ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */
+ /* ED_DELETE_PREV_WORD: Only until strt edit pos */
+ /* 24 */ ED_INSERT, /* ^X */
+ /* 25 */ ED_INSERT, /* ^Y */
+ /* 26 */ ED_INSERT, /* ^Z */
+ /* 27 */ VI_COMMAND_MODE, /* ^[ */ /* [ Esc ] key */
+ /* 28 */ ED_IGNORE, /* ^\ */
+ /* 29 */ ED_INSERT, /* ^] */
+ /* 30 */ ED_INSERT, /* ^^ */
+ /* 31 */ ED_INSERT, /* ^_ */
+#else /* !KSHVI */
+ /*
+ * NOTE: These mappings do NOT Correspond well
+ * to the KSH VI editing assignments.
+ * On the other and they are convenient and
+ * many people have have gotten used to them.
+ */
+ /* 0 */ ED_UNASSIGNED, /* ^@ */
+ /* 1 */ ED_MOVE_TO_BEG, /* ^A */
+ /* 2 */ ED_PREV_CHAR, /* ^B */
+ /* 3 */ ED_IGNORE, /* ^C */
+ /* 4 */ VI_LIST_OR_EOF, /* ^D */
+ /* 5 */ ED_MOVE_TO_END, /* ^E */
+ /* 6 */ ED_NEXT_CHAR, /* ^F */
+ /* 7 */ ED_UNASSIGNED, /* ^G */
+ /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */
+ /* 9 */ ED_UNASSIGNED, /* ^I */ /* Tab Key */
+ /* 10 */ ED_NEWLINE, /* ^J */
+ /* 11 */ ED_KILL_LINE, /* ^K */
+ /* 12 */ ED_CLEAR_SCREEN, /* ^L */
+ /* 13 */ ED_NEWLINE, /* ^M */
+ /* 14 */ ED_NEXT_HISTORY, /* ^N */
+ /* 15 */ ED_IGNORE, /* ^O */
+ /* 16 */ ED_PREV_HISTORY, /* ^P */
+ /* 17 */ ED_IGNORE, /* ^Q */
+ /* 18 */ ED_REDISPLAY, /* ^R */
+ /* 19 */ ED_IGNORE, /* ^S */
+ /* 20 */ ED_TRANSPOSE_CHARS, /* ^T */
+ /* 21 */ VI_KILL_LINE_PREV, /* ^U */
+ /* 22 */ ED_QUOTED_INSERT, /* ^V */
+ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */
+ /* 24 */ ED_UNASSIGNED, /* ^X */
+ /* 25 */ ED_IGNORE, /* ^Y */
+ /* 26 */ ED_IGNORE, /* ^Z */
+ /* 27 */ VI_COMMAND_MODE, /* ^[ */
+ /* 28 */ ED_IGNORE, /* ^\ */
+ /* 29 */ ED_UNASSIGNED, /* ^] */
+ /* 30 */ ED_UNASSIGNED, /* ^^ */
+ /* 31 */ ED_UNASSIGNED, /* ^_ */
+#endif /* KSHVI */
+ /* 32 */ ED_INSERT, /* SPACE */
+ /* 33 */ ED_INSERT, /* ! */
+ /* 34 */ ED_INSERT, /* " */
+ /* 35 */ ED_INSERT, /* # */
+ /* 36 */ ED_INSERT, /* $ */
+ /* 37 */ ED_INSERT, /* % */
+ /* 38 */ ED_INSERT, /* & */
+ /* 39 */ ED_INSERT, /* ' */
+ /* 40 */ ED_INSERT, /* ( */
+ /* 41 */ ED_INSERT, /* ) */
+ /* 42 */ ED_INSERT, /* * */
+ /* 43 */ ED_INSERT, /* + */
+ /* 44 */ ED_INSERT, /* , */
+ /* 45 */ ED_INSERT, /* - */
+ /* 46 */ ED_INSERT, /* . */
+ /* 47 */ ED_INSERT, /* / */
+ /* 48 */ ED_INSERT, /* 0 */
+ /* 49 */ ED_INSERT, /* 1 */
+ /* 50 */ ED_INSERT, /* 2 */
+ /* 51 */ ED_INSERT, /* 3 */
+ /* 52 */ ED_INSERT, /* 4 */
+ /* 53 */ ED_INSERT, /* 5 */
+ /* 54 */ ED_INSERT, /* 6 */
+ /* 55 */ ED_INSERT, /* 7 */
+ /* 56 */ ED_INSERT, /* 8 */
+ /* 57 */ ED_INSERT, /* 9 */
+ /* 58 */ ED_INSERT, /* : */
+ /* 59 */ ED_INSERT, /* ; */
+ /* 60 */ ED_INSERT, /* < */
+ /* 61 */ ED_INSERT, /* = */
+ /* 62 */ ED_INSERT, /* > */
+ /* 63 */ ED_INSERT, /* ? */
+ /* 64 */ ED_INSERT, /* @ */
+ /* 65 */ ED_INSERT, /* A */
+ /* 66 */ ED_INSERT, /* B */
+ /* 67 */ ED_INSERT, /* C */
+ /* 68 */ ED_INSERT, /* D */
+ /* 69 */ ED_INSERT, /* E */
+ /* 70 */ ED_INSERT, /* F */
+ /* 71 */ ED_INSERT, /* G */
+ /* 72 */ ED_INSERT, /* H */
+ /* 73 */ ED_INSERT, /* I */
+ /* 74 */ ED_INSERT, /* J */
+ /* 75 */ ED_INSERT, /* K */
+ /* 76 */ ED_INSERT, /* L */
+ /* 77 */ ED_INSERT, /* M */
+ /* 78 */ ED_INSERT, /* N */
+ /* 79 */ ED_INSERT, /* O */
+ /* 80 */ ED_INSERT, /* P */
+ /* 81 */ ED_INSERT, /* Q */
+ /* 82 */ ED_INSERT, /* R */
+ /* 83 */ ED_INSERT, /* S */
+ /* 84 */ ED_INSERT, /* T */
+ /* 85 */ ED_INSERT, /* U */
+ /* 86 */ ED_INSERT, /* V */
+ /* 87 */ ED_INSERT, /* W */
+ /* 88 */ ED_INSERT, /* X */
+ /* 89 */ ED_INSERT, /* Y */
+ /* 90 */ ED_INSERT, /* Z */
+ /* 91 */ ED_INSERT, /* [ */
+ /* 92 */ ED_INSERT, /* \ */
+ /* 93 */ ED_INSERT, /* ] */
+ /* 94 */ ED_INSERT, /* ^ */
+ /* 95 */ ED_INSERT, /* _ */
+ /* 96 */ ED_INSERT, /* ` */
+ /* 97 */ ED_INSERT, /* a */
+ /* 98 */ ED_INSERT, /* b */
+ /* 99 */ ED_INSERT, /* c */
+ /* 100 */ ED_INSERT, /* d */
+ /* 101 */ ED_INSERT, /* e */
+ /* 102 */ ED_INSERT, /* f */
+ /* 103 */ ED_INSERT, /* g */
+ /* 104 */ ED_INSERT, /* h */
+ /* 105 */ ED_INSERT, /* i */
+ /* 106 */ ED_INSERT, /* j */
+ /* 107 */ ED_INSERT, /* k */
+ /* 108 */ ED_INSERT, /* l */
+ /* 109 */ ED_INSERT, /* m */
+ /* 110 */ ED_INSERT, /* n */
+ /* 111 */ ED_INSERT, /* o */
+ /* 112 */ ED_INSERT, /* p */
+ /* 113 */ ED_INSERT, /* q */
+ /* 114 */ ED_INSERT, /* r */
+ /* 115 */ ED_INSERT, /* s */
+ /* 116 */ ED_INSERT, /* t */
+ /* 117 */ ED_INSERT, /* u */
+ /* 118 */ ED_INSERT, /* v */
+ /* 119 */ ED_INSERT, /* w */
+ /* 120 */ ED_INSERT, /* x */
+ /* 121 */ ED_INSERT, /* y */
+ /* 122 */ ED_INSERT, /* z */
+ /* 123 */ ED_INSERT, /* { */
+ /* 124 */ ED_INSERT, /* | */
+ /* 125 */ ED_INSERT, /* } */
+ /* 126 */ ED_INSERT, /* ~ */
+ /* 127 */ VI_DELETE_PREV_CHAR, /* ^? */
+ /* 128 */ ED_INSERT, /* M-^@ */
+ /* 129 */ ED_INSERT, /* M-^A */
+ /* 130 */ ED_INSERT, /* M-^B */
+ /* 131 */ ED_INSERT, /* M-^C */
+ /* 132 */ ED_INSERT, /* M-^D */
+ /* 133 */ ED_INSERT, /* M-^E */
+ /* 134 */ ED_INSERT, /* M-^F */
+ /* 135 */ ED_INSERT, /* M-^G */
+ /* 136 */ ED_INSERT, /* M-^H */
+ /* 137 */ ED_INSERT, /* M-^I */
+ /* 138 */ ED_INSERT, /* M-^J */
+ /* 139 */ ED_INSERT, /* M-^K */
+ /* 140 */ ED_INSERT, /* M-^L */
+ /* 141 */ ED_INSERT, /* M-^M */
+ /* 142 */ ED_INSERT, /* M-^N */
+ /* 143 */ ED_INSERT, /* M-^O */
+ /* 144 */ ED_INSERT, /* M-^P */
+ /* 145 */ ED_INSERT, /* M-^Q */
+ /* 146 */ ED_INSERT, /* M-^R */
+ /* 147 */ ED_INSERT, /* M-^S */
+ /* 148 */ ED_INSERT, /* M-^T */
+ /* 149 */ ED_INSERT, /* M-^U */
+ /* 150 */ ED_INSERT, /* M-^V */
+ /* 151 */ ED_INSERT, /* M-^W */
+ /* 152 */ ED_INSERT, /* M-^X */
+ /* 153 */ ED_INSERT, /* M-^Y */
+ /* 154 */ ED_INSERT, /* M-^Z */
+ /* 155 */ ED_INSERT, /* M-^[ */
+ /* 156 */ ED_INSERT, /* M-^\ */
+ /* 157 */ ED_INSERT, /* M-^] */
+ /* 158 */ ED_INSERT, /* M-^^ */
+ /* 159 */ ED_INSERT, /* M-^_ */
+ /* 160 */ ED_INSERT, /* M-SPACE */
+ /* 161 */ ED_INSERT, /* M-! */
+ /* 162 */ ED_INSERT, /* M-" */
+ /* 163 */ ED_INSERT, /* M-# */
+ /* 164 */ ED_INSERT, /* M-$ */
+ /* 165 */ ED_INSERT, /* M-% */
+ /* 166 */ ED_INSERT, /* M-& */
+ /* 167 */ ED_INSERT, /* M-' */
+ /* 168 */ ED_INSERT, /* M-( */
+ /* 169 */ ED_INSERT, /* M-) */
+ /* 170 */ ED_INSERT, /* M-* */
+ /* 171 */ ED_INSERT, /* M-+ */
+ /* 172 */ ED_INSERT, /* M-, */
+ /* 173 */ ED_INSERT, /* M-- */
+ /* 174 */ ED_INSERT, /* M-. */
+ /* 175 */ ED_INSERT, /* M-/ */
+ /* 176 */ ED_INSERT, /* M-0 */
+ /* 177 */ ED_INSERT, /* M-1 */
+ /* 178 */ ED_INSERT, /* M-2 */
+ /* 179 */ ED_INSERT, /* M-3 */
+ /* 180 */ ED_INSERT, /* M-4 */
+ /* 181 */ ED_INSERT, /* M-5 */
+ /* 182 */ ED_INSERT, /* M-6 */
+ /* 183 */ ED_INSERT, /* M-7 */
+ /* 184 */ ED_INSERT, /* M-8 */
+ /* 185 */ ED_INSERT, /* M-9 */
+ /* 186 */ ED_INSERT, /* M-: */
+ /* 187 */ ED_INSERT, /* M-; */
+ /* 188 */ ED_INSERT, /* M-< */
+ /* 189 */ ED_INSERT, /* M-= */
+ /* 190 */ ED_INSERT, /* M-> */
+ /* 191 */ ED_INSERT, /* M-? */
+ /* 192 */ ED_INSERT, /* M-@ */
+ /* 193 */ ED_INSERT, /* M-A */
+ /* 194 */ ED_INSERT, /* M-B */
+ /* 195 */ ED_INSERT, /* M-C */
+ /* 196 */ ED_INSERT, /* M-D */
+ /* 197 */ ED_INSERT, /* M-E */
+ /* 198 */ ED_INSERT, /* M-F */
+ /* 199 */ ED_INSERT, /* M-G */
+ /* 200 */ ED_INSERT, /* M-H */
+ /* 201 */ ED_INSERT, /* M-I */
+ /* 202 */ ED_INSERT, /* M-J */
+ /* 203 */ ED_INSERT, /* M-K */
+ /* 204 */ ED_INSERT, /* M-L */
+ /* 205 */ ED_INSERT, /* M-M */
+ /* 206 */ ED_INSERT, /* M-N */
+ /* 207 */ ED_INSERT, /* M-O */
+ /* 208 */ ED_INSERT, /* M-P */
+ /* 209 */ ED_INSERT, /* M-Q */
+ /* 210 */ ED_INSERT, /* M-R */
+ /* 211 */ ED_INSERT, /* M-S */
+ /* 212 */ ED_INSERT, /* M-T */
+ /* 213 */ ED_INSERT, /* M-U */
+ /* 214 */ ED_INSERT, /* M-V */
+ /* 215 */ ED_INSERT, /* M-W */
+ /* 216 */ ED_INSERT, /* M-X */
+ /* 217 */ ED_INSERT, /* M-Y */
+ /* 218 */ ED_INSERT, /* M-Z */
+ /* 219 */ ED_INSERT, /* M-[ */
+ /* 220 */ ED_INSERT, /* M-\ */
+ /* 221 */ ED_INSERT, /* M-] */
+ /* 222 */ ED_INSERT, /* M-^ */
+ /* 223 */ ED_INSERT, /* M-_ */
+ /* 224 */ ED_INSERT, /* M-` */
+ /* 225 */ ED_INSERT, /* M-a */
+ /* 226 */ ED_INSERT, /* M-b */
+ /* 227 */ ED_INSERT, /* M-c */
+ /* 228 */ ED_INSERT, /* M-d */
+ /* 229 */ ED_INSERT, /* M-e */
+ /* 230 */ ED_INSERT, /* M-f */
+ /* 231 */ ED_INSERT, /* M-g */
+ /* 232 */ ED_INSERT, /* M-h */
+ /* 233 */ ED_INSERT, /* M-i */
+ /* 234 */ ED_INSERT, /* M-j */
+ /* 235 */ ED_INSERT, /* M-k */
+ /* 236 */ ED_INSERT, /* M-l */
+ /* 237 */ ED_INSERT, /* M-m */
+ /* 238 */ ED_INSERT, /* M-n */
+ /* 239 */ ED_INSERT, /* M-o */
+ /* 240 */ ED_INSERT, /* M-p */
+ /* 241 */ ED_INSERT, /* M-q */
+ /* 242 */ ED_INSERT, /* M-r */
+ /* 243 */ ED_INSERT, /* M-s */
+ /* 244 */ ED_INSERT, /* M-t */
+ /* 245 */ ED_INSERT, /* M-u */
+ /* 246 */ ED_INSERT, /* M-v */
+ /* 247 */ ED_INSERT, /* M-w */
+ /* 248 */ ED_INSERT, /* M-x */
+ /* 249 */ ED_INSERT, /* M-y */
+ /* 250 */ ED_INSERT, /* M-z */
+ /* 251 */ ED_INSERT, /* M-{ */
+ /* 252 */ ED_INSERT, /* M-| */
+ /* 253 */ ED_INSERT, /* M-} */
+ /* 254 */ ED_INSERT, /* M-~ */
+ /* 255 */ ED_INSERT /* M-^? */
+};
+
+static const el_action_t el_map_vi_command[] = {
+ /* 0 */ ED_UNASSIGNED, /* ^@ */
+ /* 1 */ ED_MOVE_TO_BEG, /* ^A */
+ /* 2 */ ED_UNASSIGNED, /* ^B */
+ /* 3 */ ED_IGNORE, /* ^C */
+ /* 4 */ ED_UNASSIGNED, /* ^D */
+ /* 5 */ ED_MOVE_TO_END, /* ^E */
+ /* 6 */ ED_UNASSIGNED, /* ^F */
+ /* 7 */ ED_UNASSIGNED, /* ^G */
+ /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */
+ /* 9 */ ED_UNASSIGNED, /* ^I */
+ /* 10 */ ED_NEWLINE, /* ^J */
+ /* 11 */ ED_KILL_LINE, /* ^K */
+ /* 12 */ ED_CLEAR_SCREEN, /* ^L */
+ /* 13 */ ED_NEWLINE, /* ^M */
+ /* 14 */ ED_NEXT_HISTORY, /* ^N */
+ /* 15 */ ED_IGNORE, /* ^O */
+ /* 16 */ ED_PREV_HISTORY, /* ^P */
+ /* 17 */ ED_IGNORE, /* ^Q */
+ /* 18 */ ED_REDISPLAY, /* ^R */
+ /* 19 */ ED_IGNORE, /* ^S */
+ /* 20 */ ED_UNASSIGNED, /* ^T */
+ /* 21 */ VI_KILL_LINE_PREV, /* ^U */
+ /* 22 */ ED_UNASSIGNED, /* ^V */
+ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */
+ /* 24 */ ED_UNASSIGNED, /* ^X */
+ /* 25 */ ED_UNASSIGNED, /* ^Y */
+ /* 26 */ ED_UNASSIGNED, /* ^Z */
+ /* 27 */ EM_META_NEXT, /* ^[ */
+ /* 28 */ ED_IGNORE, /* ^\ */
+ /* 29 */ ED_UNASSIGNED, /* ^] */
+ /* 30 */ ED_UNASSIGNED, /* ^^ */
+ /* 31 */ ED_UNASSIGNED, /* ^_ */
+ /* 32 */ ED_NEXT_CHAR, /* SPACE */
+ /* 33 */ ED_UNASSIGNED, /* ! */
+ /* 34 */ ED_UNASSIGNED, /* " */
+ /* 35 */ VI_COMMENT_OUT, /* # */
+ /* 36 */ ED_MOVE_TO_END, /* $ */
+ /* 37 */ VI_MATCH, /* % */
+ /* 38 */ ED_UNASSIGNED, /* & */
+ /* 39 */ ED_UNASSIGNED, /* ' */
+ /* 40 */ ED_UNASSIGNED, /* ( */
+ /* 41 */ ED_UNASSIGNED, /* ) */
+ /* 42 */ ED_UNASSIGNED, /* * */
+ /* 43 */ ED_NEXT_HISTORY, /* + */
+ /* 44 */ VI_REPEAT_PREV_CHAR, /* , */
+ /* 45 */ ED_PREV_HISTORY, /* - */
+ /* 46 */ VI_REDO, /* . */
+ /* 47 */ VI_SEARCH_PREV, /* / */
+ /* 48 */ VI_ZERO, /* 0 */
+ /* 49 */ ED_ARGUMENT_DIGIT, /* 1 */
+ /* 50 */ ED_ARGUMENT_DIGIT, /* 2 */
+ /* 51 */ ED_ARGUMENT_DIGIT, /* 3 */
+ /* 52 */ ED_ARGUMENT_DIGIT, /* 4 */
+ /* 53 */ ED_ARGUMENT_DIGIT, /* 5 */
+ /* 54 */ ED_ARGUMENT_DIGIT, /* 6 */
+ /* 55 */ ED_ARGUMENT_DIGIT, /* 7 */
+ /* 56 */ ED_ARGUMENT_DIGIT, /* 8 */
+ /* 57 */ ED_ARGUMENT_DIGIT, /* 9 */
+ /* 58 */ ED_COMMAND, /* : */
+ /* 59 */ VI_REPEAT_NEXT_CHAR, /* ; */
+ /* 60 */ ED_UNASSIGNED, /* < */
+ /* 61 */ ED_UNASSIGNED, /* = */
+ /* 62 */ ED_UNASSIGNED, /* > */
+ /* 63 */ VI_SEARCH_NEXT, /* ? */
+ /* 64 */ VI_ALIAS, /* @ */
+ /* 65 */ VI_ADD_AT_EOL, /* A */
+ /* 66 */ VI_PREV_BIG_WORD, /* B */
+ /* 67 */ VI_CHANGE_TO_EOL, /* C */
+ /* 68 */ ED_KILL_LINE, /* D */
+ /* 69 */ VI_END_BIG_WORD, /* E */
+ /* 70 */ VI_PREV_CHAR, /* F */
+ /* 71 */ VI_TO_HISTORY_LINE, /* G */
+ /* 72 */ ED_UNASSIGNED, /* H */
+ /* 73 */ VI_INSERT_AT_BOL, /* I */
+ /* 74 */ ED_SEARCH_NEXT_HISTORY, /* J */
+ /* 75 */ ED_SEARCH_PREV_HISTORY, /* K */
+ /* 76 */ ED_UNASSIGNED, /* L */
+ /* 77 */ ED_UNASSIGNED, /* M */
+ /* 78 */ VI_REPEAT_SEARCH_PREV, /* N */
+ /* 79 */ ED_SEQUENCE_LEAD_IN, /* O */
+ /* 80 */ VI_PASTE_PREV, /* P */
+ /* 81 */ ED_UNASSIGNED, /* Q */
+ /* 82 */ VI_REPLACE_MODE, /* R */
+ /* 83 */ VI_SUBSTITUTE_LINE, /* S */
+ /* 84 */ VI_TO_PREV_CHAR, /* T */
+ /* 85 */ VI_UNDO_LINE, /* U */
+ /* 86 */ ED_UNASSIGNED, /* V */
+ /* 87 */ VI_NEXT_BIG_WORD, /* W */
+ /* 88 */ ED_DELETE_PREV_CHAR, /* X */
+ /* 89 */ VI_YANK_END, /* Y */
+ /* 90 */ ED_UNASSIGNED, /* Z */
+ /* 91 */ ED_SEQUENCE_LEAD_IN, /* [ */
+ /* 92 */ ED_UNASSIGNED, /* \ */
+ /* 93 */ ED_UNASSIGNED, /* ] */
+ /* 94 */ ED_MOVE_TO_BEG, /* ^ */
+ /* 95 */ VI_HISTORY_WORD, /* _ */
+ /* 96 */ ED_UNASSIGNED, /* ` */
+ /* 97 */ VI_ADD, /* a */
+ /* 98 */ VI_PREV_WORD, /* b */
+ /* 99 */ VI_CHANGE_META, /* c */
+ /* 100 */ VI_DELETE_META, /* d */
+ /* 101 */ VI_END_WORD, /* e */
+ /* 102 */ VI_NEXT_CHAR, /* f */
+ /* 103 */ ED_UNASSIGNED, /* g */
+ /* 104 */ ED_PREV_CHAR, /* h */
+ /* 105 */ VI_INSERT, /* i */
+ /* 106 */ ED_NEXT_HISTORY, /* j */
+ /* 107 */ ED_PREV_HISTORY, /* k */
+ /* 108 */ ED_NEXT_CHAR, /* l */
+ /* 109 */ ED_UNASSIGNED, /* m */
+ /* 110 */ VI_REPEAT_SEARCH_NEXT, /* n */
+ /* 111 */ ED_UNASSIGNED, /* o */
+ /* 112 */ VI_PASTE_NEXT, /* p */
+ /* 113 */ ED_UNASSIGNED, /* q */
+ /* 114 */ VI_REPLACE_CHAR, /* r */
+ /* 115 */ VI_SUBSTITUTE_CHAR, /* s */
+ /* 116 */ VI_TO_NEXT_CHAR, /* t */
+ /* 117 */ VI_UNDO, /* u */
+ /* 118 */ VI_HISTEDIT, /* v */
+ /* 119 */ VI_NEXT_WORD, /* w */
+ /* 120 */ ED_DELETE_NEXT_CHAR, /* x */
+ /* 121 */ VI_YANK, /* y */
+ /* 122 */ ED_UNASSIGNED, /* z */
+ /* 123 */ ED_UNASSIGNED, /* { */
+ /* 124 */ VI_TO_COLUMN, /* | */
+ /* 125 */ ED_UNASSIGNED, /* } */
+ /* 126 */ VI_CHANGE_CASE, /* ~ */
+ /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */
+ /* 128 */ ED_UNASSIGNED, /* M-^@ */
+ /* 129 */ ED_UNASSIGNED, /* M-^A */
+ /* 130 */ ED_UNASSIGNED, /* M-^B */
+ /* 131 */ ED_UNASSIGNED, /* M-^C */
+ /* 132 */ ED_UNASSIGNED, /* M-^D */
+ /* 133 */ ED_UNASSIGNED, /* M-^E */
+ /* 134 */ ED_UNASSIGNED, /* M-^F */
+ /* 135 */ ED_UNASSIGNED, /* M-^G */
+ /* 136 */ ED_UNASSIGNED, /* M-^H */
+ /* 137 */ ED_UNASSIGNED, /* M-^I */
+ /* 138 */ ED_UNASSIGNED, /* M-^J */
+ /* 139 */ ED_UNASSIGNED, /* M-^K */
+ /* 140 */ ED_UNASSIGNED, /* M-^L */
+ /* 141 */ ED_UNASSIGNED, /* M-^M */
+ /* 142 */ ED_UNASSIGNED, /* M-^N */
+ /* 143 */ ED_UNASSIGNED, /* M-^O */
+ /* 144 */ ED_UNASSIGNED, /* M-^P */
+ /* 145 */ ED_UNASSIGNED, /* M-^Q */
+ /* 146 */ ED_UNASSIGNED, /* M-^R */
+ /* 147 */ ED_UNASSIGNED, /* M-^S */
+ /* 148 */ ED_UNASSIGNED, /* M-^T */
+ /* 149 */ ED_UNASSIGNED, /* M-^U */
+ /* 150 */ ED_UNASSIGNED, /* M-^V */
+ /* 151 */ ED_UNASSIGNED, /* M-^W */
+ /* 152 */ ED_UNASSIGNED, /* M-^X */
+ /* 153 */ ED_UNASSIGNED, /* M-^Y */
+ /* 154 */ ED_UNASSIGNED, /* M-^Z */
+ /* 155 */ ED_UNASSIGNED, /* M-^[ */
+ /* 156 */ ED_UNASSIGNED, /* M-^\ */
+ /* 157 */ ED_UNASSIGNED, /* M-^] */
+ /* 158 */ ED_UNASSIGNED, /* M-^^ */
+ /* 159 */ ED_UNASSIGNED, /* M-^_ */
+ /* 160 */ ED_UNASSIGNED, /* M-SPACE */
+ /* 161 */ ED_UNASSIGNED, /* M-! */
+ /* 162 */ ED_UNASSIGNED, /* M-" */
+ /* 163 */ ED_UNASSIGNED, /* M-# */
+ /* 164 */ ED_UNASSIGNED, /* M-$ */
+ /* 165 */ ED_UNASSIGNED, /* M-% */
+ /* 166 */ ED_UNASSIGNED, /* M-& */
+ /* 167 */ ED_UNASSIGNED, /* M-' */
+ /* 168 */ ED_UNASSIGNED, /* M-( */
+ /* 169 */ ED_UNASSIGNED, /* M-) */
+ /* 170 */ ED_UNASSIGNED, /* M-* */
+ /* 171 */ ED_UNASSIGNED, /* M-+ */
+ /* 172 */ ED_UNASSIGNED, /* M-, */
+ /* 173 */ ED_UNASSIGNED, /* M-- */
+ /* 174 */ ED_UNASSIGNED, /* M-. */
+ /* 175 */ ED_UNASSIGNED, /* M-/ */
+ /* 176 */ ED_UNASSIGNED, /* M-0 */
+ /* 177 */ ED_UNASSIGNED, /* M-1 */
+ /* 178 */ ED_UNASSIGNED, /* M-2 */
+ /* 179 */ ED_UNASSIGNED, /* M-3 */
+ /* 180 */ ED_UNASSIGNED, /* M-4 */
+ /* 181 */ ED_UNASSIGNED, /* M-5 */
+ /* 182 */ ED_UNASSIGNED, /* M-6 */
+ /* 183 */ ED_UNASSIGNED, /* M-7 */
+ /* 184 */ ED_UNASSIGNED, /* M-8 */
+ /* 185 */ ED_UNASSIGNED, /* M-9 */
+ /* 186 */ ED_UNASSIGNED, /* M-: */
+ /* 187 */ ED_UNASSIGNED, /* M-; */
+ /* 188 */ ED_UNASSIGNED, /* M-< */
+ /* 189 */ ED_UNASSIGNED, /* M-= */
+ /* 190 */ ED_UNASSIGNED, /* M-> */
+ /* 191 */ ED_UNASSIGNED, /* M-? */
+ /* 192 */ ED_UNASSIGNED, /* M-@ */
+ /* 193 */ ED_UNASSIGNED, /* M-A */
+ /* 194 */ ED_UNASSIGNED, /* M-B */
+ /* 195 */ ED_UNASSIGNED, /* M-C */
+ /* 196 */ ED_UNASSIGNED, /* M-D */
+ /* 197 */ ED_UNASSIGNED, /* M-E */
+ /* 198 */ ED_UNASSIGNED, /* M-F */
+ /* 199 */ ED_UNASSIGNED, /* M-G */
+ /* 200 */ ED_UNASSIGNED, /* M-H */
+ /* 201 */ ED_UNASSIGNED, /* M-I */
+ /* 202 */ ED_UNASSIGNED, /* M-J */
+ /* 203 */ ED_UNASSIGNED, /* M-K */
+ /* 204 */ ED_UNASSIGNED, /* M-L */
+ /* 205 */ ED_UNASSIGNED, /* M-M */
+ /* 206 */ ED_UNASSIGNED, /* M-N */
+ /* 207 */ ED_SEQUENCE_LEAD_IN, /* M-O */
+ /* 208 */ ED_UNASSIGNED, /* M-P */
+ /* 209 */ ED_UNASSIGNED, /* M-Q */
+ /* 210 */ ED_UNASSIGNED, /* M-R */
+ /* 211 */ ED_UNASSIGNED, /* M-S */
+ /* 212 */ ED_UNASSIGNED, /* M-T */
+ /* 213 */ ED_UNASSIGNED, /* M-U */
+ /* 214 */ ED_UNASSIGNED, /* M-V */
+ /* 215 */ ED_UNASSIGNED, /* M-W */
+ /* 216 */ ED_UNASSIGNED, /* M-X */
+ /* 217 */ ED_UNASSIGNED, /* M-Y */
+ /* 218 */ ED_UNASSIGNED, /* M-Z */
+ /* 219 */ ED_SEQUENCE_LEAD_IN, /* M-[ */
+ /* 220 */ ED_UNASSIGNED, /* M-\ */
+ /* 221 */ ED_UNASSIGNED, /* M-] */
+ /* 222 */ ED_UNASSIGNED, /* M-^ */
+ /* 223 */ ED_UNASSIGNED, /* M-_ */
+ /* 224 */ ED_UNASSIGNED, /* M-` */
+ /* 225 */ ED_UNASSIGNED, /* M-a */
+ /* 226 */ ED_UNASSIGNED, /* M-b */
+ /* 227 */ ED_UNASSIGNED, /* M-c */
+ /* 228 */ ED_UNASSIGNED, /* M-d */
+ /* 229 */ ED_UNASSIGNED, /* M-e */
+ /* 230 */ ED_UNASSIGNED, /* M-f */
+ /* 231 */ ED_UNASSIGNED, /* M-g */
+ /* 232 */ ED_UNASSIGNED, /* M-h */
+ /* 233 */ ED_UNASSIGNED, /* M-i */
+ /* 234 */ ED_UNASSIGNED, /* M-j */
+ /* 235 */ ED_UNASSIGNED, /* M-k */
+ /* 236 */ ED_UNASSIGNED, /* M-l */
+ /* 237 */ ED_UNASSIGNED, /* M-m */
+ /* 238 */ ED_UNASSIGNED, /* M-n */
+ /* 239 */ ED_UNASSIGNED, /* M-o */
+ /* 240 */ ED_UNASSIGNED, /* M-p */
+ /* 241 */ ED_UNASSIGNED, /* M-q */
+ /* 242 */ ED_UNASSIGNED, /* M-r */
+ /* 243 */ ED_UNASSIGNED, /* M-s */
+ /* 244 */ ED_UNASSIGNED, /* M-t */
+ /* 245 */ ED_UNASSIGNED, /* M-u */
+ /* 246 */ ED_UNASSIGNED, /* M-v */
+ /* 247 */ ED_UNASSIGNED, /* M-w */
+ /* 248 */ ED_UNASSIGNED, /* M-x */
+ /* 249 */ ED_UNASSIGNED, /* M-y */
+ /* 250 */ ED_UNASSIGNED, /* M-z */
+ /* 251 */ ED_UNASSIGNED, /* M-{ */
+ /* 252 */ ED_UNASSIGNED, /* M-| */
+ /* 253 */ ED_UNASSIGNED, /* M-} */
+ /* 254 */ ED_UNASSIGNED, /* M-~ */
+ /* 255 */ ED_UNASSIGNED /* M-^? */
+};
+
+
+/* map_init():
+ * Initialize and allocate the maps
+ */
+libedit_private int
+map_init(EditLine *el)
+{
+
+ /*
+ * Make sure those are correct before starting.
+ */
+#ifdef MAP_DEBUG
+ if (sizeof(el_map_emacs) != N_KEYS * sizeof(el_action_t))
+ EL_ABORT((el->errfile, "Emacs map incorrect\n"));
+ if (sizeof(el_map_vi_command) != N_KEYS * sizeof(el_action_t))
+ EL_ABORT((el->errfile, "Vi command map incorrect\n"));
+ if (sizeof(el_map_vi_insert) != N_KEYS * sizeof(el_action_t))
+ EL_ABORT((el->errfile, "Vi insert map incorrect\n"));
+#endif
+
+ el->el_map.alt = el_malloc(sizeof(*el->el_map.alt) * N_KEYS);
+ if (el->el_map.alt == NULL)
+ return -1;
+ el->el_map.key = el_malloc(sizeof(*el->el_map.key) * N_KEYS);
+ if (el->el_map.key == NULL)
+ return -1;
+ el->el_map.emacs = el_map_emacs;
+ el->el_map.vic = el_map_vi_command;
+ el->el_map.vii = el_map_vi_insert;
+ el->el_map.help = el_malloc(sizeof(*el->el_map.help) * EL_NUM_FCNS);
+ if (el->el_map.help == NULL)
+ return -1;
+ (void) memcpy(el->el_map.help, el_func_help,
+ sizeof(*el->el_map.help) * EL_NUM_FCNS);
+ el->el_map.func = el_malloc(sizeof(*el->el_map.func) * EL_NUM_FCNS);
+ if (el->el_map.func == NULL)
+ return -1;
+ memcpy(el->el_map.func, el_func, sizeof(*el->el_map.func)
+ * EL_NUM_FCNS);
+ el->el_map.nfunc = EL_NUM_FCNS;
+
+#ifdef VIDEFAULT
+ map_init_vi(el);
+#else
+ map_init_emacs(el);
+#endif /* VIDEFAULT */
+ return 0;
+}
+
+
+/* map_end():
+ * Free the space taken by the editor maps
+ */
+libedit_private void
+map_end(EditLine *el)
+{
+
+ el_free(el->el_map.alt);
+ el->el_map.alt = NULL;
+ el_free(el->el_map.key);
+ el->el_map.key = NULL;
+ el->el_map.emacs = NULL;
+ el->el_map.vic = NULL;
+ el->el_map.vii = NULL;
+ el_free(el->el_map.help);
+ el->el_map.help = NULL;
+ el_free(el->el_map.func);
+ el->el_map.func = NULL;
+}
+
+
+/* map_init_nls():
+ * Find all the printable keys and bind them to self insert
+ */
+static void
+map_init_nls(EditLine *el)
+{
+ int i;
+
+ el_action_t *map = el->el_map.key;
+
+ for (i = 0200; i <= 0377; i++)
+ if (iswprint(i))
+ map[i] = ED_INSERT;
+}
+
+
+/* map_init_meta():
+ * Bind all the meta keys to the appropriate ESC-<key> sequence
+ */
+static void
+map_init_meta(EditLine *el)
+{
+ wchar_t buf[3];
+ int i;
+ el_action_t *map = el->el_map.key;
+ el_action_t *alt = el->el_map.alt;
+
+ for (i = 0; i <= 0377 && map[i] != EM_META_NEXT; i++)
+ continue;
+
+ if (i > 0377) {
+ for (i = 0; i <= 0377 && alt[i] != EM_META_NEXT; i++)
+ continue;
+ if (i > 0377) {
+ i = 033;
+ if (el->el_map.type == MAP_VI)
+ map = alt;
+ } else
+ map = alt;
+ }
+ buf[0] = (wchar_t)i;
+ buf[2] = 0;
+ for (i = 0200; i <= 0377; i++)
+ switch (map[i]) {
+ case ED_INSERT:
+ case ED_UNASSIGNED:
+ case ED_SEQUENCE_LEAD_IN:
+ break;
+ default:
+ buf[1] = i & 0177;
+ keymacro_add(el, buf, keymacro_map_cmd(el, (int) map[i]), XK_CMD);
+ break;
+ }
+ map[(int) buf[0]] = ED_SEQUENCE_LEAD_IN;
+}
+
+
+/* map_init_vi():
+ * Initialize the vi bindings
+ */
+libedit_private void
+map_init_vi(EditLine *el)
+{
+ int i;
+ el_action_t *key = el->el_map.key;
+ el_action_t *alt = el->el_map.alt;
+ const el_action_t *vii = el->el_map.vii;
+ const el_action_t *vic = el->el_map.vic;
+
+ el->el_map.type = MAP_VI;
+ el->el_map.current = el->el_map.key;
+
+ keymacro_reset(el);
+
+ for (i = 0; i < N_KEYS; i++) {
+ key[i] = vii[i];
+ alt[i] = vic[i];
+ }
+
+ map_init_meta(el);
+ map_init_nls(el);
+
+ tty_bind_char(el, 1);
+ terminal_bind_arrow(el);
+}
+
+
+/* map_init_emacs():
+ * Initialize the emacs bindings
+ */
+libedit_private void
+map_init_emacs(EditLine *el)
+{
+ int i;
+ wchar_t buf[3];
+ el_action_t *key = el->el_map.key;
+ el_action_t *alt = el->el_map.alt;
+ const el_action_t *emacs = el->el_map.emacs;
+
+ el->el_map.type = MAP_EMACS;
+ el->el_map.current = el->el_map.key;
+ keymacro_reset(el);
+
+ for (i = 0; i < N_KEYS; i++) {
+ key[i] = emacs[i];
+ alt[i] = ED_UNASSIGNED;
+ }
+
+ map_init_meta(el);
+ map_init_nls(el);
+
+ buf[0] = CONTROL('X');
+ buf[1] = CONTROL('X');
+ buf[2] = 0;
+ keymacro_add(el, buf, keymacro_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD);
+
+ tty_bind_char(el, 1);
+ terminal_bind_arrow(el);
+}
+
+
+/* map_set_editor():
+ * Set the editor
+ */
+libedit_private int
+map_set_editor(EditLine *el, wchar_t *editor)
+{
+
+ if (wcscmp(editor, L"emacs") == 0) {
+ map_init_emacs(el);
+ return 0;
+ }
+ if (wcscmp(editor, L"vi") == 0) {
+ map_init_vi(el);
+ return 0;
+ }
+ return -1;
+}
+
+
+/* map_get_editor():
+ * Retrieve the editor
+ */
+libedit_private int
+map_get_editor(EditLine *el, const wchar_t **editor)
+{
+
+ if (editor == NULL)
+ return -1;
+ switch (el->el_map.type) {
+ case MAP_EMACS:
+ *editor = L"emacs";
+ return 0;
+ case MAP_VI:
+ *editor = L"vi";
+ return 0;
+ }
+ return -1;
+}
+
+
+/* map_print_key():
+ * Print the function description for 1 key
+ */
+static void
+map_print_key(EditLine *el, el_action_t *map, const wchar_t *in)
+{
+ char outbuf[EL_BUFSIZ];
+ el_bindings_t *bp, *ep;
+
+ if (in[0] == '\0' || in[1] == '\0') {
+ (void) keymacro__decode_str(in, outbuf, sizeof(outbuf), "");
+ ep = &el->el_map.help[el->el_map.nfunc];
+ for (bp = el->el_map.help; bp < ep; bp++)
+ if (bp->func == map[(unsigned char) *in]) {
+ (void) fprintf(el->el_outfile,
+ "%s\t->\t%ls\n", outbuf, bp->name);
+ return;
+ }
+ } else
+ keymacro_print(el, in);
+}
+
+
+/* map_print_some_keys():
+ * Print keys from first to last
+ */
+static void
+map_print_some_keys(EditLine *el, el_action_t *map, wint_t first, wint_t last)
+{
+ el_bindings_t *bp, *ep;
+ wchar_t firstbuf[2], lastbuf[2];
+ char unparsbuf[EL_BUFSIZ], extrabuf[EL_BUFSIZ];
+
+ firstbuf[0] = first;
+ firstbuf[1] = 0;
+ lastbuf[0] = last;
+ lastbuf[1] = 0;
+ if (map[first] == ED_UNASSIGNED) {
+ if (first == last) {
+ (void) keymacro__decode_str(firstbuf, unparsbuf,
+ sizeof(unparsbuf), STRQQ);
+ (void) fprintf(el->el_outfile,
+ "%-15s-> is undefined\n", unparsbuf);
+ }
+ return;
+ }
+ ep = &el->el_map.help[el->el_map.nfunc];
+ for (bp = el->el_map.help; bp < ep; bp++) {
+ if (bp->func == map[first]) {
+ if (first == last) {
+ (void) keymacro__decode_str(firstbuf, unparsbuf,
+ sizeof(unparsbuf), STRQQ);
+ (void) fprintf(el->el_outfile, "%-15s-> %ls\n",
+ unparsbuf, bp->name);
+ } else {
+ (void) keymacro__decode_str(firstbuf, unparsbuf,
+ sizeof(unparsbuf), STRQQ);
+ (void) keymacro__decode_str(lastbuf, extrabuf,
+ sizeof(extrabuf), STRQQ);
+ (void) fprintf(el->el_outfile,
+ "%-4s to %-7s-> %ls\n",
+ unparsbuf, extrabuf, bp->name);
+ }
+ return;
+ }
+ }
+#ifdef MAP_DEBUG
+ if (map == el->el_map.key) {
+ (void) keymacro__decode_str(firstbuf, unparsbuf,
+ sizeof(unparsbuf), STRQQ);
+ (void) fprintf(el->el_outfile,
+ "BUG!!! %s isn't bound to anything.\n", unparsbuf);
+ (void) fprintf(el->el_outfile, "el->el_map.key[%d] == %d\n",
+ first, el->el_map.key[first]);
+ } else {
+ (void) keymacro__decode_str(firstbuf, unparsbuf,
+ sizeof(unparsbuf), STRQQ);
+ (void) fprintf(el->el_outfile,
+ "BUG!!! %s isn't bound to anything.\n", unparsbuf);
+ (void) fprintf(el->el_outfile, "el->el_map.alt[%d] == %d\n",
+ first, el->el_map.alt[first]);
+ }
+#endif
+ EL_ABORT((el->el_errfile, "Error printing keys\n"));
+}
+
+
+/* map_print_all_keys():
+ * Print the function description for all keys.
+ */
+static void
+map_print_all_keys(EditLine *el)
+{
+ int prev, i;
+
+ (void) fprintf(el->el_outfile, "Standard key bindings\n");
+ prev = 0;
+ for (i = 0; i < N_KEYS; i++) {
+ if (el->el_map.key[prev] == el->el_map.key[i])
+ continue;
+ map_print_some_keys(el, el->el_map.key, prev, i - 1);
+ prev = i;
+ }
+ map_print_some_keys(el, el->el_map.key, prev, i - 1);
+
+ (void) fprintf(el->el_outfile, "Alternative key bindings\n");
+ prev = 0;
+ for (i = 0; i < N_KEYS; i++) {
+ if (el->el_map.alt[prev] == el->el_map.alt[i])
+ continue;
+ map_print_some_keys(el, el->el_map.alt, prev, i - 1);
+ prev = i;
+ }
+ map_print_some_keys(el, el->el_map.alt, prev, i - 1);
+
+ (void) fprintf(el->el_outfile, "Multi-character bindings\n");
+ keymacro_print(el, L"");
+ (void) fprintf(el->el_outfile, "Arrow key bindings\n");
+ terminal_print_arrow(el, L"");
+}
+
+
+/* map_bind():
+ * Add/remove/change bindings
+ */
+libedit_private int
+map_bind(EditLine *el, int argc, const wchar_t **argv)
+{
+ el_action_t *map;
+ int ntype, rem;
+ const wchar_t *p;
+ wchar_t inbuf[EL_BUFSIZ];
+ wchar_t outbuf[EL_BUFSIZ];
+ const wchar_t *in = NULL;
+ wchar_t *out;
+ el_bindings_t *bp, *ep;
+ int cmd;
+ int key;
+
+ if (argv == NULL)
+ return -1;
+
+ map = el->el_map.key;
+ ntype = XK_CMD;
+ key = rem = 0;
+ for (argc = 1; (p = argv[argc]) != NULL; argc++)
+ if (p[0] == '-')
+ switch (p[1]) {
+ case 'a':
+ map = el->el_map.alt;
+ break;
+
+ case 's':
+ ntype = XK_STR;
+ break;
+ case 'k':
+ key = 1;
+ break;
+
+ case 'r':
+ rem = 1;
+ break;
+
+ case 'v':
+ map_init_vi(el);
+ return 0;
+
+ case 'e':
+ map_init_emacs(el);
+ return 0;
+
+ case 'l':
+ ep = &el->el_map.help[el->el_map.nfunc];
+ for (bp = el->el_map.help; bp < ep; bp++)
+ (void) fprintf(el->el_outfile,
+ "%ls\n\t%ls\n",
+ bp->name, bp->description);
+ return 0;
+ default:
+ (void) fprintf(el->el_errfile,
+ "%ls: Invalid switch `%lc'.\n",
+ argv[0], (wint_t)p[1]);
+ }
+ else
+ break;
+
+ if (argv[argc] == NULL) {
+ map_print_all_keys(el);
+ return 0;
+ }
+ if (key)
+ in = argv[argc++];
+ else if ((in = parse__string(inbuf, argv[argc++])) == NULL) {
+ (void) fprintf(el->el_errfile,
+ "%ls: Invalid \\ or ^ in instring.\n",
+ argv[0]);
+ return -1;
+ }
+ if (rem) {
+ if (key) {
+ (void) terminal_clear_arrow(el, in);
+ return -1;
+ }
+ if (in[1])
+ (void) keymacro_delete(el, in);
+ else if (map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN)
+ (void) keymacro_delete(el, in);
+ else
+ map[(unsigned char) *in] = ED_UNASSIGNED;
+ return 0;
+ }
+ if (argv[argc] == NULL) {
+ if (key)
+ terminal_print_arrow(el, in);
+ else
+ map_print_key(el, map, in);
+ return 0;
+ }
+#ifdef notyet
+ if (argv[argc + 1] != NULL) {
+ bindkeymacro_usage();
+ return -1;
+ }
+#endif
+
+ switch (ntype) {
+ case XK_STR:
+ if ((out = parse__string(outbuf, argv[argc])) == NULL) {
+ (void) fprintf(el->el_errfile,
+ "%ls: Invalid \\ or ^ in outstring.\n", argv[0]);
+ return -1;
+ }
+ if (key)
+ terminal_set_arrow(el, in, keymacro_map_str(el, out), ntype);
+ else
+ keymacro_add(el, in, keymacro_map_str(el, out), ntype);
+ map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN;
+ break;
+
+ case XK_CMD:
+ if ((cmd = parse_cmd(el, argv[argc])) == -1) {
+ (void) fprintf(el->el_errfile,
+ "%ls: Invalid command `%ls'.\n",
+ argv[0], argv[argc]);
+ return -1;
+ }
+ if (key)
+ terminal_set_arrow(el, in, keymacro_map_cmd(el, cmd), ntype);
+ else {
+ if (in[1]) {
+ keymacro_add(el, in, keymacro_map_cmd(el, cmd), ntype);
+ map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN;
+ } else {
+ keymacro_clear(el, map, in);
+ map[(unsigned char) *in] = (el_action_t)cmd;
+ }
+ }
+ break;
+
+ /* coverity[dead_error_begin] */
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
+ break;
+ }
+ return 0;
+}
+
+
+/* map_addfunc():
+ * add a user defined function
+ */
+libedit_private int
+map_addfunc(EditLine *el, const wchar_t *name, const wchar_t *help,
+ el_func_t func)
+{
+ void *p;
+ size_t nf = el->el_map.nfunc + 1;
+
+ if (name == NULL || help == NULL || func == NULL)
+ return -1;
+
+ if ((p = el_realloc(el->el_map.func, nf *
+ sizeof(*el->el_map.func))) == NULL)
+ return -1;
+ el->el_map.func = p;
+ if ((p = el_realloc(el->el_map.help, nf * sizeof(*el->el_map.help)))
+ == NULL)
+ return -1;
+ el->el_map.help = p;
+
+ nf = (size_t)el->el_map.nfunc;
+ el->el_map.func[nf] = func;
+
+ el->el_map.help[nf].name = name;
+ el->el_map.help[nf].func = (int)nf;
+ el->el_map.help[nf].description = help;
+ el->el_map.nfunc++;
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/libedit/src/map.h b/third_party/heimdal/lib/libedit/src/map.h
new file mode 100644
index 0000000..b4e4e28
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/map.h
@@ -0,0 +1,79 @@
+/* $NetBSD: map.h,v 1.13 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)map.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.map.h: Editor maps
+ */
+#ifndef _h_el_map
+#define _h_el_map
+
+typedef el_action_t (*el_func_t)(EditLine *, wint_t);
+
+typedef struct el_bindings_t { /* for the "bind" shell command */
+ const wchar_t *name; /* function name for bind command */
+ int func; /* function numeric value */
+ const wchar_t *description; /* description of function */
+} el_bindings_t;
+
+typedef struct el_map_t {
+ el_action_t *alt; /* The current alternate key map */
+ el_action_t *key; /* The current normal key map */
+ el_action_t *current; /* The keymap we are using */
+ const el_action_t *emacs; /* The default emacs key map */
+ const el_action_t *vic; /* The vi command mode key map */
+ const el_action_t *vii; /* The vi insert mode key map */
+ int type; /* Emacs or vi */
+ el_bindings_t *help; /* The help for the editor functions */
+ el_func_t *func; /* List of available functions */
+ size_t nfunc; /* The number of functions/help items */
+} el_map_t;
+
+#define MAP_EMACS 0
+#define MAP_VI 1
+
+#define N_KEYS 256
+
+libedit_private int map_bind(EditLine *, int, const wchar_t **);
+libedit_private int map_init(EditLine *);
+libedit_private void map_end(EditLine *);
+libedit_private void map_init_vi(EditLine *);
+libedit_private void map_init_emacs(EditLine *);
+libedit_private int map_set_editor(EditLine *, wchar_t *);
+libedit_private int map_get_editor(EditLine *, const wchar_t **);
+libedit_private int map_addfunc(EditLine *, const wchar_t *, const wchar_t *,
+ el_func_t);
+
+#endif /* _h_el_map */
diff --git a/third_party/heimdal/lib/libedit/src/parse.c b/third_party/heimdal/lib/libedit/src/parse.c
new file mode 100644
index 0000000..fdd0d84
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/parse.c
@@ -0,0 +1,289 @@
+/* $NetBSD: parse.c,v 1.40 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: parse.c,v 1.40 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * parse.c: parse an editline extended command
+ *
+ * commands are:
+ *
+ * bind
+ * echotc
+ * edit
+ * gettc
+ * history
+ * settc
+ * setty
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "el.h"
+#include "parse.h"
+
+static const struct {
+ const wchar_t *name;
+ int (*func)(EditLine *, int, const wchar_t **);
+} cmds[] = {
+ { L"bind", map_bind },
+ { L"echotc", terminal_echotc },
+ { L"edit", el_editmode },
+ { L"history", hist_command },
+ { L"telltc", terminal_telltc },
+ { L"settc", terminal_settc },
+ { L"setty", tty_stty },
+ { NULL, NULL }
+};
+
+
+/* parse_line():
+ * Parse a line and dispatch it
+ */
+libedit_private int
+parse_line(EditLine *el, const wchar_t *line)
+{
+ const wchar_t **argv;
+ int argc;
+ TokenizerW *tok;
+
+ tok = tok_winit(NULL);
+ tok_wstr(tok, line, &argc, &argv);
+ argc = el_wparse(el, argc, argv);
+ tok_wend(tok);
+ return argc;
+}
+
+
+/* el_parse():
+ * Command dispatcher
+ */
+int
+el_wparse(EditLine *el, int argc, const wchar_t *argv[])
+{
+ const wchar_t *ptr;
+ int i;
+
+ if (argc < 1)
+ return -1;
+ ptr = wcschr(argv[0], L':');
+ if (ptr != NULL) {
+ wchar_t *tprog;
+ size_t l;
+
+ if (ptr == argv[0])
+ return 0;
+ l = (size_t)(ptr - argv[0] - 1);
+ tprog = el_malloc((l + 1) * sizeof(*tprog));
+ if (tprog == NULL)
+ return 0;
+ (void) wcsncpy(tprog, argv[0], l);
+ tprog[l] = '\0';
+ ptr++;
+ l = (size_t)el_match(el->el_prog, tprog);
+ el_free(tprog);
+ if (!l)
+ return 0;
+ } else
+ ptr = argv[0];
+
+ for (i = 0; cmds[i].name != NULL; i++)
+ if (wcscmp(cmds[i].name, ptr) == 0) {
+ i = (*cmds[i].func) (el, argc, argv);
+ return -i;
+ }
+ return -1;
+}
+
+
+/* parse__escape():
+ * Parse a string of the form ^<char> \<odigit> \<char> \U+xxxx and return
+ * the appropriate character or -1 if the escape is not valid
+ */
+libedit_private int
+parse__escape(const wchar_t **ptr)
+{
+ const wchar_t *p;
+ wint_t c;
+
+ p = *ptr;
+
+ if (p[1] == 0)
+ return -1;
+
+ if (*p == '\\') {
+ p++;
+ switch (*p) {
+ case 'a':
+ c = '\007'; /* Bell */
+ break;
+ case 'b':
+ c = '\010'; /* Backspace */
+ break;
+ case 't':
+ c = '\011'; /* Horizontal Tab */
+ break;
+ case 'n':
+ c = '\012'; /* New Line */
+ break;
+ case 'v':
+ c = '\013'; /* Vertical Tab */
+ break;
+ case 'f':
+ c = '\014'; /* Form Feed */
+ break;
+ case 'r':
+ c = '\015'; /* Carriage Return */
+ break;
+ case 'e':
+ c = '\033'; /* Escape */
+ break;
+ case 'U': /* Unicode \U+xxxx or \U+xxxxx format */
+ {
+ int i;
+ const wchar_t hex[] = L"0123456789ABCDEF";
+ const wchar_t *h;
+ ++p;
+ if (*p++ != '+')
+ return -1;
+ c = 0;
+ for (i = 0; i < 5; ++i) {
+ h = wcschr(hex, *p++);
+ if (!h && i < 4)
+ return -1;
+ else if (h)
+ c = (c << 4) | ((int)(h - hex));
+ else
+ --p;
+ }
+ if (c > 0x10FFFF) /* outside valid character range */
+ return -1;
+ break;
+ }
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int cnt, ch;
+
+ for (cnt = 0, c = 0; cnt < 3; cnt++) {
+ ch = *p++;
+ if (ch < '0' || ch > '7') {
+ p--;
+ break;
+ }
+ c = (c << 3) | (ch - '0');
+ }
+ if ((c & (wint_t)0xffffff00) != (wint_t)0)
+ return -1;
+ --p;
+ break;
+ }
+ default:
+ c = *p;
+ break;
+ }
+ } else if (*p == '^') {
+ p++;
+ c = (*p == '?') ? '\177' : (*p & 0237);
+ } else
+ c = *p;
+ *ptr = ++p;
+ return c;
+}
+
+/* parse__string():
+ * Parse the escapes from in and put the raw string out
+ */
+libedit_private wchar_t *
+parse__string(wchar_t *out, const wchar_t *in)
+{
+ wchar_t *rv = out;
+ int n;
+
+ for (;;)
+ switch (*in) {
+ case '\0':
+ *out = '\0';
+ return rv;
+
+ case '\\':
+ case '^':
+ if ((n = parse__escape(&in)) == -1)
+ return NULL;
+ *out++ = (wchar_t)n;
+ break;
+
+ case 'M':
+ if (in[1] == '-' && in[2] != '\0') {
+ *out++ = '\033';
+ in += 2;
+ break;
+ }
+ /*FALLTHROUGH*/
+
+ default:
+ *out++ = *in++;
+ break;
+ }
+}
+
+
+/* parse_cmd():
+ * Return the command number for the command string given
+ * or -1 if one is not found
+ */
+libedit_private int
+parse_cmd(EditLine *el, const wchar_t *cmd)
+{
+ el_bindings_t *b = el->el_map.help;
+ size_t i;
+
+ for (i = 0; i < el->el_map.nfunc; i++)
+ if (wcscmp(b[i].name, cmd) == 0)
+ return b[i].func;
+ return -1;
+}
diff --git a/third_party/heimdal/lib/libedit/src/parse.h b/third_party/heimdal/lib/libedit/src/parse.h
new file mode 100644
index 0000000..fe8eb47
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/parse.h
@@ -0,0 +1,48 @@
+/* $NetBSD: parse.h,v 1.9 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)parse.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.parse.h: Parser functions
+ */
+#ifndef _h_el_parse
+#define _h_el_parse
+
+libedit_private int parse_line(EditLine *, const wchar_t *);
+libedit_private int parse__escape(const wchar_t **);
+libedit_private wchar_t *parse__string(wchar_t *, const wchar_t *);
+libedit_private int parse_cmd(EditLine *, const wchar_t *);
+
+#endif /* _h_el_parse */
diff --git a/third_party/heimdal/lib/libedit/src/prompt.c b/third_party/heimdal/lib/libedit/src/prompt.c
new file mode 100644
index 0000000..a3d9915
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/prompt.c
@@ -0,0 +1,199 @@
+/* $NetBSD: prompt.c,v 1.26 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)prompt.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: prompt.c,v 1.26 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * prompt.c: Prompt printing functions
+ */
+#include <stdio.h>
+#include "el.h"
+
+static wchar_t *prompt_default(EditLine *);
+static wchar_t *prompt_default_r(EditLine *);
+
+/* prompt_default():
+ * Just a default prompt, in case the user did not provide one
+ */
+static wchar_t *
+/*ARGSUSED*/
+prompt_default(EditLine *el __attribute__((__unused__)))
+{
+ static wchar_t a[3] = L"? ";
+
+ return a;
+}
+
+
+/* prompt_default_r():
+ * Just a default rprompt, in case the user did not provide one
+ */
+static wchar_t *
+/*ARGSUSED*/
+prompt_default_r(EditLine *el __attribute__((__unused__)))
+{
+ static wchar_t a[1] = L"";
+
+ return a;
+}
+
+
+/* prompt_print():
+ * Print the prompt and update the prompt position.
+ */
+libedit_private void
+prompt_print(EditLine *el, int op)
+{
+ el_prompt_t *elp;
+ wchar_t *p;
+ int ignore = 0;
+
+ if (op == EL_PROMPT)
+ elp = &el->el_prompt;
+ else
+ elp = &el->el_rprompt;
+
+ if (elp->p_wide)
+ p = (*elp->p_func)(el);
+ else
+ p = ct_decode_string((char *)(void *)(*elp->p_func)(el),
+ &el->el_scratch);
+
+ for (; *p; p++) {
+ if (elp->p_ignore == *p) {
+ ignore = !ignore;
+ continue;
+ }
+ if (ignore)
+ terminal__putc(el, *p);
+ else
+ re_putc(el, *p, 1);
+ }
+
+ elp->p_pos.v = el->el_refresh.r_cursor.v;
+ elp->p_pos.h = el->el_refresh.r_cursor.h;
+}
+
+
+/* prompt_init():
+ * Initialize the prompt stuff
+ */
+libedit_private int
+prompt_init(EditLine *el)
+{
+
+ el->el_prompt.p_func = prompt_default;
+ el->el_prompt.p_pos.v = 0;
+ el->el_prompt.p_pos.h = 0;
+ el->el_prompt.p_ignore = '\0';
+ el->el_rprompt.p_func = prompt_default_r;
+ el->el_rprompt.p_pos.v = 0;
+ el->el_rprompt.p_pos.h = 0;
+ el->el_rprompt.p_ignore = '\0';
+ return 0;
+}
+
+
+/* prompt_end():
+ * Clean up the prompt stuff
+ */
+libedit_private void
+/*ARGSUSED*/
+prompt_end(EditLine *el __attribute__((__unused__)))
+{
+}
+
+
+/* prompt_set():
+ * Install a prompt printing function
+ */
+libedit_private int
+prompt_set(EditLine *el, el_pfunc_t prf, wchar_t c, int op, int wide)
+{
+ el_prompt_t *p;
+
+ if (op == EL_PROMPT || op == EL_PROMPT_ESC)
+ p = &el->el_prompt;
+ else
+ p = &el->el_rprompt;
+
+ if (prf == NULL) {
+ if (op == EL_PROMPT || op == EL_PROMPT_ESC)
+ p->p_func = prompt_default;
+ else
+ p->p_func = prompt_default_r;
+ } else {
+ p->p_func = prf;
+ }
+
+ p->p_ignore = c;
+
+ p->p_pos.v = 0;
+ p->p_pos.h = 0;
+ p->p_wide = wide;
+
+ return 0;
+}
+
+
+/* prompt_get():
+ * Retrieve the prompt printing function
+ */
+libedit_private int
+prompt_get(EditLine *el, el_pfunc_t *prf, wchar_t *c, int op)
+{
+ el_prompt_t *p;
+
+ if (prf == NULL)
+ return -1;
+
+ if (op == EL_PROMPT)
+ p = &el->el_prompt;
+ else
+ p = &el->el_rprompt;
+
+ if (prf)
+ *prf = p->p_func;
+ if (c)
+ *c = p->p_ignore;
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/libedit/src/prompt.h b/third_party/heimdal/lib/libedit/src/prompt.h
new file mode 100644
index 0000000..2931428
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/prompt.h
@@ -0,0 +1,58 @@
+/* $NetBSD: prompt.h,v 1.15 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)prompt.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.prompt.h: Prompt printing stuff
+ */
+#ifndef _h_el_prompt
+#define _h_el_prompt
+
+typedef wchar_t *(*el_pfunc_t)(EditLine *);
+
+typedef struct el_prompt_t {
+ el_pfunc_t p_func; /* Function to return the prompt */
+ coord_t p_pos; /* position in the line after prompt */
+ wchar_t p_ignore; /* character to start/end literal */
+ int p_wide;
+} el_prompt_t;
+
+libedit_private void prompt_print(EditLine *, int);
+libedit_private int prompt_set(EditLine *, el_pfunc_t, wchar_t, int, int);
+libedit_private int prompt_get(EditLine *, el_pfunc_t *, wchar_t *, int);
+libedit_private int prompt_init(EditLine *);
+libedit_private void prompt_end(EditLine *);
+
+#endif /* _h_el_prompt */
diff --git a/third_party/heimdal/lib/libedit/src/read.c b/third_party/heimdal/lib/libedit/src/read.c
new file mode 100644
index 0000000..cfab820
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/read.c
@@ -0,0 +1,628 @@
+/* $NetBSD: read.c,v 1.101 2016/05/25 13:01:11 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: read.c,v 1.101 2016/05/25 13:01:11 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * read.c: Terminal read functions
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "el.h"
+#include "fcns.h"
+#include "read.h"
+
+#define EL_MAXMACRO 10
+
+struct macros {
+ wchar_t **macro;
+ int level;
+ int offset;
+};
+
+struct el_read_t {
+ struct macros macros;
+ el_rfunc_t read_char; /* Function to read a character. */
+ int read_errno;
+};
+
+static int read__fixio(int, int);
+static int read_char(EditLine *, wchar_t *);
+static int read_getcmd(EditLine *, el_action_t *, wchar_t *);
+static void read_clearmacros(struct macros *);
+static void read_pop(struct macros *);
+static const wchar_t *noedit_wgets(EditLine *, int *);
+
+/* read_init():
+ * Initialize the read stuff
+ */
+libedit_private int
+read_init(EditLine *el)
+{
+ struct macros *ma;
+
+ if ((el->el_read = el_malloc(sizeof(*el->el_read))) == NULL)
+ return -1;
+
+ ma = &el->el_read->macros;
+ if ((ma->macro = el_malloc(EL_MAXMACRO *
+ sizeof(*ma->macro))) == NULL) {
+ free(el->el_read);
+ return -1;
+ }
+ ma->level = -1;
+ ma->offset = 0;
+
+ /* builtin read_char */
+ el->el_read->read_char = read_char;
+ return 0;
+}
+
+/* el_read_end():
+ * Free the data structures used by the read stuff.
+ */
+libedit_private void
+read_end(struct el_read_t *el_read)
+{
+ read_clearmacros(&el_read->macros);
+ el_free(el_read->macros.macro);
+ el_read->macros.macro = NULL;
+}
+
+/* el_read_setfn():
+ * Set the read char function to the one provided.
+ * If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
+ */
+libedit_private int
+el_read_setfn(struct el_read_t *el_read, el_rfunc_t rc)
+{
+ el_read->read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
+ return 0;
+}
+
+
+/* el_read_getfn():
+ * return the current read char function, or EL_BUILTIN_GETCFN
+ * if it is the default one
+ */
+libedit_private el_rfunc_t
+el_read_getfn(struct el_read_t *el_read)
+{
+ return el_read->read_char == read_char ?
+ EL_BUILTIN_GETCFN : el_read->read_char;
+}
+
+
+/* read__fixio():
+ * Try to recover from a read error
+ */
+/* ARGSUSED */
+static int
+read__fixio(int fd __attribute__((__unused__)), int e)
+{
+
+ switch (e) {
+ case -1: /* Make sure that the code is reachable */
+
+#ifdef EWOULDBLOCK
+ case EWOULDBLOCK:
+#ifndef TRY_AGAIN
+#define TRY_AGAIN
+#endif
+#endif /* EWOULDBLOCK */
+
+#if defined(POSIX) && defined(EAGAIN)
+#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
+ case EAGAIN:
+#ifndef TRY_AGAIN
+#define TRY_AGAIN
+#endif
+#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
+#endif /* POSIX && EAGAIN */
+
+ e = 0;
+#ifdef TRY_AGAIN
+#if defined(F_SETFL) && defined(O_NDELAY)
+ if ((e = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+
+ if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
+ return -1;
+ else
+ e = 1;
+#endif /* F_SETFL && O_NDELAY */
+
+#ifdef FIONBIO
+ {
+ int zero = 0;
+
+ if (ioctl(fd, FIONBIO, &zero) == -1)
+ return -1;
+ else
+ e = 1;
+ }
+#endif /* FIONBIO */
+
+#endif /* TRY_AGAIN */
+ return e ? 0 : -1;
+
+ case EINTR:
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+
+/* el_push():
+ * Push a macro
+ */
+void
+el_wpush(EditLine *el, const wchar_t *str)
+{
+ struct macros *ma = &el->el_read->macros;
+
+ if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
+ ma->level++;
+ if ((ma->macro[ma->level] = wcsdup(str)) != NULL)
+ return;
+ ma->level--;
+ }
+ terminal_beep(el);
+ terminal__flush(el);
+}
+
+
+/* read_getcmd():
+ * Get next command from the input stream,
+ * return 0 on success or -1 on EOF or error.
+ * Character values > 255 are not looked up in the map, but inserted.
+ */
+static int
+read_getcmd(EditLine *el, el_action_t *cmdnum, wchar_t *ch)
+{
+ static const wchar_t meta = (wchar_t)0x80;
+ el_action_t cmd;
+ int num;
+
+ do {
+ if ((num = el_wgetc(el, ch)) != 1)
+ return -1;
+
+#ifdef KANJI
+ if ((*ch & meta)) {
+ el->el_state.metanext = 0;
+ cmd = CcViMap[' '];
+ break;
+ } else
+#endif /* KANJI */
+
+ if (el->el_state.metanext) {
+ el->el_state.metanext = 0;
+ *ch |= meta;
+ }
+ if (*ch >= N_KEYS)
+ cmd = ED_INSERT;
+ else
+ cmd = el->el_map.current[(unsigned char) *ch];
+ if (cmd == ED_SEQUENCE_LEAD_IN) {
+ keymacro_value_t val;
+ switch (keymacro_get(el, ch, &val)) {
+ case XK_CMD:
+ cmd = val.cmd;
+ break;
+ case XK_STR:
+ el_wpush(el, val.str);
+ break;
+ case XK_NOD:
+ return -1;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
+ break;
+ }
+ }
+ } while (cmd == ED_SEQUENCE_LEAD_IN);
+ *cmdnum = cmd;
+ return 0;
+}
+
+/* read_char():
+ * Read a character from the tty.
+ */
+static int
+read_char(EditLine *el, wchar_t *cp)
+{
+ ssize_t num_read;
+ int tried = 0;
+ char cbuf[MB_LEN_MAX];
+ size_t cbp = 0;
+ int save_errno = errno;
+
+ again:
+ el->el_signal->sig_no = 0;
+ while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) {
+ int e = errno;
+ switch (el->el_signal->sig_no) {
+ case SIGCONT:
+ el_wset(el, EL_REFRESH);
+ /*FALLTHROUGH*/
+ case SIGWINCH:
+ sig_set(el);
+ goto again;
+ default:
+ break;
+ }
+ if (!tried && read__fixio(el->el_infd, e) == 0) {
+ errno = save_errno;
+ tried = 1;
+ } else {
+ errno = e;
+ *cp = L'\0';
+ return -1;
+ }
+ }
+
+ /* Test for EOF */
+ if (num_read == 0) {
+ *cp = L'\0';
+ return 0;
+ }
+
+ for (;;) {
+ mbstate_t mbs;
+
+ ++cbp;
+ /* This only works because UTF8 is stateless. */
+ memset(&mbs, 0, sizeof(mbs));
+ switch (mbrtowc(cp, cbuf, cbp, &mbs)) {
+ case (size_t)-1:
+ if (cbp > 1) {
+ /*
+ * Invalid sequence, discard all bytes
+ * except the last one.
+ */
+ cbuf[0] = cbuf[cbp - 1];
+ cbp = 0;
+ break;
+ } else {
+ /* Invalid byte, discard it. */
+ cbp = 0;
+ goto again;
+ }
+ case (size_t)-2:
+ /*
+ * We don't support other multibyte charsets.
+ * The second condition shouldn't happen
+ * and is here merely for additional safety.
+ */
+ if ((el->el_flags & CHARSET_IS_UTF8) == 0 ||
+ cbp >= MB_LEN_MAX) {
+ errno = EILSEQ;
+ *cp = L'\0';
+ return -1;
+ }
+ /* Incomplete sequence, read another byte. */
+ goto again;
+ default:
+ /* Valid character, process it. */
+ return 1;
+ }
+ }
+}
+
+/* read_pop():
+ * Pop a macro from the stack
+ */
+static void
+read_pop(struct macros *ma)
+{
+ int i;
+
+ el_free(ma->macro[0]);
+ for (i = 0; i < ma->level; i++)
+ ma->macro[i] = ma->macro[i + 1];
+ ma->level--;
+ ma->offset = 0;
+}
+
+static void
+read_clearmacros(struct macros *ma)
+{
+ while (ma->level >= 0)
+ el_free(ma->macro[ma->level--]);
+ ma->offset = 0;
+}
+
+/* el_wgetc():
+ * Read a wide character
+ */
+int
+el_wgetc(EditLine *el, wchar_t *cp)
+{
+ struct macros *ma = &el->el_read->macros;
+ int num_read;
+
+ terminal__flush(el);
+ for (;;) {
+ if (ma->level < 0)
+ break;
+
+ if (ma->macro[0][ma->offset] == '\0') {
+ read_pop(ma);
+ continue;
+ }
+
+ *cp = ma->macro[0][ma->offset++];
+
+ if (ma->macro[0][ma->offset] == '\0') {
+ /* Needed for QuoteMode On */
+ read_pop(ma);
+ }
+
+ return 1;
+ }
+
+ if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
+ return 0;
+
+ num_read = (*el->el_read->read_char)(el, cp);
+
+ /*
+ * Remember the original reason of a read failure
+ * such that el_wgets() can restore it after doing
+ * various cleanup operation that might change errno.
+ */
+ if (num_read < 0)
+ el->el_read->read_errno = errno;
+
+ return num_read;
+}
+
+libedit_private void
+read_prepare(EditLine *el)
+{
+ if (el->el_flags & HANDLE_SIGNALS)
+ sig_set(el);
+ if (el->el_flags & NO_TTY)
+ return;
+ if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
+ tty_rawmode(el);
+
+ /* This is relatively cheap, and things go terribly wrong if
+ we have the wrong size. */
+ el_resize(el);
+ re_clear_display(el); /* reset the display stuff */
+ ch_reset(el);
+ re_refresh(el); /* print the prompt */
+
+ if (el->el_flags & UNBUFFERED)
+ terminal__flush(el);
+}
+
+libedit_private void
+read_finish(EditLine *el)
+{
+ if ((el->el_flags & UNBUFFERED) == 0)
+ (void) tty_cookedmode(el);
+ if (el->el_flags & HANDLE_SIGNALS)
+ sig_clr(el);
+}
+
+static const wchar_t *
+noedit_wgets(EditLine *el, int *nread)
+{
+ el_line_t *lp = &el->el_line;
+ int num;
+
+ while ((num = (*el->el_read->read_char)(el, lp->lastchar)) == 1) {
+ if (lp->lastchar + 1 >= lp->limit &&
+ !ch_enlargebufs(el, (size_t)2))
+ break;
+ lp->lastchar++;
+ if (el->el_flags & UNBUFFERED ||
+ lp->lastchar[-1] == '\r' ||
+ lp->lastchar[-1] == '\n')
+ break;
+ }
+ if (num == -1 && errno == EINTR)
+ lp->lastchar = lp->buffer;
+ lp->cursor = lp->lastchar;
+ *lp->lastchar = '\0';
+ *nread = (int)(lp->lastchar - lp->buffer);
+ return *nread ? lp->buffer : NULL;
+}
+
+const wchar_t *
+el_wgets(EditLine *el, int *nread)
+{
+ int retval;
+ el_action_t cmdnum = 0;
+ int num; /* how many chars we have read at NL */
+ wchar_t ch;
+ int nrb;
+
+ if (nread == NULL)
+ nread = &nrb;
+ *nread = 0;
+ el->el_read->read_errno = 0;
+
+ if (el->el_flags & NO_TTY) {
+ el->el_line.lastchar = el->el_line.buffer;
+ return noedit_wgets(el, nread);
+ }
+
+#ifdef FIONREAD
+ if (el->el_tty.t_mode == EX_IO && el->el_read->macros.level < 0) {
+ int chrs = 0;
+
+ (void) ioctl(el->el_infd, FIONREAD, &chrs);
+ if (chrs == 0) {
+ if (tty_rawmode(el) < 0) {
+ errno = 0;
+ *nread = 0;
+ return NULL;
+ }
+ }
+ }
+#endif /* FIONREAD */
+
+ if ((el->el_flags & UNBUFFERED) == 0)
+ read_prepare(el);
+
+ if (el->el_flags & EDIT_DISABLED) {
+ if ((el->el_flags & UNBUFFERED) == 0)
+ el->el_line.lastchar = el->el_line.buffer;
+ terminal__flush(el);
+ return noedit_wgets(el, nread);
+ }
+
+ for (num = -1; num == -1;) { /* while still editing this line */
+ /* if EOF or error */
+ if (read_getcmd(el, &cmdnum, &ch) == -1)
+ break;
+ if ((size_t)cmdnum >= el->el_map.nfunc) /* BUG CHECK command */
+ continue; /* try again */
+ /* now do the real command */
+ /* vi redo needs these way down the levels... */
+ el->el_state.thiscmd = cmdnum;
+ el->el_state.thisch = ch;
+ if (el->el_map.type == MAP_VI &&
+ el->el_map.current == el->el_map.key &&
+ el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
+ if (cmdnum == VI_DELETE_PREV_CHAR &&
+ el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
+ && iswprint(el->el_chared.c_redo.pos[-1]))
+ el->el_chared.c_redo.pos--;
+ else
+ *el->el_chared.c_redo.pos++ = ch;
+ }
+ retval = (*el->el_map.func[cmdnum]) (el, ch);
+
+ /* save the last command here */
+ el->el_state.lastcmd = cmdnum;
+
+ /* use any return value */
+ switch (retval) {
+ case CC_CURSOR:
+ re_refresh_cursor(el);
+ break;
+
+ case CC_REDISPLAY:
+ re_clear_lines(el);
+ re_clear_display(el);
+ /* FALLTHROUGH */
+
+ case CC_REFRESH:
+ re_refresh(el);
+ break;
+
+ case CC_REFRESH_BEEP:
+ re_refresh(el);
+ terminal_beep(el);
+ break;
+
+ case CC_NORM: /* normal char */
+ break;
+
+ case CC_ARGHACK: /* Suggested by Rich Salz */
+ /* <rsalz@pineapple.bbn.com> */
+ continue; /* keep going... */
+
+ case CC_EOF: /* end of file typed */
+ if ((el->el_flags & UNBUFFERED) == 0)
+ num = 0;
+ else if (num == -1) {
+ *el->el_line.lastchar++ = CONTROL('d');
+ el->el_line.cursor = el->el_line.lastchar;
+ num = 1;
+ }
+ break;
+
+ case CC_NEWLINE: /* normal end of line */
+ num = (int)(el->el_line.lastchar - el->el_line.buffer);
+ break;
+
+ case CC_FATAL: /* fatal error, reset to known state */
+ /* put (real) cursor in a known place */
+ re_clear_display(el); /* reset the display stuff */
+ ch_reset(el); /* reset the input pointers */
+ read_clearmacros(&el->el_read->macros);
+ re_refresh(el); /* print the prompt again */
+ break;
+
+ case CC_ERROR:
+ default: /* functions we don't know about */
+ terminal_beep(el);
+ terminal__flush(el);
+ break;
+ }
+ el->el_state.argument = 1;
+ el->el_state.doingarg = 0;
+ el->el_chared.c_vcmd.action = NOP;
+ if (el->el_flags & UNBUFFERED)
+ break;
+ }
+
+ terminal__flush(el); /* flush any buffered output */
+ /* make sure the tty is set up correctly */
+ if ((el->el_flags & UNBUFFERED) == 0) {
+ read_finish(el);
+ *nread = num != -1 ? num : 0;
+ } else
+ *nread = (int)(el->el_line.lastchar - el->el_line.buffer);
+
+ if (*nread == 0) {
+ if (num == -1) {
+ *nread = -1;
+ if (el->el_read->read_errno)
+ errno = el->el_read->read_errno;
+ }
+ return NULL;
+ } else
+ return el->el_line.buffer;
+}
diff --git a/third_party/heimdal/lib/libedit/src/read.h b/third_party/heimdal/lib/libedit/src/read.h
new file mode 100644
index 0000000..1acf5d6
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/read.h
@@ -0,0 +1,45 @@
+/* $NetBSD: read.h,v 1.12 2016/05/22 19:44:26 christos Exp $ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Anthony Mallet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * el.read.h: Character reading functions
+ */
+#ifndef _h_el_read
+#define _h_el_read
+
+libedit_private int read_init(EditLine *);
+libedit_private void read_end(struct el_read_t *);
+libedit_private void read_prepare(EditLine *);
+libedit_private void read_finish(EditLine *);
+libedit_private int el_read_setfn(struct el_read_t *, el_rfunc_t);
+libedit_private el_rfunc_t el_read_getfn(struct el_read_t *);
+
+#endif /* _h_el_read */
diff --git a/third_party/heimdal/lib/libedit/src/readline.c b/third_party/heimdal/lib/libedit/src/readline.c
new file mode 100644
index 0000000..f4e0a39
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/readline.c
@@ -0,0 +1,2367 @@
+/* $NetBSD: readline.c,v 1.139 2016/10/28 18:32:26 christos Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jaromir Dolecek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+__RCSID("$NetBSD: readline.c,v 1.139 2016/10/28 18:32:26 christos Exp $");
+#endif /* not lint && not SCCSID */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+
+#include "readline/readline.h"
+#include "el.h"
+#include "fcns.h"
+#include "filecomplete.h"
+
+void rl_prep_terminal(int);
+void rl_deprep_terminal(void);
+
+/* for rl_complete() */
+#define TAB '\r'
+
+/* see comment at the #ifdef for sense of this */
+/* #define GDB_411_HACK */
+
+/* readline compatibility stuff - look at readline sources/documentation */
+/* to see what these variables mean */
+const char *rl_library_version = "EditLine wrapper";
+int rl_readline_version = RL_READLINE_VERSION;
+static char empty[] = { '\0' };
+static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' };
+static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$',
+ '>', '<', '=', ';', '|', '&', '{', '(', '\0' };
+char *rl_readline_name = empty;
+FILE *rl_instream = NULL;
+FILE *rl_outstream = NULL;
+int rl_point = 0;
+int rl_end = 0;
+char *rl_line_buffer = NULL;
+rl_vcpfunc_t *rl_linefunc = NULL;
+int rl_done = 0;
+VFunction *rl_event_hook = NULL;
+KEYMAP_ENTRY_ARRAY emacs_standard_keymap,
+ emacs_meta_keymap,
+ emacs_ctlx_keymap;
+/*
+ * The following is not implemented; we always catch signals in the
+ * libedit fashion: set handlers on entry to el_gets() and clear them
+ * on the way out. This simplistic approach works for most cases; if
+ * it does not work for your application, please let us know.
+ */
+int rl_catch_signals = 1;
+int rl_catch_sigwinch = 1;
+
+int history_base = 1; /* probably never subject to change */
+int history_length = 0;
+int history_offset = 0;
+int max_input_history = 0;
+char history_expansion_char = '!';
+char history_subst_char = '^';
+char *history_no_expand_chars = expand_chars;
+Function *history_inhibit_expansion_function = NULL;
+char *history_arg_extract(int start, int end, const char *str);
+
+int rl_inhibit_completion = 0;
+int rl_attempted_completion_over = 0;
+char *rl_basic_word_break_characters = break_chars;
+char *rl_completer_word_break_characters = NULL;
+char *rl_completer_quote_characters = NULL;
+rl_compentry_func_t *rl_completion_entry_function = NULL;
+char *(*rl_completion_word_break_hook)(void) = NULL;
+rl_completion_func_t *rl_attempted_completion_function = NULL;
+Function *rl_pre_input_hook = NULL;
+Function *rl_startup1_hook = NULL;
+int (*rl_getc_function)(FILE *) = NULL;
+char *rl_terminal_name = NULL;
+int rl_already_prompted = 0;
+int rl_filename_completion_desired = 0;
+int rl_ignore_completion_duplicates = 0;
+int readline_echoing_p = 1;
+int _rl_print_completions_horizontally = 0;
+VFunction *rl_redisplay_function = NULL;
+Function *rl_startup_hook = NULL;
+VFunction *rl_completion_display_matches_hook = NULL;
+VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal;
+VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal;
+KEYMAP_ENTRY_ARRAY emacs_meta_keymap;
+
+/*
+ * The current prompt string.
+ */
+char *rl_prompt = NULL;
+/*
+ * This is set to character indicating type of completion being done by
+ * rl_complete_internal(); this is available for application completion
+ * functions.
+ */
+int rl_completion_type = 0;
+
+/*
+ * If more than this number of items results from query for possible
+ * completions, we ask user if they are sure to really display the list.
+ */
+int rl_completion_query_items = 100;
+
+/*
+ * List of characters which are word break characters, but should be left
+ * in the parsed text when it is passed to the completion function.
+ * Shell uses this to help determine what kind of completing to do.
+ */
+char *rl_special_prefixes = NULL;
+
+/*
+ * This is the character appended to the completed words if at the end of
+ * the line. Default is ' ' (a space).
+ */
+int rl_completion_append_character = ' ';
+
+/* stuff below is used internally by libedit for readline emulation */
+
+static History *h = NULL;
+static EditLine *e = NULL;
+static rl_command_func_t *map[256];
+static jmp_buf topbuf;
+
+/* internal functions */
+static unsigned char _el_rl_complete(EditLine *, int);
+static unsigned char _el_rl_tstp(EditLine *, int);
+static char *_get_prompt(EditLine *);
+static int _getc_function(EditLine *, wchar_t *);
+static int _history_expand_command(const char *, size_t, size_t,
+ char **);
+static char *_rl_compat_sub(const char *, const char *,
+ const char *, int);
+static int _rl_event_read_char(EditLine *, wchar_t *);
+static void _rl_update_pos(void);
+
+static HIST_ENTRY rl_he;
+
+/* ARGSUSED */
+static char *
+_get_prompt(EditLine *el __attribute__((__unused__)))
+{
+ rl_already_prompted = 1;
+ return rl_prompt;
+}
+
+
+/*
+ * read one key from user defined input function
+ */
+static int
+/*ARGSUSED*/
+_getc_function(EditLine *el __attribute__((__unused__)), wchar_t *c)
+{
+ int i;
+
+ i = (*rl_getc_function)(rl_instream);
+ if (i == -1)
+ return 0;
+ *c = (wchar_t)i;
+ return 1;
+}
+
+static void
+_resize_fun(EditLine *el, void *a)
+{
+ const LineInfo *li;
+ char **ap = a;
+
+ li = el_line(el);
+ /* a cheesy way to get rid of const cast. */
+ *ap = memchr(li->buffer, *li->buffer, (size_t)1);
+}
+
+static const char *
+_default_history_file(void)
+{
+ struct passwd *p;
+ static char *path;
+ size_t len;
+
+ if (path)
+ return path;
+
+ if ((p = getpwuid(getuid())) == NULL)
+ return NULL;
+
+ len = strlen(p->pw_dir) + sizeof("/.history");
+ if ((path = malloc(len)) == NULL)
+ return NULL;
+
+ (void)snprintf(path, len, "%s/.history", p->pw_dir);
+ return path;
+}
+
+/*
+ * READLINE compatibility stuff
+ */
+
+/*
+ * Set the prompt
+ */
+int
+rl_set_prompt(const char *prompt)
+{
+ char *p;
+
+ if (!prompt)
+ prompt = "";
+ if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0)
+ return 0;
+ if (rl_prompt)
+ el_free(rl_prompt);
+ rl_prompt = strdup(prompt);
+ if (rl_prompt == NULL)
+ return -1;
+
+ while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL)
+ *p = RL_PROMPT_START_IGNORE;
+
+ return 0;
+}
+
+/*
+ * initialize rl compat stuff
+ */
+int
+rl_initialize(void)
+{
+ HistEvent ev;
+ int editmode = 1;
+ struct termios t;
+
+ if (e != NULL)
+ el_end(e);
+ if (h != NULL)
+ history_end(h);
+
+ if (!rl_instream)
+ rl_instream = stdin;
+ if (!rl_outstream)
+ rl_outstream = stdout;
+
+ /*
+ * See if we don't really want to run the editor
+ */
+ if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0)
+ editmode = 0;
+
+ e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr);
+
+ if (!editmode)
+ el_set(e, EL_EDITMODE, 0);
+
+ h = history_init();
+ if (!e || !h)
+ return -1;
+
+ history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */
+ history_length = 0;
+ max_input_history = INT_MAX;
+ el_set(e, EL_HIST, history, h);
+
+ /* Setup resize function */
+ el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer);
+
+ /* setup getc function if valid */
+ if (rl_getc_function)
+ el_set(e, EL_GETCFN, _getc_function);
+
+ /* for proper prompt printing in readline() */
+ if (rl_set_prompt("") == -1) {
+ history_end(h);
+ el_end(e);
+ return -1;
+ }
+ el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE);
+ el_set(e, EL_SIGNAL, rl_catch_signals);
+
+ /* set default mode to "emacs"-style and read setting afterwards */
+ /* so this can be overridden */
+ el_set(e, EL_EDITOR, "emacs");
+ if (rl_terminal_name != NULL)
+ el_set(e, EL_TERMINAL, rl_terminal_name);
+ else
+ el_get(e, EL_TERMINAL, &rl_terminal_name);
+
+ /*
+ * Word completion - this has to go AFTER rebinding keys
+ * to emacs-style.
+ */
+ el_set(e, EL_ADDFN, "rl_complete",
+ "ReadLine compatible completion function",
+ _el_rl_complete);
+ el_set(e, EL_BIND, "^I", "rl_complete", NULL);
+
+ /*
+ * Send TSTP when ^Z is pressed.
+ */
+ el_set(e, EL_ADDFN, "rl_tstp",
+ "ReadLine compatible suspend function",
+ _el_rl_tstp);
+ el_set(e, EL_BIND, "^Z", "rl_tstp", NULL);
+
+ /*
+ * Set some readline compatible key-bindings.
+ */
+ el_set(e, EL_BIND, "^R", "em-inc-search-prev", NULL);
+
+ /*
+ * Allow the use of Home/End keys.
+ */
+ el_set(e, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
+ el_set(e, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
+ el_set(e, EL_BIND, "\\e[7~", "ed-move-to-beg", NULL);
+ el_set(e, EL_BIND, "\\e[8~", "ed-move-to-end", NULL);
+ el_set(e, EL_BIND, "\\e[H", "ed-move-to-beg", NULL);
+ el_set(e, EL_BIND, "\\e[F", "ed-move-to-end", NULL);
+
+ /*
+ * Allow the use of the Delete/Insert keys.
+ */
+ el_set(e, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
+ el_set(e, EL_BIND, "\\e[2~", "ed-quoted-insert", NULL);
+
+ /*
+ * Ctrl-left-arrow and Ctrl-right-arrow for word moving.
+ */
+ el_set(e, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
+ el_set(e, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
+ el_set(e, EL_BIND, "\\e[5C", "em-next-word", NULL);
+ el_set(e, EL_BIND, "\\e[5D", "ed-prev-word", NULL);
+ el_set(e, EL_BIND, "\\e\\e[C", "em-next-word", NULL);
+ el_set(e, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
+
+ /* read settings from configuration file */
+ el_source(e, NULL);
+
+ /*
+ * Unfortunately, some applications really do use rl_point
+ * and rl_line_buffer directly.
+ */
+ _resize_fun(e, &rl_line_buffer);
+ _rl_update_pos();
+
+ if (rl_startup_hook)
+ (*rl_startup_hook)(NULL, 0);
+
+ return 0;
+}
+
+
+/*
+ * read one line from input stream and return it, chomping
+ * trailing newline (if there is any)
+ */
+char *
+readline(const char *p)
+{
+ HistEvent ev;
+ const char * volatile prompt = p;
+ int count;
+ const char *ret;
+ char *buf;
+ static int used_event_hook;
+
+ if (e == NULL || h == NULL)
+ rl_initialize();
+
+ rl_done = 0;
+
+ (void)setjmp(topbuf);
+
+ /* update prompt accordingly to what has been passed */
+ if (rl_set_prompt(prompt) == -1)
+ return NULL;
+
+ if (rl_pre_input_hook)
+ (*rl_pre_input_hook)(NULL, 0);
+
+ if (rl_event_hook && !(e->el_flags&NO_TTY)) {
+ el_set(e, EL_GETCFN, _rl_event_read_char);
+ used_event_hook = 1;
+ }
+
+ if (!rl_event_hook && used_event_hook) {
+ el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN);
+ used_event_hook = 0;
+ }
+
+ rl_already_prompted = 0;
+
+ /* get one line from input stream */
+ ret = el_gets(e, &count);
+
+ if (ret && count > 0) {
+ int lastidx;
+
+ buf = strdup(ret);
+ if (buf == NULL)
+ return NULL;
+ lastidx = count - 1;
+ if (buf[lastidx] == '\n')
+ buf[lastidx] = '\0';
+ } else
+ buf = NULL;
+
+ history(h, &ev, H_GETSIZE);
+ history_length = ev.num;
+
+ return buf;
+}
+
+/*
+ * history functions
+ */
+
+/*
+ * is normally called before application starts to use
+ * history expansion functions
+ */
+void
+using_history(void)
+{
+ if (h == NULL || e == NULL)
+ rl_initialize();
+ history_offset = history_length;
+}
+
+
+/*
+ * substitute ``what'' with ``with'', returning resulting string; if
+ * globally == 1, substitutes all occurrences of what, otherwise only the
+ * first one
+ */
+static char *
+_rl_compat_sub(const char *str, const char *what, const char *with,
+ int globally)
+{
+ const char *s;
+ char *r, *result;
+ size_t len, with_len, what_len;
+
+ len = strlen(str);
+ with_len = strlen(with);
+ what_len = strlen(what);
+
+ /* calculate length we need for result */
+ s = str;
+ while (*s) {
+ if (*s == *what && !strncmp(s, what, what_len)) {
+ len += with_len - what_len;
+ if (!globally)
+ break;
+ s += what_len;
+ } else
+ s++;
+ }
+ r = result = el_malloc((len + 1) * sizeof(*r));
+ if (result == NULL)
+ return NULL;
+ s = str;
+ while (*s) {
+ if (*s == *what && !strncmp(s, what, what_len)) {
+ (void)strncpy(r, with, with_len);
+ r += with_len;
+ s += what_len;
+ if (!globally) {
+ (void)strcpy(r, s);
+ return result;
+ }
+ } else
+ *r++ = *s++;
+ }
+ *r = '\0';
+ return result;
+}
+
+static char *last_search_pat; /* last !?pat[?] search pattern */
+static char *last_search_match; /* last !?pat[?] that matched */
+
+const char *
+get_history_event(const char *cmd, int *cindex, int qchar)
+{
+ int idx, sign, sub, num, begin, ret;
+ size_t len;
+ char *pat;
+ const char *rptr;
+ HistEvent ev;
+
+ idx = *cindex;
+ if (cmd[idx++] != history_expansion_char)
+ return NULL;
+
+ /* find out which event to take */
+ if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') {
+ if (history(h, &ev, H_FIRST) != 0)
+ return NULL;
+ *cindex = cmd[idx]? (idx + 1):idx;
+ return ev.str;
+ }
+ sign = 0;
+ if (cmd[idx] == '-') {
+ sign = 1;
+ idx++;
+ }
+
+ if ('0' <= cmd[idx] && cmd[idx] <= '9') {
+ HIST_ENTRY *he;
+
+ num = 0;
+ while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') {
+ num = num * 10 + cmd[idx] - '0';
+ idx++;
+ }
+ if (sign)
+ num = history_length - num + 1;
+
+ if (!(he = history_get(num)))
+ return NULL;
+
+ *cindex = idx;
+ return he->line;
+ }
+ sub = 0;
+ if (cmd[idx] == '?') {
+ sub = 1;
+ idx++;
+ }
+ begin = idx;
+ while (cmd[idx]) {
+ if (cmd[idx] == '\n')
+ break;
+ if (sub && cmd[idx] == '?')
+ break;
+ if (!sub && (cmd[idx] == ':' || cmd[idx] == ' '
+ || cmd[idx] == '\t' || cmd[idx] == qchar))
+ break;
+ idx++;
+ }
+ len = (size_t)idx - (size_t)begin;
+ if (sub && cmd[idx] == '?')
+ idx++;
+ if (sub && len == 0 && last_search_pat && *last_search_pat)
+ pat = last_search_pat;
+ else if (len == 0)
+ return NULL;
+ else {
+ if ((pat = el_malloc((len + 1) * sizeof(*pat))) == NULL)
+ return NULL;
+ (void)strncpy(pat, cmd + begin, len);
+ pat[len] = '\0';
+ }
+
+ if (history(h, &ev, H_CURR) != 0) {
+ if (pat != last_search_pat)
+ el_free(pat);
+ return NULL;
+ }
+ num = ev.num;
+
+ if (sub) {
+ if (pat != last_search_pat) {
+ if (last_search_pat)
+ el_free(last_search_pat);
+ last_search_pat = pat;
+ }
+ ret = history_search(pat, -1);
+ } else
+ ret = history_search_prefix(pat, -1);
+
+ if (ret == -1) {
+ /* restore to end of list on failed search */
+ history(h, &ev, H_FIRST);
+ (void)fprintf(rl_outstream, "%s: Event not found\n", pat);
+ if (pat != last_search_pat)
+ el_free(pat);
+ return NULL;
+ }
+
+ if (sub && len) {
+ if (last_search_match && last_search_match != pat)
+ el_free(last_search_match);
+ last_search_match = pat;
+ }
+
+ if (pat != last_search_pat)
+ el_free(pat);
+
+ if (history(h, &ev, H_CURR) != 0)
+ return NULL;
+ *cindex = idx;
+ rptr = ev.str;
+
+ /* roll back to original position */
+ (void)history(h, &ev, H_SET, num);
+
+ return rptr;
+}
+
+/*
+ * the real function doing history expansion - takes as argument command
+ * to do and data upon which the command should be executed
+ * does expansion the way I've understood readline documentation
+ *
+ * returns 0 if data was not modified, 1 if it was and 2 if the string
+ * should be only printed and not executed; in case of error,
+ * returns -1 and *result points to NULL
+ * it's the caller's responsibility to free() the string returned in *result
+ */
+static int
+_history_expand_command(const char *command, size_t offs, size_t cmdlen,
+ char **result)
+{
+ char *tmp, *search = NULL, *aptr;
+ const char *ptr, *cmd;
+ static char *from = NULL, *to = NULL;
+ int start, end, idx, has_mods = 0;
+ int p_on = 0, g_on = 0;
+
+ *result = NULL;
+ aptr = NULL;
+ ptr = NULL;
+
+ /* First get event specifier */
+ idx = 0;
+
+ if (strchr(":^*$", command[offs + 1])) {
+ char str[4];
+ /*
+ * "!:" is shorthand for "!!:".
+ * "!^", "!*" and "!$" are shorthand for
+ * "!!:^", "!!:*" and "!!:$" respectively.
+ */
+ str[0] = str[1] = '!';
+ str[2] = '0';
+ ptr = get_history_event(str, &idx, 0);
+ idx = (command[offs + 1] == ':')? 1:0;
+ has_mods = 1;
+ } else {
+ if (command[offs + 1] == '#') {
+ /* use command so far */
+ if ((aptr = el_malloc((offs + 1) * sizeof(*aptr)))
+ == NULL)
+ return -1;
+ (void)strncpy(aptr, command, offs);
+ aptr[offs] = '\0';
+ idx = 1;
+ } else {
+ int qchar;
+
+ qchar = (offs > 0 && command[offs - 1] == '"')? '"':0;
+ ptr = get_history_event(command + offs, &idx, qchar);
+ }
+ has_mods = command[offs + (size_t)idx] == ':';
+ }
+
+ if (ptr == NULL && aptr == NULL)
+ return -1;
+
+ if (!has_mods) {
+ *result = strdup(aptr ? aptr : ptr);
+ if (aptr)
+ el_free(aptr);
+ if (*result == NULL)
+ return -1;
+ return 1;
+ }
+
+ cmd = command + offs + idx + 1;
+
+ /* Now parse any word designators */
+
+ if (*cmd == '%') /* last word matched by ?pat? */
+ tmp = strdup(last_search_match? last_search_match:"");
+ else if (strchr("^*$-0123456789", *cmd)) {
+ start = end = -1;
+ if (*cmd == '^')
+ start = end = 1, cmd++;
+ else if (*cmd == '$')
+ start = -1, cmd++;
+ else if (*cmd == '*')
+ start = 1, cmd++;
+ else if (*cmd == '-' || isdigit((unsigned char) *cmd)) {
+ start = 0;
+ while (*cmd && '0' <= *cmd && *cmd <= '9')
+ start = start * 10 + *cmd++ - '0';
+
+ if (*cmd == '-') {
+ if (isdigit((unsigned char) cmd[1])) {
+ cmd++;
+ end = 0;
+ while (*cmd && '0' <= *cmd && *cmd <= '9')
+ end = end * 10 + *cmd++ - '0';
+ } else if (cmd[1] == '$') {
+ cmd += 2;
+ end = -1;
+ } else {
+ cmd++;
+ end = -2;
+ }
+ } else if (*cmd == '*')
+ end = -1, cmd++;
+ else
+ end = start;
+ }
+ tmp = history_arg_extract(start, end, aptr? aptr:ptr);
+ if (tmp == NULL) {
+ (void)fprintf(rl_outstream, "%s: Bad word specifier",
+ command + offs + idx);
+ if (aptr)
+ el_free(aptr);
+ return -1;
+ }
+ } else
+ tmp = strdup(aptr? aptr:ptr);
+
+ if (aptr)
+ el_free(aptr);
+
+ if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) {
+ *result = tmp;
+ return 1;
+ }
+
+ for (; *cmd; cmd++) {
+ if (*cmd == ':')
+ continue;
+ else if (*cmd == 'h') { /* remove trailing path */
+ if ((aptr = strrchr(tmp, '/')) != NULL)
+ *aptr = '\0';
+ } else if (*cmd == 't') { /* remove leading path */
+ if ((aptr = strrchr(tmp, '/')) != NULL) {
+ aptr = strdup(aptr + 1);
+ el_free(tmp);
+ tmp = aptr;
+ }
+ } else if (*cmd == 'r') { /* remove trailing suffix */
+ if ((aptr = strrchr(tmp, '.')) != NULL)
+ *aptr = '\0';
+ } else if (*cmd == 'e') { /* remove all but suffix */
+ if ((aptr = strrchr(tmp, '.')) != NULL) {
+ aptr = strdup(aptr);
+ el_free(tmp);
+ tmp = aptr;
+ }
+ } else if (*cmd == 'p') /* print only */
+ p_on = 1;
+ else if (*cmd == 'g')
+ g_on = 2;
+ else if (*cmd == 's' || *cmd == '&') {
+ char *what, *with, delim;
+ size_t len, from_len;
+ size_t size;
+
+ if (*cmd == '&' && (from == NULL || to == NULL))
+ continue;
+ else if (*cmd == 's') {
+ delim = *(++cmd), cmd++;
+ size = 16;
+ what = el_realloc(from, size * sizeof(*what));
+ if (what == NULL) {
+ el_free(from);
+ el_free(tmp);
+ return 0;
+ }
+ len = 0;
+ for (; *cmd && *cmd != delim; cmd++) {
+ if (*cmd == '\\' && cmd[1] == delim)
+ cmd++;
+ if (len >= size) {
+ char *nwhat;
+ nwhat = el_realloc(what,
+ (size <<= 1) *
+ sizeof(*nwhat));
+ if (nwhat == NULL) {
+ el_free(what);
+ el_free(tmp);
+ return 0;
+ }
+ what = nwhat;
+ }
+ what[len++] = *cmd;
+ }
+ what[len] = '\0';
+ from = what;
+ if (*what == '\0') {
+ el_free(what);
+ if (search) {
+ from = strdup(search);
+ if (from == NULL) {
+ el_free(tmp);
+ return 0;
+ }
+ } else {
+ from = NULL;
+ el_free(tmp);
+ return -1;
+ }
+ }
+ cmd++; /* shift after delim */
+ if (!*cmd)
+ continue;
+
+ size = 16;
+ with = el_realloc(to, size * sizeof(*with));
+ if (with == NULL) {
+ el_free(to);
+ el_free(tmp);
+ return -1;
+ }
+ len = 0;
+ from_len = strlen(from);
+ for (; *cmd && *cmd != delim; cmd++) {
+ if (len + from_len + 1 >= size) {
+ char *nwith;
+ size += from_len + 1;
+ nwith = el_realloc(with,
+ size * sizeof(*nwith));
+ if (nwith == NULL) {
+ el_free(with);
+ el_free(tmp);
+ return -1;
+ }
+ with = nwith;
+ }
+ if (*cmd == '&') {
+ /* safe */
+ (void)strcpy(&with[len], from);
+ len += from_len;
+ continue;
+ }
+ if (*cmd == '\\'
+ && (*(cmd + 1) == delim
+ || *(cmd + 1) == '&'))
+ cmd++;
+ with[len++] = *cmd;
+ }
+ with[len] = '\0';
+ to = with;
+ }
+
+ aptr = _rl_compat_sub(tmp, from, to, g_on);
+ if (aptr) {
+ el_free(tmp);
+ tmp = aptr;
+ }
+ g_on = 0;
+ }
+ }
+ *result = tmp;
+ return p_on? 2:1;
+}
+
+
+/*
+ * csh-style history expansion
+ */
+int
+history_expand(char *str, char **output)
+{
+ int ret = 0;
+ size_t idx, i, size;
+ char *tmp, *result;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ if (history_expansion_char == 0) {
+ *output = strdup(str);
+ return 0;
+ }
+
+ *output = NULL;
+ if (str[0] == history_subst_char) {
+ /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
+ *output = el_malloc((strlen(str) + 4 + 1) * sizeof(**output));
+ if (*output == NULL)
+ return 0;
+ (*output)[0] = (*output)[1] = history_expansion_char;
+ (*output)[2] = ':';
+ (*output)[3] = 's';
+ (void)strcpy((*output) + 4, str);
+ str = *output;
+ } else {
+ *output = strdup(str);
+ if (*output == NULL)
+ return 0;
+ }
+
+#define ADD_STRING(what, len, fr) \
+ { \
+ if (idx + len + 1 > size) { \
+ char *nresult = el_realloc(result, \
+ (size += len + 1) * sizeof(*nresult)); \
+ if (nresult == NULL) { \
+ el_free(*output); \
+ if (/*CONSTCOND*/fr) \
+ el_free(tmp); \
+ return 0; \
+ } \
+ result = nresult; \
+ } \
+ (void)strncpy(&result[idx], what, len); \
+ idx += len; \
+ result[idx] = '\0'; \
+ }
+
+ result = NULL;
+ size = idx = 0;
+ tmp = NULL;
+ for (i = 0; str[i];) {
+ int qchar, loop_again;
+ size_t len, start, j;
+
+ qchar = 0;
+ loop_again = 1;
+ start = j = i;
+loop:
+ for (; str[j]; j++) {
+ if (str[j] == '\\' &&
+ str[j + 1] == history_expansion_char) {
+ len = strlen(&str[j + 1]) + 1;
+ memmove(&str[j], &str[j + 1], len);
+ continue;
+ }
+ if (!loop_again) {
+ if (isspace((unsigned char) str[j])
+ || str[j] == qchar)
+ break;
+ }
+ if (str[j] == history_expansion_char
+ && !strchr(history_no_expand_chars, str[j + 1])
+ && (!history_inhibit_expansion_function ||
+ (*history_inhibit_expansion_function)(str,
+ (int)j) == 0))
+ break;
+ }
+
+ if (str[j] && loop_again) {
+ i = j;
+ qchar = (j > 0 && str[j - 1] == '"' )? '"':0;
+ j++;
+ if (str[j] == history_expansion_char)
+ j++;
+ loop_again = 0;
+ goto loop;
+ }
+ len = i - start;
+ ADD_STRING(&str[start], len, 0);
+
+ if (str[i] == '\0' || str[i] != history_expansion_char) {
+ len = j - i;
+ ADD_STRING(&str[i], len, 0);
+ if (start == 0)
+ ret = 0;
+ else
+ ret = 1;
+ break;
+ }
+ ret = _history_expand_command (str, i, (j - i), &tmp);
+ if (ret > 0 && tmp) {
+ len = strlen(tmp);
+ ADD_STRING(tmp, len, 1);
+ }
+ if (tmp) {
+ el_free(tmp);
+ tmp = NULL;
+ }
+ i = j;
+ }
+
+ /* ret is 2 for "print only" option */
+ if (ret == 2) {
+ add_history(result);
+#ifdef GDB_411_HACK
+ /* gdb 4.11 has been shipped with readline, where */
+ /* history_expand() returned -1 when the line */
+ /* should not be executed; in readline 2.1+ */
+ /* it should return 2 in such a case */
+ ret = -1;
+#endif
+ }
+ el_free(*output);
+ *output = result;
+
+ return ret;
+}
+
+/*
+* Return a string consisting of arguments of "str" from "start" to "end".
+*/
+char *
+history_arg_extract(int start, int end, const char *str)
+{
+ size_t i, len, max;
+ char **arr, *result = NULL;
+
+ arr = history_tokenize(str);
+ if (!arr)
+ return NULL;
+ if (arr && *arr == NULL)
+ goto out;
+
+ for (max = 0; arr[max]; max++)
+ continue;
+ max--;
+
+ if (start == '$')
+ start = (int)max;
+ if (end == '$')
+ end = (int)max;
+ if (end < 0)
+ end = (int)max + end + 1;
+ if (start < 0)
+ start = end;
+
+ if (start < 0 || end < 0 || (size_t)start > max ||
+ (size_t)end > max || start > end)
+ goto out;
+
+ for (i = (size_t)start, len = 0; i <= (size_t)end; i++)
+ len += strlen(arr[i]) + 1;
+ len++;
+ result = el_malloc(len * sizeof(*result));
+ if (result == NULL)
+ goto out;
+
+ for (i = (size_t)start, len = 0; i <= (size_t)end; i++) {
+ (void)strcpy(result + len, arr[i]);
+ len += strlen(arr[i]);
+ if (i < (size_t)end)
+ result[len++] = ' ';
+ }
+ result[len] = '\0';
+
+out:
+ for (i = 0; arr[i]; i++)
+ el_free(arr[i]);
+ el_free(arr);
+
+ return result;
+}
+
+/*
+ * Parse the string into individual tokens,
+ * similar to how shell would do it.
+ */
+char **
+history_tokenize(const char *str)
+{
+ int size = 1, idx = 0, i, start;
+ size_t len;
+ char **result = NULL, *temp, delim = '\0';
+
+ for (i = 0; str[i];) {
+ while (isspace((unsigned char) str[i]))
+ i++;
+ start = i;
+ for (; str[i];) {
+ if (str[i] == '\\') {
+ if (str[i+1] != '\0')
+ i++;
+ } else if (str[i] == delim)
+ delim = '\0';
+ else if (!delim &&
+ (isspace((unsigned char) str[i]) ||
+ strchr("()<>;&|$", str[i])))
+ break;
+ else if (!delim && strchr("'`\"", str[i]))
+ delim = str[i];
+ if (str[i])
+ i++;
+ }
+
+ if (idx + 2 >= size) {
+ char **nresult;
+ size <<= 1;
+ nresult = el_realloc(result, (size_t)size * sizeof(*nresult));
+ if (nresult == NULL) {
+ el_free(result);
+ return NULL;
+ }
+ result = nresult;
+ }
+ len = (size_t)i - (size_t)start;
+ temp = el_malloc((size_t)(len + 1) * sizeof(*temp));
+ if (temp == NULL) {
+ for (i = 0; i < idx; i++)
+ el_free(result[i]);
+ el_free(result);
+ return NULL;
+ }
+ (void)strncpy(temp, &str[start], len);
+ temp[len] = '\0';
+ result[idx++] = temp;
+ result[idx] = NULL;
+ if (str[i])
+ i++;
+ }
+ return result;
+}
+
+
+/*
+ * limit size of history record to ``max'' events
+ */
+void
+stifle_history(int max)
+{
+ HistEvent ev;
+ HIST_ENTRY *he;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ if (history(h, &ev, H_SETSIZE, max) == 0) {
+ max_input_history = max;
+ if (history_length > max)
+ history_base = history_length - max;
+ while (history_length > max) {
+ he = remove_history(0);
+ el_free(he->data);
+ el_free((void *)(unsigned long)he->line);
+ el_free(he);
+ }
+ }
+}
+
+
+/*
+ * "unlimit" size of history - set the limit to maximum allowed int value
+ */
+int
+unstifle_history(void)
+{
+ HistEvent ev;
+ int omax;
+
+ history(h, &ev, H_SETSIZE, INT_MAX);
+ omax = max_input_history;
+ max_input_history = INT_MAX;
+ return omax; /* some value _must_ be returned */
+}
+
+
+int
+history_is_stifled(void)
+{
+
+ /* cannot return true answer */
+ return max_input_history != INT_MAX;
+}
+
+static const char _history_tmp_template[] = "/tmp/.historyXXXXXX";
+
+int
+history_truncate_file (const char *filename, int nlines)
+{
+ int ret = 0;
+ FILE *fp, *tp;
+ char template[sizeof(_history_tmp_template)];
+ char buf[4096];
+ int fd;
+ char *cp;
+ off_t off;
+ int count = 0;
+ ssize_t left = 0;
+
+ if (filename == NULL && (filename = _default_history_file()) == NULL)
+ return errno;
+ if ((fp = fopen(filename, "r+")) == NULL)
+ return errno;
+ strcpy(template, _history_tmp_template);
+ if ((fd = mkstemp(template)) == -1) {
+ ret = errno;
+ goto out1;
+ }
+
+ if ((tp = fdopen(fd, "r+")) == NULL) {
+ close(fd);
+ ret = errno;
+ goto out2;
+ }
+
+ for(;;) {
+ if (fread(buf, sizeof(buf), (size_t)1, fp) != 1) {
+ if (ferror(fp)) {
+ ret = errno;
+ break;
+ }
+ if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) ==
+ (off_t)-1) {
+ ret = errno;
+ break;
+ }
+ left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), fp);
+ if (ferror(fp)) {
+ ret = errno;
+ break;
+ }
+ if (left == 0) {
+ count--;
+ left = sizeof(buf);
+ } else if (fwrite(buf, (size_t)left, (size_t)1, tp)
+ != 1) {
+ ret = errno;
+ break;
+ }
+ fflush(tp);
+ break;
+ }
+ if (fwrite(buf, sizeof(buf), (size_t)1, tp) != 1) {
+ ret = errno;
+ break;
+ }
+ count++;
+ }
+ if (ret)
+ goto out3;
+ cp = buf + left - 1;
+ if(*cp != '\n')
+ cp++;
+ for(;;) {
+ while (--cp >= buf) {
+ if (*cp == '\n') {
+ if (--nlines == 0) {
+ if (++cp >= buf + sizeof(buf)) {
+ count++;
+ cp = buf;
+ }
+ break;
+ }
+ }
+ }
+ if (nlines <= 0 || count == 0)
+ break;
+ count--;
+ if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) {
+ ret = errno;
+ break;
+ }
+ if (fread(buf, sizeof(buf), (size_t)1, tp) != 1) {
+ if (ferror(tp)) {
+ ret = errno;
+ break;
+ }
+ ret = EAGAIN;
+ break;
+ }
+ cp = buf + sizeof(buf);
+ }
+
+ if (ret || nlines > 0)
+ goto out3;
+
+ if (fseeko(fp, (off_t)0, SEEK_SET) == (off_t)-1) {
+ ret = errno;
+ goto out3;
+ }
+
+ if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) ==
+ (off_t)-1) {
+ ret = errno;
+ goto out3;
+ }
+
+ for(;;) {
+ if ((left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), tp)) == 0) {
+ if (ferror(fp))
+ ret = errno;
+ break;
+ }
+ if (fwrite(buf, (size_t)left, (size_t)1, fp) != 1) {
+ ret = errno;
+ break;
+ }
+ }
+ fflush(fp);
+ if((off = ftello(fp)) > 0)
+ (void)ftruncate(fileno(fp), off);
+out3:
+ fclose(tp);
+out2:
+ unlink(template);
+out1:
+ fclose(fp);
+
+ return ret;
+}
+
+
+/*
+ * read history from a file given
+ */
+int
+read_history(const char *filename)
+{
+ HistEvent ev;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+ if (filename == NULL && (filename = _default_history_file()) == NULL)
+ return errno;
+ return history(h, &ev, H_LOAD, filename) == -1 ?
+ (errno ? errno : EINVAL) : 0;
+}
+
+
+/*
+ * write history to a file given
+ */
+int
+write_history(const char *filename)
+{
+ HistEvent ev;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+ if (filename == NULL && (filename = _default_history_file()) == NULL)
+ return errno;
+ return history(h, &ev, H_SAVE, filename) == -1 ?
+ (errno ? errno : EINVAL) : 0;
+}
+
+
+/*
+ * returns history ``num''th event
+ *
+ * returned pointer points to static variable
+ */
+HIST_ENTRY *
+history_get(int num)
+{
+ static HIST_ENTRY she;
+ HistEvent ev;
+ int curr_num;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ if (num < history_base)
+ return NULL;
+
+ /* save current position */
+ if (history(h, &ev, H_CURR) != 0)
+ return NULL;
+ curr_num = ev.num;
+
+ /*
+ * use H_DELDATA to set to nth history (without delete) by passing
+ * (void **)-1 -- as in history_set_pos
+ */
+ if (history(h, &ev, H_DELDATA, num - history_base, (void **)-1) != 0)
+ goto out;
+
+ /* get current entry */
+ if (history(h, &ev, H_CURR) != 0)
+ goto out;
+ if (history(h, &ev, H_NEXT_EVDATA, ev.num, &she.data) != 0)
+ goto out;
+ she.line = ev.str;
+
+ /* restore pointer to where it was */
+ (void)history(h, &ev, H_SET, curr_num);
+
+ return &she;
+
+out:
+ /* restore pointer to where it was */
+ (void)history(h, &ev, H_SET, curr_num);
+ return NULL;
+}
+
+
+/*
+ * add the line to history table
+ */
+int
+add_history(const char *line)
+{
+ HistEvent ev;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ if (history(h, &ev, H_ENTER, line) == -1)
+ return 0;
+
+ (void)history(h, &ev, H_GETSIZE);
+ if (ev.num == history_length)
+ history_base++;
+ else
+ history_length = ev.num;
+ return 0;
+}
+
+
+/*
+ * remove the specified entry from the history list and return it.
+ */
+HIST_ENTRY *
+remove_history(int num)
+{
+ HIST_ENTRY *he;
+ HistEvent ev;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ if ((he = el_malloc(sizeof(*he))) == NULL)
+ return NULL;
+
+ if (history(h, &ev, H_DELDATA, num, &he->data) != 0) {
+ el_free(he);
+ return NULL;
+ }
+
+ he->line = ev.str;
+ if (history(h, &ev, H_GETSIZE) == 0)
+ history_length = ev.num;
+
+ return he;
+}
+
+
+/*
+ * replace the line and data of the num-th entry
+ */
+HIST_ENTRY *
+replace_history_entry(int num, const char *line, histdata_t data)
+{
+ HIST_ENTRY *he;
+ HistEvent ev;
+ int curr_num;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ /* save current position */
+ if (history(h, &ev, H_CURR) != 0)
+ return NULL;
+ curr_num = ev.num;
+
+ /* start from the oldest */
+ if (history(h, &ev, H_LAST) != 0)
+ return NULL; /* error */
+
+ if ((he = el_malloc(sizeof(*he))) == NULL)
+ return NULL;
+
+ /* look forwards for event matching specified offset */
+ if (history(h, &ev, H_NEXT_EVDATA, num, &he->data))
+ goto out;
+
+ he->line = strdup(ev.str);
+ if (he->line == NULL)
+ goto out;
+
+ if (history(h, &ev, H_REPLACE, line, data))
+ goto out;
+
+ /* restore pointer to where it was */
+ if (history(h, &ev, H_SET, curr_num))
+ goto out;
+
+ return he;
+out:
+ el_free(he);
+ return NULL;
+}
+
+/*
+ * clear the history list - delete all entries
+ */
+void
+clear_history(void)
+{
+ HistEvent ev;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ (void)history(h, &ev, H_CLEAR);
+ history_offset = history_length = 0;
+}
+
+
+/*
+ * returns offset of the current history event
+ */
+int
+where_history(void)
+{
+ return history_offset;
+}
+
+static HIST_ENTRY **_history_listp;
+static HIST_ENTRY *_history_list;
+
+HIST_ENTRY **
+history_list(void)
+{
+ HistEvent ev;
+ HIST_ENTRY **nlp, *nl;
+ int i;
+
+ if (history(h, &ev, H_LAST) != 0)
+ return NULL;
+
+ if ((nlp = el_realloc(_history_listp,
+ (size_t)history_length * sizeof(*nlp))) == NULL)
+ return NULL;
+ _history_listp = nlp;
+
+ if ((nl = el_realloc(_history_list,
+ (size_t)history_length * sizeof(*nl))) == NULL)
+ return NULL;
+ _history_list = nl;
+
+ i = 0;
+ do {
+ _history_listp[i] = &_history_list[i];
+ _history_list[i].line = ev.str;
+ _history_list[i].data = NULL;
+ if (i++ == history_length)
+ abort();
+ } while (history(h, &ev, H_PREV) == 0);
+ return _history_listp;
+}
+
+/*
+ * returns current history event or NULL if there is no such event
+ */
+HIST_ENTRY *
+current_history(void)
+{
+ HistEvent ev;
+
+ if (history(h, &ev, H_PREV_EVENT, history_offset + 1) != 0)
+ return NULL;
+
+ rl_he.line = ev.str;
+ rl_he.data = NULL;
+ return &rl_he;
+}
+
+
+/*
+ * returns total number of bytes history events' data are using
+ */
+int
+history_total_bytes(void)
+{
+ HistEvent ev;
+ int curr_num;
+ size_t size;
+
+ if (history(h, &ev, H_CURR) != 0)
+ return -1;
+ curr_num = ev.num;
+
+ (void)history(h, &ev, H_FIRST);
+ size = 0;
+ do
+ size += strlen(ev.str) * sizeof(*ev.str);
+ while (history(h, &ev, H_NEXT) == 0);
+
+ /* get to the same position as before */
+ history(h, &ev, H_PREV_EVENT, curr_num);
+
+ return (int)size;
+}
+
+
+/*
+ * sets the position in the history list to ``pos''
+ */
+int
+history_set_pos(int pos)
+{
+ if (pos >= history_length || pos < 0)
+ return 0;
+
+ history_offset = pos;
+ return 1;
+}
+
+
+/*
+ * returns previous event in history and shifts pointer accordingly
+ * Note that readline and editline define directions in opposite ways.
+ */
+HIST_ENTRY *
+previous_history(void)
+{
+ HistEvent ev;
+
+ if (history_offset == 0)
+ return NULL;
+
+ if (history(h, &ev, H_LAST) != 0)
+ return NULL;
+
+ history_offset--;
+ return current_history();
+}
+
+
+/*
+ * returns next event in history and shifts pointer accordingly
+ */
+HIST_ENTRY *
+next_history(void)
+{
+ HistEvent ev;
+
+ if (history_offset >= history_length)
+ return NULL;
+
+ if (history(h, &ev, H_LAST) != 0)
+ return NULL;
+
+ history_offset++;
+ return current_history();
+}
+
+
+/*
+ * searches for first history event containing the str
+ */
+int
+history_search(const char *str, int direction)
+{
+ HistEvent ev;
+ const char *strp;
+ int curr_num;
+
+ if (history(h, &ev, H_CURR) != 0)
+ return -1;
+ curr_num = ev.num;
+
+ for (;;) {
+ if ((strp = strstr(ev.str, str)) != NULL)
+ return (int)(strp - ev.str);
+ if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0)
+ break;
+ }
+ (void)history(h, &ev, H_SET, curr_num);
+ return -1;
+}
+
+
+/*
+ * searches for first history event beginning with str
+ */
+int
+history_search_prefix(const char *str, int direction)
+{
+ HistEvent ev;
+
+ return (history(h, &ev, direction < 0 ?
+ H_PREV_STR : H_NEXT_STR, str));
+}
+
+
+/*
+ * search for event in history containing str, starting at offset
+ * abs(pos); continue backward, if pos<0, forward otherwise
+ */
+/* ARGSUSED */
+int
+history_search_pos(const char *str,
+ int direction __attribute__((__unused__)), int pos)
+{
+ HistEvent ev;
+ int curr_num, off;
+
+ off = (pos > 0) ? pos : -pos;
+ pos = (pos > 0) ? 1 : -1;
+
+ if (history(h, &ev, H_CURR) != 0)
+ return -1;
+ curr_num = ev.num;
+
+ if (!history_set_pos(off) || history(h, &ev, H_CURR) != 0)
+ return -1;
+
+ for (;;) {
+ if (strstr(ev.str, str))
+ return off;
+ if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0)
+ break;
+ }
+
+ /* set "current" pointer back to previous state */
+ (void)history(h, &ev,
+ pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
+
+ return -1;
+}
+
+
+/********************************/
+/* completion functions */
+
+char *
+tilde_expand(char *name)
+{
+ return fn_tilde_expand(name);
+}
+
+char *
+filename_completion_function(const char *name, int state)
+{
+ return fn_filename_completion_function(name, state);
+}
+
+/*
+ * a completion generator for usernames; returns _first_ username
+ * which starts with supplied text
+ * text contains a partial username preceded by random character
+ * (usually '~'); state resets search from start (??? should we do that anyway)
+ * it's the caller's responsibility to free the returned value
+ */
+char *
+username_completion_function(const char *text, int state)
+{
+#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT)
+ struct passwd pwres;
+ char pwbuf[1024];
+#endif
+ struct passwd *pass = NULL;
+
+ if (text[0] == '\0')
+ return NULL;
+
+ if (*text == '~')
+ text++;
+
+ if (state == 0)
+ setpwent();
+
+ while (
+ (pass = getpwent()) != NULL
+ && text[0] == pass->pw_name[0]
+ && strcmp(text, pass->pw_name) == 0)
+ continue;
+
+ if (pass == NULL) {
+ endpwent();
+ return NULL;
+ }
+ return strdup(pass->pw_name);
+}
+
+
+/*
+ * el-compatible wrapper to send TSTP on ^Z
+ */
+/* ARGSUSED */
+static unsigned char
+_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__)))
+{
+ (void)kill(0, SIGTSTP);
+ return CC_NORM;
+}
+
+/*
+ * Display list of strings in columnar format on readline's output stream.
+ * 'matches' is list of strings, 'len' is number of strings in 'matches',
+ * 'max' is maximum length of string in 'matches'.
+ */
+void
+rl_display_match_list(char **matches, int len, int max)
+{
+
+ fn_display_match_list(e, matches, (size_t)len, (size_t)max);
+}
+
+static const char *
+/*ARGSUSED*/
+_rl_completion_append_character_function(const char *dummy
+ __attribute__((__unused__)))
+{
+ static char buf[2];
+ buf[0] = (char)rl_completion_append_character;
+ buf[1] = '\0';
+ return buf;
+}
+
+
+/*
+ * complete word at current point
+ */
+/* ARGSUSED */
+int
+rl_complete(int ignore __attribute__((__unused__)), int invoking_key)
+{
+ static ct_buffer_t wbreak_conv, sprefix_conv;
+ char *breakchars;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ if (rl_inhibit_completion) {
+ char arr[2];
+ arr[0] = (char)invoking_key;
+ arr[1] = '\0';
+ el_insertstr(e, arr);
+ return CC_REFRESH;
+ }
+
+ if (rl_completion_word_break_hook != NULL)
+ breakchars = (*rl_completion_word_break_hook)();
+ else
+ breakchars = rl_basic_word_break_characters;
+
+ _rl_update_pos();
+
+ /* Just look at how many global variables modify this operation! */
+ return fn_complete(e,
+ (rl_compentry_func_t *)rl_completion_entry_function,
+ rl_attempted_completion_function,
+ ct_decode_string(rl_basic_word_break_characters, &wbreak_conv),
+ ct_decode_string(breakchars, &sprefix_conv),
+ _rl_completion_append_character_function,
+ (size_t)rl_completion_query_items,
+ &rl_completion_type, &rl_attempted_completion_over,
+ &rl_point, &rl_end);
+
+
+}
+
+
+/* ARGSUSED */
+static unsigned char
+_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch)
+{
+ return (unsigned char)rl_complete(0, ch);
+}
+
+/*
+ * misc other functions
+ */
+
+/*
+ * bind key c to readline-type function func
+ */
+int
+rl_bind_key(int c, rl_command_func_t *func)
+{
+ int retval = -1;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ if (func == rl_insert) {
+ /* XXX notice there is no range checking of ``c'' */
+ e->el_map.key[c] = ED_INSERT;
+ retval = 0;
+ }
+ return retval;
+}
+
+
+/*
+ * read one key from input - handles chars pushed back
+ * to input stream also
+ */
+int
+rl_read_key(void)
+{
+ char fooarr[2 * sizeof(int)];
+
+ if (e == NULL || h == NULL)
+ rl_initialize();
+
+ return el_getc(e, fooarr);
+}
+
+
+/*
+ * reset the terminal
+ */
+/* ARGSUSED */
+void
+rl_reset_terminal(const char *p __attribute__((__unused__)))
+{
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+ el_reset(e);
+}
+
+
+/*
+ * insert character ``c'' back into input stream, ``count'' times
+ */
+int
+rl_insert(int count, int c)
+{
+ char arr[2];
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ /* XXX - int -> char conversion can lose on multichars */
+ arr[0] = (char)c;
+ arr[1] = '\0';
+
+ for (; count > 0; count--)
+ el_push(e, arr);
+
+ return 0;
+}
+
+int
+rl_insert_text(const char *text)
+{
+ if (!text || *text == 0)
+ return 0;
+
+ if (h == NULL || e == NULL)
+ rl_initialize();
+
+ if (el_insertstr(e, text) < 0)
+ return 0;
+ return (int)strlen(text);
+}
+
+/*ARGSUSED*/
+int
+rl_newline(int count __attribute__((__unused__)),
+ int c __attribute__((__unused__)))
+{
+ /*
+ * Readline-4.0 appears to ignore the args.
+ */
+ return rl_insert(1, '\n');
+}
+
+/*ARGSUSED*/
+static unsigned char
+rl_bind_wrapper(EditLine *el __attribute__((__unused__)), unsigned char c)
+{
+ if (map[c] == NULL)
+ return CC_ERROR;
+
+ _rl_update_pos();
+
+ (*map[c])(1, c);
+
+ /* If rl_done was set by the above call, deal with it here */
+ if (rl_done)
+ return CC_EOF;
+
+ return CC_NORM;
+}
+
+int
+rl_add_defun(const char *name, rl_command_func_t *fun, int c)
+{
+ char dest[8];
+ if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0)
+ return -1;
+ map[(unsigned char)c] = fun;
+ el_set(e, EL_ADDFN, name, name, rl_bind_wrapper);
+ vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0);
+ el_set(e, EL_BIND, dest, name, NULL);
+ return 0;
+}
+
+void
+rl_callback_read_char(void)
+{
+ int count = 0, done = 0;
+ const char *buf = el_gets(e, &count);
+ char *wbuf;
+
+ if (buf == NULL || count-- <= 0)
+ return;
+ if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF])
+ done = 1;
+ if (buf[count] == '\n' || buf[count] == '\r')
+ done = 2;
+
+ if (done && rl_linefunc != NULL) {
+ el_set(e, EL_UNBUFFERED, 0);
+ if (done == 2) {
+ if ((wbuf = strdup(buf)) != NULL)
+ wbuf[count] = '\0';
+ } else
+ wbuf = NULL;
+ (*(void (*)(const char *))rl_linefunc)(wbuf);
+ el_set(e, EL_UNBUFFERED, 1);
+ }
+}
+
+void
+rl_callback_handler_install(const char *prompt, rl_vcpfunc_t *linefunc)
+{
+ if (e == NULL) {
+ rl_initialize();
+ }
+ (void)rl_set_prompt(prompt);
+ rl_linefunc = linefunc;
+ el_set(e, EL_UNBUFFERED, 1);
+}
+
+void
+rl_callback_handler_remove(void)
+{
+ el_set(e, EL_UNBUFFERED, 0);
+ rl_linefunc = NULL;
+}
+
+void
+rl_redisplay(void)
+{
+ char a[2];
+ a[0] = (char)e->el_tty.t_c[TS_IO][C_REPRINT];
+ a[1] = '\0';
+ el_push(e, a);
+}
+
+int
+rl_get_previous_history(int count, int key)
+{
+ char a[2];
+ a[0] = (char)key;
+ a[1] = '\0';
+ while (count--)
+ el_push(e, a);
+ return 0;
+}
+
+void
+/*ARGSUSED*/
+rl_prep_terminal(int meta_flag __attribute__((__unused__)))
+{
+ el_set(e, EL_PREP_TERM, 1);
+}
+
+void
+rl_deprep_terminal(void)
+{
+ el_set(e, EL_PREP_TERM, 0);
+}
+
+int
+rl_read_init_file(const char *s)
+{
+ return el_source(e, s);
+}
+
+int
+rl_parse_and_bind(const char *line)
+{
+ const char **argv;
+ int argc;
+ Tokenizer *tok;
+
+ tok = tok_init(NULL);
+ tok_str(tok, line, &argc, &argv);
+ argc = el_parse(e, argc, argv);
+ tok_end(tok);
+ return argc ? 1 : 0;
+}
+
+int
+rl_variable_bind(const char *var, const char *value)
+{
+ /*
+ * The proper return value is undocument, but this is what the
+ * readline source seems to do.
+ */
+ return el_set(e, EL_BIND, "", var, value, NULL) == -1 ? 1 : 0;
+}
+
+void
+rl_stuff_char(int c)
+{
+ char buf[2];
+
+ buf[0] = (char)c;
+ buf[1] = '\0';
+ el_insertstr(e, buf);
+}
+
+static int
+_rl_event_read_char(EditLine *el, wchar_t *wc)
+{
+ char ch;
+ int n;
+ ssize_t num_read = 0;
+
+ ch = '\0';
+ *wc = L'\0';
+ while (rl_event_hook) {
+
+ (*rl_event_hook)();
+
+#if defined(FIONREAD)
+ if (ioctl(el->el_infd, FIONREAD, &n) < 0)
+ return -1;
+ if (n)
+ num_read = read(el->el_infd, &ch, (size_t)1);
+ else
+ num_read = 0;
+#elif defined(F_SETFL) && defined(O_NDELAY)
+ if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0)
+ return -1;
+ if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0)
+ return -1;
+ num_read = read(el->el_infd, &ch, 1);
+ if (fcntl(el->el_infd, F_SETFL, n))
+ return -1;
+#else
+ /* not non-blocking, but what you gonna do? */
+ num_read = read(el->el_infd, &ch, 1);
+ return -1;
+#endif
+
+ if (num_read < 0 && errno == EAGAIN)
+ continue;
+ if (num_read == 0)
+ continue;
+ break;
+ }
+ if (!rl_event_hook)
+ el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN);
+ *wc = (wchar_t)ch;
+ return (int)num_read;
+}
+
+static void
+_rl_update_pos(void)
+{
+ const LineInfo *li = el_line(e);
+
+ rl_point = (int)(li->cursor - li->buffer);
+ rl_end = (int)(li->lastchar - li->buffer);
+}
+
+void
+rl_get_screen_size(int *rows, int *cols)
+{
+ if (rows)
+ el_get(e, EL_GETTC, "li", rows, (void *)0);
+ if (cols)
+ el_get(e, EL_GETTC, "co", cols, (void *)0);
+}
+
+void
+rl_set_screen_size(int rows, int cols)
+{
+ char buf[64];
+ (void)snprintf(buf, sizeof(buf), "%d", rows);
+ el_set(e, EL_SETTC, "li", buf, NULL);
+ (void)snprintf(buf, sizeof(buf), "%d", cols);
+ el_set(e, EL_SETTC, "co", buf, NULL);
+}
+
+char **
+rl_completion_matches(const char *str, rl_compentry_func_t *fun)
+{
+ size_t len, max, i, j, min;
+ char **list, *match, *a, *b;
+
+ len = 1;
+ max = 10;
+ if ((list = el_malloc(max * sizeof(*list))) == NULL)
+ return NULL;
+
+ while ((match = (*fun)(str, (int)(len - 1))) != NULL) {
+ list[len++] = match;
+ if (len == max) {
+ char **nl;
+ max += 10;
+ if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL)
+ goto out;
+ list = nl;
+ }
+ }
+ if (len == 1)
+ goto out;
+ list[len] = NULL;
+ if (len == 2) {
+ if ((list[0] = strdup(list[1])) == NULL)
+ goto out;
+ return list;
+ }
+ qsort(&list[1], len - 1, sizeof(*list),
+ (int (*)(const void *, const void *)) strcmp);
+ min = SIZE_MAX;
+ for (i = 1, a = list[i]; i < len - 1; i++, a = b) {
+ b = list[i + 1];
+ for (j = 0; a[j] && a[j] == b[j]; j++)
+ continue;
+ if (min > j)
+ min = j;
+ }
+ if (min == 0 && *str) {
+ if ((list[0] = strdup(str)) == NULL)
+ goto out;
+ } else {
+ if ((list[0] = el_malloc((min + 1) * sizeof(*list[0]))) == NULL)
+ goto out;
+ (void)memcpy(list[0], list[1], min);
+ list[0][min] = '\0';
+ }
+ return list;
+
+out:
+ el_free(list);
+ return NULL;
+}
+
+char *
+rl_filename_completion_function (const char *text, int state)
+{
+ return fn_filename_completion_function(text, state);
+}
+
+void
+rl_forced_update_display(void)
+{
+ el_set(e, EL_REFRESH);
+}
+
+int
+_rl_abort_internal(void)
+{
+ el_beep(e);
+ longjmp(topbuf, 1);
+ /*NOTREACHED*/
+}
+
+int
+_rl_qsort_string_compare(char **s1, char **s2)
+{
+ return strcoll(*s1, *s2);
+}
+
+HISTORY_STATE *
+history_get_history_state(void)
+{
+ HISTORY_STATE *hs;
+
+ if ((hs = el_malloc(sizeof(*hs))) == NULL)
+ return NULL;
+ hs->length = history_length;
+ return hs;
+}
+
+int
+/*ARGSUSED*/
+rl_kill_text(int from __attribute__((__unused__)),
+ int to __attribute__((__unused__)))
+{
+ return 0;
+}
+
+Keymap
+rl_make_bare_keymap(void)
+{
+ return NULL;
+}
+
+Keymap
+rl_get_keymap(void)
+{
+ return NULL;
+}
+
+void
+/*ARGSUSED*/
+rl_set_keymap(Keymap k __attribute__((__unused__)))
+{
+}
+
+int
+/*ARGSUSED*/
+rl_generic_bind(int type __attribute__((__unused__)),
+ const char * keyseq __attribute__((__unused__)),
+ const char * data __attribute__((__unused__)),
+ Keymap k __attribute__((__unused__)))
+{
+ return 0;
+}
+
+int
+/*ARGSUSED*/
+rl_bind_key_in_map(int key __attribute__((__unused__)),
+ rl_command_func_t *fun __attribute__((__unused__)),
+ Keymap k __attribute__((__unused__)))
+{
+ return 0;
+}
+
+/* unsupported, but needed by python */
+void
+rl_cleanup_after_signal(void)
+{
+}
+
+int
+rl_on_new_line(void)
+{
+ return 0;
+}
+
+void
+rl_free_line_state(void)
+{
+}
+
+int
+/*ARGSUSED*/
+rl_set_keyboard_input_timeout(int u __attribute__((__unused__)))
+{
+ return 0;
+}
diff --git a/third_party/heimdal/lib/libedit/src/readline/readline.h b/third_party/heimdal/lib/libedit/src/readline/readline.h
new file mode 100644
index 0000000..79ae115
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/readline/readline.h
@@ -0,0 +1,227 @@
+/* $NetBSD: readline.h,v 1.41 2016/10/28 18:32:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jaromir Dolecek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _READLINE_H_
+#define _READLINE_H_
+
+#include <sys/types.h>
+#include <stdio.h>
+
+/* list of readline stuff supported by editline library's readline wrapper */
+
+/* typedefs */
+typedef int Function(const char *, int);
+typedef void VFunction(void);
+typedef void rl_vcpfunc_t(char *);
+typedef char **rl_completion_func_t(const char *, int, int);
+typedef char *rl_compentry_func_t(const char *, int);
+typedef int rl_command_func_t(int, int);
+
+/* only supports length */
+typedef struct {
+ int length;
+} HISTORY_STATE;
+
+typedef void *histdata_t;
+
+typedef struct _hist_entry {
+ const char *line;
+ histdata_t data;
+} HIST_ENTRY;
+
+typedef struct _keymap_entry {
+ char type;
+#define ISFUNC 0
+#define ISKMAP 1
+#define ISMACR 2
+ Function *function;
+} KEYMAP_ENTRY;
+
+#define KEYMAP_SIZE 256
+
+typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE];
+typedef KEYMAP_ENTRY *Keymap;
+
+#define control_character_threshold 0x20
+#define control_character_bit 0x40
+
+#ifndef CTRL
+#include <sys/ioctl.h>
+#if !defined(__sun) && !defined(__hpux) && !defined(_AIX) && !defined(_CYGWIN_)
+#include <sys/ttydefaults.h>
+#endif
+#ifndef CTRL
+#define CTRL(c) ((c) & 037)
+#endif
+#endif
+#ifndef UNCTRL
+#define UNCTRL(c) (((c) - 'a' + 'A')|control_character_bit)
+#endif
+
+#define RUBOUT 0x7f
+#define ABORT_CHAR CTRL('G')
+#define RL_READLINE_VERSION 0x0402
+#define RL_PROMPT_START_IGNORE '\1'
+#define RL_PROMPT_END_IGNORE '\2'
+
+/* global variables used by readline enabled applications */
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern const char *rl_library_version;
+extern int rl_readline_version;
+extern char *rl_readline_name;
+extern FILE *rl_instream;
+extern FILE *rl_outstream;
+extern char *rl_line_buffer;
+extern int rl_point, rl_end;
+extern int history_base, history_length;
+extern int max_input_history;
+extern char *rl_basic_word_break_characters;
+extern char *rl_completer_word_break_characters;
+extern char *rl_completer_quote_characters;
+extern rl_compentry_func_t *rl_completion_entry_function;
+extern char *(*rl_completion_word_break_hook)(void);
+extern rl_completion_func_t *rl_attempted_completion_function;
+extern int rl_attempted_completion_over;
+extern int rl_completion_type;
+extern int rl_completion_query_items;
+extern char *rl_special_prefixes;
+extern int rl_completion_append_character;
+extern int rl_inhibit_completion;
+extern Function *rl_pre_input_hook;
+extern Function *rl_startup_hook;
+extern char *rl_terminal_name;
+extern int rl_already_prompted;
+extern char *rl_prompt;
+extern int rl_done;
+/*
+ * The following is not implemented
+ */
+extern int rl_catch_signals;
+extern int rl_catch_sigwinch;
+extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap,
+ emacs_meta_keymap,
+ emacs_ctlx_keymap;
+extern int rl_filename_completion_desired;
+extern int rl_ignore_completion_duplicates;
+extern int (*rl_getc_function)(FILE *);
+extern VFunction *rl_redisplay_function;
+extern VFunction *rl_completion_display_matches_hook;
+extern VFunction *rl_prep_term_function;
+extern VFunction *rl_deprep_term_function;
+extern int readline_echoing_p;
+extern int _rl_print_completions_horizontally;
+
+/* supported functions */
+char *readline(const char *);
+int rl_initialize(void);
+
+void using_history(void);
+int add_history(const char *);
+void clear_history(void);
+void stifle_history(int);
+int unstifle_history(void);
+int history_is_stifled(void);
+int where_history(void);
+HIST_ENTRY *current_history(void);
+HIST_ENTRY *history_get(int);
+HIST_ENTRY *remove_history(int);
+HIST_ENTRY *replace_history_entry(int, const char *, histdata_t);
+int history_total_bytes(void);
+int history_set_pos(int);
+HIST_ENTRY *previous_history(void);
+HIST_ENTRY *next_history(void);
+HIST_ENTRY **history_list(void);
+int history_search(const char *, int);
+int history_search_prefix(const char *, int);
+int history_search_pos(const char *, int, int);
+int read_history(const char *);
+int write_history(const char *);
+int history_truncate_file (const char *, int);
+int history_expand(char *, char **);
+char **history_tokenize(const char *);
+const char *get_history_event(const char *, int *, int);
+char *history_arg_extract(int, int, const char *);
+
+char *tilde_expand(char *);
+char *filename_completion_function(const char *, int);
+char *username_completion_function(const char *, int);
+int rl_complete(int, int);
+int rl_read_key(void);
+char **completion_matches(const char *, rl_compentry_func_t *);
+void rl_display_match_list(char **, int, int);
+
+int rl_insert(int, int);
+int rl_insert_text(const char *);
+void rl_reset_terminal(const char *);
+int rl_bind_key(int, rl_command_func_t *);
+int rl_newline(int, int);
+void rl_callback_read_char(void);
+void rl_callback_handler_install(const char *, rl_vcpfunc_t *);
+void rl_callback_handler_remove(void);
+void rl_redisplay(void);
+int rl_get_previous_history(int, int);
+void rl_prep_terminal(int);
+void rl_deprep_terminal(void);
+int rl_read_init_file(const char *);
+int rl_parse_and_bind(const char *);
+int rl_variable_bind(const char *, const char *);
+void rl_stuff_char(int);
+int rl_add_defun(const char *, rl_command_func_t *, int);
+HISTORY_STATE *history_get_history_state(void);
+void rl_get_screen_size(int *, int *);
+void rl_set_screen_size(int, int);
+char *rl_filename_completion_function (const char *, int);
+int _rl_abort_internal(void);
+int _rl_qsort_string_compare(char **, char **);
+char **rl_completion_matches(const char *, rl_compentry_func_t *);
+void rl_forced_update_display(void);
+int rl_set_prompt(const char *);
+int rl_on_new_line(void);
+
+/*
+ * The following are not implemented
+ */
+int rl_kill_text(int, int);
+Keymap rl_get_keymap(void);
+void rl_set_keymap(Keymap);
+Keymap rl_make_bare_keymap(void);
+int rl_generic_bind(int, const char *, const char *, Keymap);
+int rl_bind_key_in_map(int, rl_command_func_t *, Keymap);
+void rl_cleanup_after_signal(void);
+void rl_free_line_state(void);
+int rl_set_keyboard_input_timeout(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _READLINE_H_ */
diff --git a/third_party/heimdal/lib/libedit/src/refresh.c b/third_party/heimdal/lib/libedit/src/refresh.c
new file mode 100644
index 0000000..e7775b0
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/refresh.c
@@ -0,0 +1,1187 @@
+/* $NetBSD: refresh.c,v 1.51 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: refresh.c,v 1.51 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * refresh.c: Lower level screen refreshing functions
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "el.h"
+
+static void re_nextline(EditLine *);
+static void re_addc(EditLine *, wint_t);
+static void re_update_line(EditLine *, wchar_t *, wchar_t *, int);
+static void re_insert (EditLine *, wchar_t *, int, int, wchar_t *, int);
+static void re_delete(EditLine *, wchar_t *, int, int, int);
+static void re_fastputc(EditLine *, wint_t);
+static void re_clear_eol(EditLine *, int, int, int);
+static void re__strncopy(wchar_t *, wchar_t *, size_t);
+static void re__copy_and_pad(wchar_t *, const wchar_t *, size_t);
+
+#ifdef DEBUG_REFRESH
+static void re_printstr(EditLine *, const char *, wchar_t *, wchar_t *);
+#define __F el->el_errfile
+#define ELRE_ASSERT(a, b, c) do \
+ if (/*CONSTCOND*/ a) { \
+ (void) fprintf b; \
+ c; \
+ } \
+ while (/*CONSTCOND*/0)
+#define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
+
+/* re_printstr():
+ * Print a string on the debugging pty
+ */
+static void
+re_printstr(EditLine *el, const char *str, wchar_t *f, wchar_t *t)
+{
+
+ ELRE_DEBUG(1, (__F, "%s:\"", str));
+ while (f < t)
+ ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
+ ELRE_DEBUG(1, (__F, "\"\r\n"));
+}
+#else
+#define ELRE_ASSERT(a, b, c)
+#define ELRE_DEBUG(a, b)
+#endif
+
+/* re_nextline():
+ * Move to the next line or scroll
+ */
+static void
+re_nextline(EditLine *el)
+{
+ el->el_refresh.r_cursor.h = 0; /* reset it. */
+
+ /*
+ * If we would overflow (input is longer than terminal size),
+ * emulate scroll by dropping first line and shuffling the rest.
+ * We do this via pointer shuffling - it's safe in this case
+ * and we avoid memcpy().
+ */
+ if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) {
+ int i, lins = el->el_terminal.t_size.v;
+ wchar_t *firstline = el->el_vdisplay[0];
+
+ for(i = 1; i < lins; i++)
+ el->el_vdisplay[i - 1] = el->el_vdisplay[i];
+
+ firstline[0] = '\0'; /* empty the string */
+ el->el_vdisplay[i - 1] = firstline;
+ } else
+ el->el_refresh.r_cursor.v++;
+
+ ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v,
+ (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
+ el->el_refresh.r_cursor.v, el->el_terminal.t_size.v),
+ abort());
+}
+
+/* re_addc():
+ * Draw c, expanding tabs, control chars etc.
+ */
+static void
+re_addc(EditLine *el, wint_t c)
+{
+ switch (ct_chr_class(c)) {
+ case CHTYPE_TAB: /* expand the tab */
+ for (;;) {
+ re_putc(el, ' ', 1);
+ if ((el->el_refresh.r_cursor.h & 07) == 0)
+ break; /* go until tab stop */
+ }
+ break;
+ case CHTYPE_NL: {
+ int oldv = el->el_refresh.r_cursor.v;
+ re_putc(el, '\0', 0); /* assure end of line */
+ if (oldv == el->el_refresh.r_cursor.v) /* XXX */
+ re_nextline(el);
+ break;
+ }
+ case CHTYPE_PRINT:
+ re_putc(el, c, 1);
+ break;
+ default: {
+ wchar_t visbuf[VISUAL_WIDTH_MAX];
+ ssize_t i, n =
+ ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
+ for (i = 0; n-- > 0; ++i)
+ re_putc(el, visbuf[i], 1);
+ break;
+ }
+ }
+}
+
+
+/* re_putc():
+ * Draw the character given
+ */
+libedit_private void
+re_putc(EditLine *el, wint_t c, int shift)
+{
+ int i, w = wcwidth(c);
+ ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c));
+ if (w == -1)
+ w = 0;
+
+ while (shift && (el->el_refresh.r_cursor.h + w > el->el_terminal.t_size.h))
+ re_putc(el, ' ', 1);
+
+ el->el_vdisplay[el->el_refresh.r_cursor.v]
+ [el->el_refresh.r_cursor.h] = c;
+ /* assumes !shift is only used for single-column chars */
+ i = w;
+ while (--i > 0)
+ el->el_vdisplay[el->el_refresh.r_cursor.v]
+ [el->el_refresh.r_cursor.h + i] = MB_FILL_CHAR;
+
+ if (!shift)
+ return;
+
+ el->el_refresh.r_cursor.h += w; /* advance to next place */
+ if (el->el_refresh.r_cursor.h >= el->el_terminal.t_size.h) {
+ /* assure end of line */
+ el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_terminal.t_size.h]
+ = '\0';
+ re_nextline(el);
+ }
+}
+
+
+/* re_refresh():
+ * draws the new virtual screen image from the current input
+ * line, then goes line-by-line changing the real image to the new
+ * virtual image. The routine to re-draw a line can be replaced
+ * easily in hopes of a smarter one being placed there.
+ */
+libedit_private void
+re_refresh(EditLine *el)
+{
+ int i, rhdiff;
+ wchar_t *cp, *st;
+ coord_t cur;
+#ifdef notyet
+ size_t termsz;
+#endif
+
+ ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%ls:\r\n",
+ el->el_line.buffer));
+
+ /* reset the Drawing cursor */
+ el->el_refresh.r_cursor.h = 0;
+ el->el_refresh.r_cursor.v = 0;
+
+ /* temporarily draw rprompt to calculate its size */
+ prompt_print(el, EL_RPROMPT);
+
+ /* reset the Drawing cursor */
+ el->el_refresh.r_cursor.h = 0;
+ el->el_refresh.r_cursor.v = 0;
+
+ if (el->el_line.cursor >= el->el_line.lastchar) {
+ if (el->el_map.current == el->el_map.alt
+ && el->el_line.lastchar != el->el_line.buffer)
+ el->el_line.cursor = el->el_line.lastchar - 1;
+ else
+ el->el_line.cursor = el->el_line.lastchar;
+ }
+
+ cur.h = -1; /* set flag in case I'm not set */
+ cur.v = 0;
+
+ prompt_print(el, EL_PROMPT);
+
+ /* draw the current input buffer */
+#if notyet
+ termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v;
+ if (el->el_line.lastchar - el->el_line.buffer > termsz) {
+ /*
+ * If line is longer than terminal, process only part
+ * of line which would influence display.
+ */
+ size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
+
+ st = el->el_line.lastchar - rem
+ - (termsz - (((rem / el->el_terminal.t_size.v) - 1)
+ * el->el_terminal.t_size.v));
+ } else
+#endif
+ st = el->el_line.buffer;
+
+ for (cp = st; cp < el->el_line.lastchar; cp++) {
+ if (cp == el->el_line.cursor) {
+ int w = wcwidth(*cp);
+ /* save for later */
+ cur.h = el->el_refresh.r_cursor.h;
+ cur.v = el->el_refresh.r_cursor.v;
+ /* handle being at a linebroken doublewidth char */
+ if (w > 1 && el->el_refresh.r_cursor.h + w >
+ el->el_terminal.t_size.h) {
+ cur.h = 0;
+ cur.v++;
+ }
+ }
+ re_addc(el, *cp);
+ }
+
+ if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
+ cur.h = el->el_refresh.r_cursor.h;
+ cur.v = el->el_refresh.r_cursor.v;
+ }
+ rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h -
+ el->el_rprompt.p_pos.h;
+ if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
+ !el->el_refresh.r_cursor.v && rhdiff > 1) {
+ /*
+ * have a right-hand side prompt that will fit
+ * on the end of the first line with at least
+ * one character gap to the input buffer.
+ */
+ while (--rhdiff > 0) /* pad out with spaces */
+ re_putc(el, ' ', 1);
+ prompt_print(el, EL_RPROMPT);
+ } else {
+ el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
+ el->el_rprompt.p_pos.v = 0;
+ }
+
+ re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
+
+ el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
+
+ ELRE_DEBUG(1, (__F,
+ "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
+ el->el_terminal.t_size.h, el->el_refresh.r_cursor.h,
+ el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0],
+ &el->el_scratch)));
+
+ ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
+ for (i = 0; i <= el->el_refresh.r_newcv; i++) {
+ /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
+ re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
+
+ /*
+ * Copy the new line to be the current one, and pad out with
+ * spaces to the full width of the terminal so that if we try
+ * moving the cursor by writing the character that is at the
+ * end of the screen line, it won't be a NUL or some old
+ * leftover stuff.
+ */
+ re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
+ (size_t) el->el_terminal.t_size.h);
+ }
+ ELRE_DEBUG(1, (__F,
+ "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
+ el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
+
+ if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
+ for (; i <= el->el_refresh.r_oldcv; i++) {
+ terminal_move_to_line(el, i);
+ terminal_move_to_char(el, 0);
+ /* This wcslen should be safe even with MB_FILL_CHARs */
+ terminal_clear_EOL(el, (int) wcslen(el->el_display[i]));
+#ifdef DEBUG_REFRESH
+ terminal_overwrite(el, L"C\b", 2);
+#endif /* DEBUG_REFRESH */
+ el->el_display[i][0] = '\0';
+ }
+
+ el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
+ ELRE_DEBUG(1, (__F,
+ "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
+ el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
+ cur.h, cur.v));
+ terminal_move_to_line(el, cur.v); /* go to where the cursor is */
+ terminal_move_to_char(el, cur.h);
+}
+
+
+/* re_goto_bottom():
+ * used to go to last used screen line
+ */
+libedit_private void
+re_goto_bottom(EditLine *el)
+{
+
+ terminal_move_to_line(el, el->el_refresh.r_oldcv);
+ terminal__putc(el, '\n');
+ re_clear_display(el);
+ terminal__flush(el);
+}
+
+
+/* re_insert():
+ * insert num characters of s into d (in front of the character)
+ * at dat, maximum length of d is dlen
+ */
+static void
+/*ARGSUSED*/
+re_insert(EditLine *el __attribute__((__unused__)),
+ wchar_t *d, int dat, int dlen, wchar_t *s, int num)
+{
+ wchar_t *a, *b;
+
+ if (num <= 0)
+ return;
+ if (num > dlen - dat)
+ num = dlen - dat;
+
+ ELRE_DEBUG(1,
+ (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
+ num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
+ ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
+ &el->el_scratch)));
+
+ /* open up the space for num chars */
+ if (num > 0) {
+ b = d + dlen - 1;
+ a = b - num;
+ while (a >= &d[dat])
+ *b-- = *a--;
+ d[dlen] = '\0'; /* just in case */
+ }
+
+ ELRE_DEBUG(1, (__F,
+ "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
+ num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
+ ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
+ &el->el_scratch)));
+
+ /* copy the characters */
+ for (a = d + dat; (a < d + dlen) && (num > 0); num--)
+ *a++ = *s++;
+
+#ifdef notyet
+ /* ct_encode_string() uses a static buffer, so we can't conveniently
+ * encode both d & s here */
+ ELRE_DEBUG(1,
+ (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
+ num, dat, dlen, d, s));
+ ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
+#endif
+}
+
+
+/* re_delete():
+ * delete num characters d at dat, maximum length of d is dlen
+ */
+static void
+/*ARGSUSED*/
+re_delete(EditLine *el __attribute__((__unused__)),
+ wchar_t *d, int dat, int dlen, int num)
+{
+ wchar_t *a, *b;
+
+ if (num <= 0)
+ return;
+ if (dat + num >= dlen) {
+ d[dat] = '\0';
+ return;
+ }
+ ELRE_DEBUG(1,
+ (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
+ num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
+
+ /* open up the space for num chars */
+ if (num > 0) {
+ b = d + dat;
+ a = b + num;
+ while (a < &d[dlen])
+ *b++ = *a++;
+ d[dlen] = '\0'; /* just in case */
+ }
+ ELRE_DEBUG(1,
+ (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
+ num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
+}
+
+
+/* re__strncopy():
+ * Like strncpy without padding.
+ */
+static void
+re__strncopy(wchar_t *a, wchar_t *b, size_t n)
+{
+
+ while (n-- && *b)
+ *a++ = *b++;
+}
+
+/* re_clear_eol():
+ * Find the number of characters we need to clear till the end of line
+ * in order to make sure that we have cleared the previous contents of
+ * the line. fx and sx is the number of characters inserted or deleted
+ * in the first or second diff, diff is the difference between the
+ * number of characters between the new and old line.
+ */
+static void
+re_clear_eol(EditLine *el, int fx, int sx, int diff)
+{
+
+ ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
+ sx, fx, diff));
+
+ if (fx < 0)
+ fx = -fx;
+ if (sx < 0)
+ sx = -sx;
+ if (fx > diff)
+ diff = fx;
+ if (sx > diff)
+ diff = sx;
+
+ ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
+ terminal_clear_EOL(el, diff);
+}
+
+/*****************************************************************
+ re_update_line() is based on finding the middle difference of each line
+ on the screen; vis:
+
+ /old first difference
+ /beginning of line | /old last same /old EOL
+ v v v v
+old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
+new: eddie> Oh, my little buggy says to me, as lurgid as
+ ^ ^ ^ ^
+ \beginning of line | \new last same \new end of line
+ \new first difference
+
+ all are character pointers for the sake of speed. Special cases for
+ no differences, as well as for end of line additions must be handled.
+**************************************************************** */
+
+/* Minimum at which doing an insert it "worth it". This should be about
+ * half the "cost" of going into insert mode, inserting a character, and
+ * going back out. This should really be calculated from the termcap
+ * data... For the moment, a good number for ANSI terminals.
+ */
+#define MIN_END_KEEP 4
+
+static void
+re_update_line(EditLine *el, wchar_t *old, wchar_t *new, int i)
+{
+ wchar_t *o, *n, *p, c;
+ wchar_t *ofd, *ols, *oe, *nfd, *nls, *ne;
+ wchar_t *osb, *ose, *nsb, *nse;
+ int fx, sx;
+ size_t len;
+
+ /*
+ * find first diff
+ */
+ for (o = old, n = new; *o && (*o == *n); o++, n++)
+ continue;
+ ofd = o;
+ nfd = n;
+
+ /*
+ * Find the end of both old and new
+ */
+ while (*o)
+ o++;
+ /*
+ * Remove any trailing blanks off of the end, being careful not to
+ * back up past the beginning.
+ */
+ while (ofd < o) {
+ if (o[-1] != ' ')
+ break;
+ o--;
+ }
+ oe = o;
+ *oe = '\0';
+
+ while (*n)
+ n++;
+
+ /* remove blanks from end of new */
+ while (nfd < n) {
+ if (n[-1] != ' ')
+ break;
+ n--;
+ }
+ ne = n;
+ *ne = '\0';
+
+ /*
+ * if no diff, continue to next line of redraw
+ */
+ if (*ofd == '\0' && *nfd == '\0') {
+ ELRE_DEBUG(1, (__F, "no difference.\r\n"));
+ return;
+ }
+ /*
+ * find last same pointer
+ */
+ while ((o > ofd) && (n > nfd) && (*--o == *--n))
+ continue;
+ ols = ++o;
+ nls = ++n;
+
+ /*
+ * find same beginning and same end
+ */
+ osb = ols;
+ nsb = nls;
+ ose = ols;
+ nse = nls;
+
+ /*
+ * case 1: insert: scan from nfd to nls looking for *ofd
+ */
+ if (*ofd) {
+ for (c = *ofd, n = nfd; n < nls; n++) {
+ if (c == *n) {
+ for (o = ofd, p = n;
+ p < nls && o < ols && *o == *p;
+ o++, p++)
+ continue;
+ /*
+ * if the new match is longer and it's worth
+ * keeping, then we take it
+ */
+ if (((nse - nsb) < (p - n)) &&
+ (2 * (p - n) > n - nfd)) {
+ nsb = n;
+ nse = p;
+ osb = ofd;
+ ose = o;
+ }
+ }
+ }
+ }
+ /*
+ * case 2: delete: scan from ofd to ols looking for *nfd
+ */
+ if (*nfd) {
+ for (c = *nfd, o = ofd; o < ols; o++) {
+ if (c == *o) {
+ for (n = nfd, p = o;
+ p < ols && n < nls && *p == *n;
+ p++, n++)
+ continue;
+ /*
+ * if the new match is longer and it's worth
+ * keeping, then we take it
+ */
+ if (((ose - osb) < (p - o)) &&
+ (2 * (p - o) > o - ofd)) {
+ nsb = nfd;
+ nse = n;
+ osb = o;
+ ose = p;
+ }
+ }
+ }
+ }
+ /*
+ * Pragmatics I: If old trailing whitespace or not enough characters to
+ * save to be worth it, then don't save the last same info.
+ */
+ if ((oe - ols) < MIN_END_KEEP) {
+ ols = oe;
+ nls = ne;
+ }
+ /*
+ * Pragmatics II: if the terminal isn't smart enough, make the data
+ * dumber so the smart update doesn't try anything fancy
+ */
+
+ /*
+ * fx is the number of characters we need to insert/delete: in the
+ * beginning to bring the two same begins together
+ */
+ fx = (int)((nsb - nfd) - (osb - ofd));
+ /*
+ * sx is the number of characters we need to insert/delete: in the
+ * end to bring the two same last parts together
+ */
+ sx = (int)((nls - nse) - (ols - ose));
+
+ if (!EL_CAN_INSERT) {
+ if (fx > 0) {
+ osb = ols;
+ ose = ols;
+ nsb = nls;
+ nse = nls;
+ }
+ if (sx > 0) {
+ ols = oe;
+ nls = ne;
+ }
+ if ((ols - ofd) < (nls - nfd)) {
+ ols = oe;
+ nls = ne;
+ }
+ }
+ if (!EL_CAN_DELETE) {
+ if (fx < 0) {
+ osb = ols;
+ ose = ols;
+ nsb = nls;
+ nse = nls;
+ }
+ if (sx < 0) {
+ ols = oe;
+ nls = ne;
+ }
+ if ((ols - ofd) > (nls - nfd)) {
+ ols = oe;
+ nls = ne;
+ }
+ }
+ /*
+ * Pragmatics III: make sure the middle shifted pointers are correct if
+ * they don't point to anything (we may have moved ols or nls).
+ */
+ /* if the change isn't worth it, don't bother */
+ /* was: if (osb == ose) */
+ if ((ose - osb) < MIN_END_KEEP) {
+ osb = ols;
+ ose = ols;
+ nsb = nls;
+ nse = nls;
+ }
+ /*
+ * Now that we are done with pragmatics we recompute fx, sx
+ */
+ fx = (int)((nsb - nfd) - (osb - ofd));
+ sx = (int)((nls - nse) - (ols - ose));
+
+ ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
+ ELRE_DEBUG(1, (__F, "ofd %td, osb %td, ose %td, ols %td, oe %td\n",
+ ofd - old, osb - old, ose - old, ols - old, oe - old));
+ ELRE_DEBUG(1, (__F, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n",
+ nfd - new, nsb - new, nse - new, nls - new, ne - new));
+ ELRE_DEBUG(1, (__F,
+ "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
+ ELRE_DEBUG(1, (__F,
+ "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
+#ifdef DEBUG_REFRESH
+ re_printstr(el, "old- oe", old, oe);
+ re_printstr(el, "new- ne", new, ne);
+ re_printstr(el, "old-ofd", old, ofd);
+ re_printstr(el, "new-nfd", new, nfd);
+ re_printstr(el, "ofd-osb", ofd, osb);
+ re_printstr(el, "nfd-nsb", nfd, nsb);
+ re_printstr(el, "osb-ose", osb, ose);
+ re_printstr(el, "nsb-nse", nsb, nse);
+ re_printstr(el, "ose-ols", ose, ols);
+ re_printstr(el, "nse-nls", nse, nls);
+ re_printstr(el, "ols- oe", ols, oe);
+ re_printstr(el, "nls- ne", nls, ne);
+#endif /* DEBUG_REFRESH */
+
+ /*
+ * el_cursor.v to this line i MUST be in this routine so that if we
+ * don't have to change the line, we don't move to it. el_cursor.h to
+ * first diff char
+ */
+ terminal_move_to_line(el, i);
+
+ /*
+ * at this point we have something like this:
+ *
+ * /old /ofd /osb /ose /ols /oe
+ * v.....................v v..................v v........v
+ * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
+ * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
+ * ^.....................^ ^..................^ ^........^
+ * \new \nfd \nsb \nse \nls \ne
+ *
+ * fx is the difference in length between the chars between nfd and
+ * nsb, and the chars between ofd and osb, and is thus the number of
+ * characters to delete if < 0 (new is shorter than old, as above),
+ * or insert (new is longer than short).
+ *
+ * sx is the same for the second differences.
+ */
+
+ /*
+ * if we have a net insert on the first difference, AND inserting the
+ * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
+ * character (which is ne if nls != ne, otherwise is nse) off the edge
+ * of the screen (el->el_terminal.t_size.h) else we do the deletes first
+ * so that we keep everything we need to.
+ */
+
+ /*
+ * if the last same is the same like the end, there is no last same
+ * part, otherwise we want to keep the last same part set p to the
+ * last useful old character
+ */
+ p = (ols != oe) ? oe : ose;
+
+ /*
+ * if (There is a diffence in the beginning) && (we need to insert
+ * characters) && (the number of characters to insert is less than
+ * the term width)
+ * We need to do an insert!
+ * else if (we need to delete characters)
+ * We need to delete characters!
+ * else
+ * No insert or delete
+ */
+ if ((nsb != nfd) && fx > 0 &&
+ ((p - old) + fx <= el->el_terminal.t_size.h)) {
+ ELRE_DEBUG(1,
+ (__F, "first diff insert at %td...\r\n", nfd - new));
+ /*
+ * Move to the first char to insert, where the first diff is.
+ */
+ terminal_move_to_char(el, (int)(nfd - new));
+ /*
+ * Check if we have stuff to keep at end
+ */
+ if (nsb != ne) {
+ ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
+ /*
+ * insert fx chars of new starting at nfd
+ */
+ if (fx > 0) {
+ ELRE_DEBUG(!EL_CAN_INSERT, (__F,
+ "ERROR: cannot insert in early first diff\n"));
+ terminal_insertwrite(el, nfd, fx);
+ re_insert(el, old, (int)(ofd - old),
+ el->el_terminal.t_size.h, nfd, fx);
+ }
+ /*
+ * write (nsb-nfd) - fx chars of new starting at
+ * (nfd + fx)
+ */
+ len = (size_t) ((nsb - nfd) - fx);
+ terminal_overwrite(el, (nfd + fx), len);
+ re__strncopy(ofd + fx, nfd + fx, len);
+ } else {
+ ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
+ len = (size_t)(nsb - nfd);
+ terminal_overwrite(el, nfd, len);
+ re__strncopy(ofd, nfd, len);
+ /*
+ * Done
+ */
+ return;
+ }
+ } else if (fx < 0) {
+ ELRE_DEBUG(1,
+ (__F, "first diff delete at %td...\r\n", ofd - old));
+ /*
+ * move to the first char to delete where the first diff is
+ */
+ terminal_move_to_char(el, (int)(ofd - old));
+ /*
+ * Check if we have stuff to save
+ */
+ if (osb != oe) {
+ ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
+ /*
+ * fx is less than zero *always* here but we check
+ * for code symmetry
+ */
+ if (fx < 0) {
+ ELRE_DEBUG(!EL_CAN_DELETE, (__F,
+ "ERROR: cannot delete in first diff\n"));
+ terminal_deletechars(el, -fx);
+ re_delete(el, old, (int)(ofd - old),
+ el->el_terminal.t_size.h, -fx);
+ }
+ /*
+ * write (nsb-nfd) chars of new starting at nfd
+ */
+ len = (size_t) (nsb - nfd);
+ terminal_overwrite(el, nfd, len);
+ re__strncopy(ofd, nfd, len);
+
+ } else {
+ ELRE_DEBUG(1, (__F,
+ "but with nothing left to save\r\n"));
+ /*
+ * write (nsb-nfd) chars of new starting at nfd
+ */
+ terminal_overwrite(el, nfd, (size_t)(nsb - nfd));
+ re_clear_eol(el, fx, sx,
+ (int)((oe - old) - (ne - new)));
+ /*
+ * Done
+ */
+ return;
+ }
+ } else
+ fx = 0;
+
+ if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) {
+ ELRE_DEBUG(1, (__F,
+ "second diff delete at %td...\r\n", (ose - old) + fx));
+ /*
+ * Check if we have stuff to delete
+ */
+ /*
+ * fx is the number of characters inserted (+) or deleted (-)
+ */
+
+ terminal_move_to_char(el, (int)((ose - old) + fx));
+ /*
+ * Check if we have stuff to save
+ */
+ if (ols != oe) {
+ ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
+ /*
+ * Again a duplicate test.
+ */
+ if (sx < 0) {
+ ELRE_DEBUG(!EL_CAN_DELETE, (__F,
+ "ERROR: cannot delete in second diff\n"));
+ terminal_deletechars(el, -sx);
+ }
+ /*
+ * write (nls-nse) chars of new starting at nse
+ */
+ terminal_overwrite(el, nse, (size_t)(nls - nse));
+ } else {
+ ELRE_DEBUG(1, (__F,
+ "but with nothing left to save\r\n"));
+ terminal_overwrite(el, nse, (size_t)(nls - nse));
+ re_clear_eol(el, fx, sx,
+ (int)((oe - old) - (ne - new)));
+ }
+ }
+ /*
+ * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
+ */
+ if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
+ ELRE_DEBUG(1, (__F, "late first diff insert at %td...\r\n",
+ nfd - new));
+
+ terminal_move_to_char(el, (int)(nfd - new));
+ /*
+ * Check if we have stuff to keep at the end
+ */
+ if (nsb != ne) {
+ ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
+ /*
+ * We have to recalculate fx here because we set it
+ * to zero above as a flag saying that we hadn't done
+ * an early first insert.
+ */
+ fx = (int)((nsb - nfd) - (osb - ofd));
+ if (fx > 0) {
+ /*
+ * insert fx chars of new starting at nfd
+ */
+ ELRE_DEBUG(!EL_CAN_INSERT, (__F,
+ "ERROR: cannot insert in late first diff\n"));
+ terminal_insertwrite(el, nfd, fx);
+ re_insert(el, old, (int)(ofd - old),
+ el->el_terminal.t_size.h, nfd, fx);
+ }
+ /*
+ * write (nsb-nfd) - fx chars of new starting at
+ * (nfd + fx)
+ */
+ len = (size_t) ((nsb - nfd) - fx);
+ terminal_overwrite(el, (nfd + fx), len);
+ re__strncopy(ofd + fx, nfd + fx, len);
+ } else {
+ ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
+ len = (size_t) (nsb - nfd);
+ terminal_overwrite(el, nfd, len);
+ re__strncopy(ofd, nfd, len);
+ }
+ }
+ /*
+ * line is now NEW up to nse
+ */
+ if (sx >= 0) {
+ ELRE_DEBUG(1, (__F,
+ "second diff insert at %d...\r\n", (int)(nse - new)));
+ terminal_move_to_char(el, (int)(nse - new));
+ if (ols != oe) {
+ ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
+ if (sx > 0) {
+ /* insert sx chars of new starting at nse */
+ ELRE_DEBUG(!EL_CAN_INSERT, (__F,
+ "ERROR: cannot insert in second diff\n"));
+ terminal_insertwrite(el, nse, sx);
+ }
+ /*
+ * write (nls-nse) - sx chars of new starting at
+ * (nse + sx)
+ */
+ terminal_overwrite(el, (nse + sx),
+ (size_t)((nls - nse) - sx));
+ } else {
+ ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
+ terminal_overwrite(el, nse, (size_t)(nls - nse));
+
+ /*
+ * No need to do a clear-to-end here because we were
+ * doing a second insert, so we will have over
+ * written all of the old string.
+ */
+ }
+ }
+ ELRE_DEBUG(1, (__F, "done.\r\n"));
+}
+
+
+/* re__copy_and_pad():
+ * Copy string and pad with spaces
+ */
+static void
+re__copy_and_pad(wchar_t *dst, const wchar_t *src, size_t width)
+{
+ size_t i;
+
+ for (i = 0; i < width; i++) {
+ if (*src == '\0')
+ break;
+ *dst++ = *src++;
+ }
+
+ for (; i < width; i++)
+ *dst++ = ' ';
+
+ *dst = '\0';
+}
+
+
+/* re_refresh_cursor():
+ * Move to the new cursor position
+ */
+libedit_private void
+re_refresh_cursor(EditLine *el)
+{
+ wchar_t *cp;
+ int h, v, th, w;
+
+ if (el->el_line.cursor >= el->el_line.lastchar) {
+ if (el->el_map.current == el->el_map.alt
+ && el->el_line.lastchar != el->el_line.buffer)
+ el->el_line.cursor = el->el_line.lastchar - 1;
+ else
+ el->el_line.cursor = el->el_line.lastchar;
+ }
+
+ /* first we must find where the cursor is... */
+ h = el->el_prompt.p_pos.h;
+ v = el->el_prompt.p_pos.v;
+ th = el->el_terminal.t_size.h; /* optimize for speed */
+
+ /* do input buffer to el->el_line.cursor */
+ for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
+ switch (ct_chr_class(*cp)) {
+ case CHTYPE_NL: /* handle newline in data part too */
+ h = 0;
+ v++;
+ break;
+ case CHTYPE_TAB: /* if a tab, to next tab stop */
+ while (++h & 07)
+ continue;
+ break;
+ default:
+ w = wcwidth(*cp);
+ if (w > 1 && h + w > th) { /* won't fit on line */
+ h = 0;
+ v++;
+ }
+ h += ct_visual_width(*cp);
+ break;
+ }
+
+ if (h >= th) { /* check, extra long tabs picked up here also */
+ h -= th;
+ v++;
+ }
+ }
+ /* if we have a next character, and it's a doublewidth one, we need to
+ * check whether we need to linebreak for it to fit */
+ if (cp < el->el_line.lastchar && (w = wcwidth(*cp)) > 1)
+ if (h + w > th) {
+ h = 0;
+ v++;
+ }
+
+ /* now go there */
+ terminal_move_to_line(el, v);
+ terminal_move_to_char(el, h);
+ terminal__flush(el);
+}
+
+
+/* re_fastputc():
+ * Add a character fast.
+ */
+static void
+re_fastputc(EditLine *el, wint_t c)
+{
+ int w = wcwidth(c);
+ while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h)
+ re_fastputc(el, ' ');
+
+ terminal__putc(el, c);
+ el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
+ while (--w > 0)
+ el->el_display[el->el_cursor.v][el->el_cursor.h++]
+ = MB_FILL_CHAR;
+
+ if (el->el_cursor.h >= el->el_terminal.t_size.h) {
+ /* if we must overflow */
+ el->el_cursor.h = 0;
+
+ /*
+ * If we would overflow (input is longer than terminal size),
+ * emulate scroll by dropping first line and shuffling the rest.
+ * We do this via pointer shuffling - it's safe in this case
+ * and we avoid memcpy().
+ */
+ if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) {
+ int i, lins = el->el_terminal.t_size.v;
+ wchar_t *firstline = el->el_display[0];
+
+ for(i = 1; i < lins; i++)
+ el->el_display[i - 1] = el->el_display[i];
+
+ re__copy_and_pad(firstline, L"", (size_t)0);
+ el->el_display[i - 1] = firstline;
+ } else {
+ el->el_cursor.v++;
+ el->el_refresh.r_oldcv++;
+ }
+ if (EL_HAS_AUTO_MARGINS) {
+ if (EL_HAS_MAGIC_MARGINS) {
+ terminal__putc(el, ' ');
+ terminal__putc(el, '\b');
+ }
+ } else {
+ terminal__putc(el, '\r');
+ terminal__putc(el, '\n');
+ }
+ }
+}
+
+
+/* re_fastaddc():
+ * we added just one char, handle it fast.
+ * Assumes that screen cursor == real cursor
+ */
+libedit_private void
+re_fastaddc(EditLine *el)
+{
+ wchar_t c;
+ int rhdiff;
+
+ c = el->el_line.cursor[-1];
+
+ if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
+ re_refresh(el); /* too hard to handle */
+ return;
+ }
+ rhdiff = el->el_terminal.t_size.h - el->el_cursor.h -
+ el->el_rprompt.p_pos.h;
+ if (el->el_rprompt.p_pos.h && rhdiff < 3) {
+ re_refresh(el); /* clear out rprompt if less than 1 char gap */
+ return;
+ } /* else (only do at end of line, no TAB) */
+ switch (ct_chr_class(c)) {
+ case CHTYPE_TAB: /* already handled, should never happen here */
+ break;
+ case CHTYPE_NL:
+ case CHTYPE_PRINT:
+ re_fastputc(el, c);
+ break;
+ case CHTYPE_ASCIICTL:
+ case CHTYPE_NONPRINT: {
+ wchar_t visbuf[VISUAL_WIDTH_MAX];
+ ssize_t i, n =
+ ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
+ for (i = 0; n-- > 0; ++i)
+ re_fastputc(el, visbuf[i]);
+ break;
+ }
+ }
+ terminal__flush(el);
+}
+
+
+/* re_clear_display():
+ * clear the screen buffers so that new new prompt starts fresh.
+ */
+libedit_private void
+re_clear_display(EditLine *el)
+{
+ int i;
+
+ el->el_cursor.v = 0;
+ el->el_cursor.h = 0;
+ for (i = 0; i < el->el_terminal.t_size.v; i++)
+ el->el_display[i][0] = '\0';
+ el->el_refresh.r_oldcv = 0;
+}
+
+
+/* re_clear_lines():
+ * Make sure all lines are *really* blank
+ */
+libedit_private void
+re_clear_lines(EditLine *el)
+{
+
+ if (EL_CAN_CEOL) {
+ int i;
+ for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
+ /* for each line on the screen */
+ terminal_move_to_line(el, i);
+ terminal_move_to_char(el, 0);
+ terminal_clear_EOL(el, el->el_terminal.t_size.h);
+ }
+ } else {
+ terminal_move_to_line(el, el->el_refresh.r_oldcv);
+ /* go to last line */
+ terminal__putc(el, '\r'); /* go to BOL */
+ terminal__putc(el, '\n'); /* go to new line */
+ }
+}
diff --git a/third_party/heimdal/lib/libedit/src/refresh.h b/third_party/heimdal/lib/libedit/src/refresh.h
new file mode 100644
index 0000000..621c569
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/refresh.h
@@ -0,0 +1,57 @@
+/* $NetBSD: refresh.h,v 1.10 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)refresh.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.refresh.h: Screen refresh functions
+ */
+#ifndef _h_el_refresh
+#define _h_el_refresh
+
+typedef struct {
+ coord_t r_cursor; /* Refresh cursor position */
+ int r_oldcv; /* Vertical locations */
+ int r_newcv;
+} el_refresh_t;
+
+libedit_private void re_putc(EditLine *, wint_t, int);
+libedit_private void re_clear_lines(EditLine *);
+libedit_private void re_clear_display(EditLine *);
+libedit_private void re_refresh(EditLine *);
+libedit_private void re_refresh_cursor(EditLine *);
+libedit_private void re_fastaddc(EditLine *);
+libedit_private void re_goto_bottom(EditLine *);
+
+#endif /* _h_el_refresh */
diff --git a/third_party/heimdal/lib/libedit/src/search.c b/third_party/heimdal/lib/libedit/src/search.c
new file mode 100644
index 0000000..5226cf5
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/search.c
@@ -0,0 +1,641 @@
+/* $NetBSD: search.c,v 1.47 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: search.c,v 1.47 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * search.c: History and character search functions
+ */
+#include <stdlib.h>
+#include <string.h>
+#if defined(REGEX)
+#include <regex.h>
+#elif defined(REGEXP)
+#include <regexp.h>
+#endif
+
+#include "el.h"
+#include "common.h"
+#include "fcns.h"
+
+/*
+ * Adjust cursor in vi mode to include the character under it
+ */
+#define EL_CURSOR(el) \
+ ((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \
+ ((el)->el_map.current == (el)->el_map.alt)))
+
+/* search_init():
+ * Initialize the search stuff
+ */
+libedit_private int
+search_init(EditLine *el)
+{
+
+ el->el_search.patbuf = el_malloc(EL_BUFSIZ *
+ sizeof(*el->el_search.patbuf));
+ if (el->el_search.patbuf == NULL)
+ return -1;
+ el->el_search.patbuf[0] = L'\0';
+ el->el_search.patlen = 0;
+ el->el_search.patdir = -1;
+ el->el_search.chacha = L'\0';
+ el->el_search.chadir = CHAR_FWD;
+ el->el_search.chatflg = 0;
+ return 0;
+}
+
+
+/* search_end():
+ * Initialize the search stuff
+ */
+libedit_private void
+search_end(EditLine *el)
+{
+
+ el_free(el->el_search.patbuf);
+ el->el_search.patbuf = NULL;
+}
+
+
+#ifdef REGEXP
+/* regerror():
+ * Handle regular expression errors
+ */
+void
+/*ARGSUSED*/
+regerror(const char *msg)
+{
+}
+#endif
+
+
+/* el_match():
+ * Return if string matches pattern
+ */
+libedit_private int
+el_match(const wchar_t *str, const wchar_t *pat)
+{
+ static ct_buffer_t conv;
+#if defined (REGEX)
+ regex_t re;
+ int rv;
+#elif defined (REGEXP)
+ regexp *rp;
+ int rv;
+#else
+ extern char *re_comp(const char *);
+ extern int re_exec(const char *);
+#endif
+
+ if (wcsstr(str, pat) != 0)
+ return 1;
+
+#if defined(REGEX)
+ if (regcomp(&re, ct_encode_string(pat, &conv), 0) == 0) {
+ rv = regexec(&re, ct_encode_string(str, &conv), (size_t)0, NULL,
+ 0) == 0;
+ regfree(&re);
+ } else {
+ rv = 0;
+ }
+ return rv;
+#elif defined(REGEXP)
+ if ((re = regcomp(ct_encode_string(pat, &conv))) != NULL) {
+ rv = regexec(re, ct_encode_string(str, &conv));
+ el_free(re);
+ } else {
+ rv = 0;
+ }
+ return rv;
+#else
+ if (re_comp(ct_encode_string(pat, &conv)) != NULL)
+ return 0;
+ else
+ return re_exec(ct_encode_string(str, &conv)) == 1;
+#endif
+}
+
+
+/* c_hmatch():
+ * return True if the pattern matches the prefix
+ */
+libedit_private int
+c_hmatch(EditLine *el, const wchar_t *str)
+{
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "match `%s' with `%s'\n",
+ el->el_search.patbuf, str);
+#endif /* SDEBUG */
+
+ return el_match(str, el->el_search.patbuf);
+}
+
+
+/* c_setpat():
+ * Set the history seatch pattern
+ */
+libedit_private void
+c_setpat(EditLine *el)
+{
+ if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY &&
+ el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) {
+ el->el_search.patlen =
+ (size_t)(EL_CURSOR(el) - el->el_line.buffer);
+ if (el->el_search.patlen >= EL_BUFSIZ)
+ el->el_search.patlen = EL_BUFSIZ - 1;
+ if (el->el_search.patlen != 0) {
+ (void) wcsncpy(el->el_search.patbuf, el->el_line.buffer,
+ el->el_search.patlen);
+ el->el_search.patbuf[el->el_search.patlen] = '\0';
+ } else
+ el->el_search.patlen = wcslen(el->el_search.patbuf);
+ }
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "\neventno = %d\n",
+ el->el_history.eventno);
+ (void) fprintf(el->el_errfile, "patlen = %d\n", el->el_search.patlen);
+ (void) fprintf(el->el_errfile, "patbuf = \"%s\"\n",
+ el->el_search.patbuf);
+ (void) fprintf(el->el_errfile, "cursor %d lastchar %d\n",
+ EL_CURSOR(el) - el->el_line.buffer,
+ el->el_line.lastchar - el->el_line.buffer);
+#endif
+}
+
+
+/* ce_inc_search():
+ * Emacs incremental search
+ */
+libedit_private el_action_t
+ce_inc_search(EditLine *el, int dir)
+{
+ static const wchar_t STRfwd[] = L"fwd", STRbck[] = L"bck";
+ static wchar_t pchar = L':'; /* ':' = normal, '?' = failed */
+ static wchar_t endcmd[2] = {'\0', '\0'};
+ wchar_t *ocursor = el->el_line.cursor, oldpchar = pchar, ch;
+ const wchar_t *cp;
+
+ el_action_t ret = CC_NORM;
+
+ int ohisteventno = el->el_history.eventno;
+ size_t oldpatlen = el->el_search.patlen;
+ int newdir = dir;
+ int done, redo;
+
+ if (el->el_line.lastchar + sizeof(STRfwd) /
+ sizeof(*el->el_line.lastchar) + 2 +
+ el->el_search.patlen >= el->el_line.limit)
+ return CC_ERROR;
+
+ for (;;) {
+
+ if (el->el_search.patlen == 0) { /* first round */
+ pchar = ':';
+#ifdef ANCHOR
+#define LEN 2
+ el->el_search.patbuf[el->el_search.patlen++] = '.';
+ el->el_search.patbuf[el->el_search.patlen++] = '*';
+#else
+#define LEN 0
+#endif
+ }
+ done = redo = 0;
+ *el->el_line.lastchar++ = '\n';
+ for (cp = (newdir == ED_SEARCH_PREV_HISTORY) ? STRbck : STRfwd;
+ *cp; *el->el_line.lastchar++ = *cp++)
+ continue;
+ *el->el_line.lastchar++ = pchar;
+ for (cp = &el->el_search.patbuf[LEN];
+ cp < &el->el_search.patbuf[el->el_search.patlen];
+ *el->el_line.lastchar++ = *cp++)
+ continue;
+ *el->el_line.lastchar = '\0';
+ re_refresh(el);
+
+ if (el_wgetc(el, &ch) != 1)
+ return ed_end_of_file(el, 0);
+
+ switch (el->el_map.current[(unsigned char) ch]) {
+ case ED_INSERT:
+ case ED_DIGIT:
+ if (el->el_search.patlen >= EL_BUFSIZ - LEN)
+ terminal_beep(el);
+ else {
+ el->el_search.patbuf[el->el_search.patlen++] =
+ ch;
+ *el->el_line.lastchar++ = ch;
+ *el->el_line.lastchar = '\0';
+ re_refresh(el);
+ }
+ break;
+
+ case EM_INC_SEARCH_NEXT:
+ newdir = ED_SEARCH_NEXT_HISTORY;
+ redo++;
+ break;
+
+ case EM_INC_SEARCH_PREV:
+ newdir = ED_SEARCH_PREV_HISTORY;
+ redo++;
+ break;
+
+ case EM_DELETE_PREV_CHAR:
+ case ED_DELETE_PREV_CHAR:
+ if (el->el_search.patlen > LEN)
+ done++;
+ else
+ terminal_beep(el);
+ break;
+
+ default:
+ switch (ch) {
+ case 0007: /* ^G: Abort */
+ ret = CC_ERROR;
+ done++;
+ break;
+
+ case 0027: /* ^W: Append word */
+ /* No can do if globbing characters in pattern */
+ for (cp = &el->el_search.patbuf[LEN];; cp++)
+ if (cp >= &el->el_search.patbuf[
+ el->el_search.patlen]) {
+ el->el_line.cursor +=
+ el->el_search.patlen - LEN - 1;
+ cp = c__next_word(el->el_line.cursor,
+ el->el_line.lastchar, 1,
+ ce__isword);
+ while (el->el_line.cursor < cp &&
+ *el->el_line.cursor != '\n') {
+ if (el->el_search.patlen >=
+ EL_BUFSIZ - LEN) {
+ terminal_beep(el);
+ break;
+ }
+ el->el_search.patbuf[el->el_search.patlen++] =
+ *el->el_line.cursor;
+ *el->el_line.lastchar++ =
+ *el->el_line.cursor++;
+ }
+ el->el_line.cursor = ocursor;
+ *el->el_line.lastchar = '\0';
+ re_refresh(el);
+ break;
+ } else if (isglob(*cp)) {
+ terminal_beep(el);
+ break;
+ }
+ break;
+
+ default: /* Terminate and execute cmd */
+ endcmd[0] = ch;
+ el_wpush(el, endcmd);
+ /* FALLTHROUGH */
+
+ case 0033: /* ESC: Terminate */
+ ret = CC_REFRESH;
+ done++;
+ break;
+ }
+ break;
+ }
+
+ while (el->el_line.lastchar > el->el_line.buffer &&
+ *el->el_line.lastchar != '\n')
+ *el->el_line.lastchar-- = '\0';
+ *el->el_line.lastchar = '\0';
+
+ if (!done) {
+
+ /* Can't search if unmatched '[' */
+ for (cp = &el->el_search.patbuf[el->el_search.patlen-1],
+ ch = L']';
+ cp >= &el->el_search.patbuf[LEN];
+ cp--)
+ if (*cp == '[' || *cp == ']') {
+ ch = *cp;
+ break;
+ }
+ if (el->el_search.patlen > LEN && ch != L'[') {
+ if (redo && newdir == dir) {
+ if (pchar == '?') { /* wrap around */
+ el->el_history.eventno =
+ newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff;
+ if (hist_get(el) == CC_ERROR)
+ /* el->el_history.event
+ * no was fixed by
+ * first call */
+ (void) hist_get(el);
+ el->el_line.cursor = newdir ==
+ ED_SEARCH_PREV_HISTORY ?
+ el->el_line.lastchar :
+ el->el_line.buffer;
+ } else
+ el->el_line.cursor +=
+ newdir ==
+ ED_SEARCH_PREV_HISTORY ?
+ -1 : 1;
+ }
+#ifdef ANCHOR
+ el->el_search.patbuf[el->el_search.patlen++] =
+ '.';
+ el->el_search.patbuf[el->el_search.patlen++] =
+ '*';
+#endif
+ el->el_search.patbuf[el->el_search.patlen] =
+ '\0';
+ if (el->el_line.cursor < el->el_line.buffer ||
+ el->el_line.cursor > el->el_line.lastchar ||
+ (ret = ce_search_line(el, newdir))
+ == CC_ERROR) {
+ /* avoid c_setpat */
+ el->el_state.lastcmd =
+ (el_action_t) newdir;
+ ret = (el_action_t)
+ (newdir == ED_SEARCH_PREV_HISTORY ?
+ ed_search_prev_history(el, 0) :
+ ed_search_next_history(el, 0));
+ if (ret != CC_ERROR) {
+ el->el_line.cursor = newdir ==
+ ED_SEARCH_PREV_HISTORY ?
+ el->el_line.lastchar :
+ el->el_line.buffer;
+ (void) ce_search_line(el,
+ newdir);
+ }
+ }
+ el->el_search.patlen -= LEN;
+ el->el_search.patbuf[el->el_search.patlen] =
+ '\0';
+ if (ret == CC_ERROR) {
+ terminal_beep(el);
+ if (el->el_history.eventno !=
+ ohisteventno) {
+ el->el_history.eventno =
+ ohisteventno;
+ if (hist_get(el) == CC_ERROR)
+ return CC_ERROR;
+ }
+ el->el_line.cursor = ocursor;
+ pchar = '?';
+ } else {
+ pchar = ':';
+ }
+ }
+ ret = ce_inc_search(el, newdir);
+
+ if (ret == CC_ERROR && pchar == '?' && oldpchar == ':')
+ /*
+ * break abort of failed search at last
+ * non-failed
+ */
+ ret = CC_NORM;
+
+ }
+ if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
+ /* restore on normal return or error exit */
+ pchar = oldpchar;
+ el->el_search.patlen = oldpatlen;
+ if (el->el_history.eventno != ohisteventno) {
+ el->el_history.eventno = ohisteventno;
+ if (hist_get(el) == CC_ERROR)
+ return CC_ERROR;
+ }
+ el->el_line.cursor = ocursor;
+ if (ret == CC_ERROR)
+ re_refresh(el);
+ }
+ if (done || ret != CC_NORM)
+ return ret;
+ }
+}
+
+
+/* cv_search():
+ * Vi search.
+ */
+libedit_private el_action_t
+cv_search(EditLine *el, int dir)
+{
+ wchar_t ch;
+ wchar_t tmpbuf[EL_BUFSIZ];
+ ssize_t tmplen;
+
+#ifdef ANCHOR
+ tmpbuf[0] = '.';
+ tmpbuf[1] = '*';
+#endif
+ tmplen = LEN;
+
+ el->el_search.patdir = dir;
+
+ tmplen = c_gets(el, &tmpbuf[LEN],
+ dir == ED_SEARCH_PREV_HISTORY ? L"\n/" : L"\n?" );
+ if (tmplen == -1)
+ return CC_REFRESH;
+
+ tmplen += LEN;
+ ch = tmpbuf[tmplen];
+ tmpbuf[tmplen] = '\0';
+
+ if (tmplen == LEN) {
+ /*
+ * Use the old pattern, but wild-card it.
+ */
+ if (el->el_search.patlen == 0) {
+ re_refresh(el);
+ return CC_ERROR;
+ }
+#ifdef ANCHOR
+ if (el->el_search.patbuf[0] != '.' &&
+ el->el_search.patbuf[0] != '*') {
+ (void) wcsncpy(tmpbuf, el->el_search.patbuf,
+ sizeof(tmpbuf) / sizeof(*tmpbuf) - 1);
+ el->el_search.patbuf[0] = '.';
+ el->el_search.patbuf[1] = '*';
+ (void) wcsncpy(&el->el_search.patbuf[2], tmpbuf,
+ EL_BUFSIZ - 3);
+ el->el_search.patlen++;
+ el->el_search.patbuf[el->el_search.patlen++] = '.';
+ el->el_search.patbuf[el->el_search.patlen++] = '*';
+ el->el_search.patbuf[el->el_search.patlen] = '\0';
+ }
+#endif
+ } else {
+#ifdef ANCHOR
+ tmpbuf[tmplen++] = '.';
+ tmpbuf[tmplen++] = '*';
+#endif
+ tmpbuf[tmplen] = '\0';
+ (void) wcsncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1);
+ el->el_search.patlen = (size_t)tmplen;
+ }
+ el->el_state.lastcmd = (el_action_t) dir; /* avoid c_setpat */
+ el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer;
+ if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) :
+ ed_search_next_history(el, 0)) == CC_ERROR) {
+ re_refresh(el);
+ return CC_ERROR;
+ }
+ if (ch == 0033) {
+ re_refresh(el);
+ return ed_newline(el, 0);
+ }
+ return CC_REFRESH;
+}
+
+
+/* ce_search_line():
+ * Look for a pattern inside a line
+ */
+libedit_private el_action_t
+ce_search_line(EditLine *el, int dir)
+{
+ wchar_t *cp = el->el_line.cursor;
+ wchar_t *pattern = el->el_search.patbuf;
+ wchar_t oc, *ocp;
+#ifdef ANCHOR
+ ocp = &pattern[1];
+ oc = *ocp;
+ *ocp = '^';
+#else
+ ocp = pattern;
+ oc = *ocp;
+#endif
+
+ if (dir == ED_SEARCH_PREV_HISTORY) {
+ for (; cp >= el->el_line.buffer; cp--) {
+ if (el_match(cp, ocp)) {
+ *ocp = oc;
+ el->el_line.cursor = cp;
+ return CC_NORM;
+ }
+ }
+ *ocp = oc;
+ return CC_ERROR;
+ } else {
+ for (; *cp != '\0' && cp < el->el_line.limit; cp++) {
+ if (el_match(cp, ocp)) {
+ *ocp = oc;
+ el->el_line.cursor = cp;
+ return CC_NORM;
+ }
+ }
+ *ocp = oc;
+ return CC_ERROR;
+ }
+}
+
+
+/* cv_repeat_srch():
+ * Vi repeat search
+ */
+libedit_private el_action_t
+cv_repeat_srch(EditLine *el, wint_t c)
+{
+
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "dir %d patlen %d patbuf %s\n",
+ c, el->el_search.patlen, ct_encode_string(el->el_search.patbuf));
+#endif
+
+ el->el_state.lastcmd = (el_action_t) c; /* Hack to stop c_setpat */
+ el->el_line.lastchar = el->el_line.buffer;
+
+ switch (c) {
+ case ED_SEARCH_NEXT_HISTORY:
+ return ed_search_next_history(el, 0);
+ case ED_SEARCH_PREV_HISTORY:
+ return ed_search_prev_history(el, 0);
+ default:
+ return CC_ERROR;
+ }
+}
+
+
+/* cv_csearch():
+ * Vi character search
+ */
+libedit_private el_action_t
+cv_csearch(EditLine *el, int direction, wint_t ch, int count, int tflag)
+{
+ wchar_t *cp;
+
+ if (ch == 0)
+ return CC_ERROR;
+
+ if (ch == (wint_t)-1) {
+ if (el_wgetc(el, &ch) != 1)
+ return ed_end_of_file(el, 0);
+ }
+
+ /* Save for ';' and ',' commands */
+ el->el_search.chacha = ch;
+ el->el_search.chadir = direction;
+ el->el_search.chatflg = (char)tflag;
+
+ cp = el->el_line.cursor;
+ while (count--) {
+ if ((wint_t)*cp == ch)
+ cp += direction;
+ for (;;cp += direction) {
+ if (cp >= el->el_line.lastchar)
+ return CC_ERROR;
+ if (cp < el->el_line.buffer)
+ return CC_ERROR;
+ if ((wint_t)*cp == ch)
+ break;
+ }
+ }
+
+ if (tflag)
+ cp -= direction;
+
+ el->el_line.cursor = cp;
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ if (direction > 0)
+ el->el_line.cursor++;
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
diff --git a/third_party/heimdal/lib/libedit/src/search.h b/third_party/heimdal/lib/libedit/src/search.h
new file mode 100644
index 0000000..4ca39c4
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/search.h
@@ -0,0 +1,64 @@
+/* $NetBSD: search.h,v 1.14 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)search.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.search.h: Line and history searching utilities
+ */
+#ifndef _h_el_search
+#define _h_el_search
+
+typedef struct el_search_t {
+ wchar_t *patbuf; /* The pattern buffer */
+ size_t patlen; /* Length of the pattern buffer */
+ int patdir; /* Direction of the last search */
+ int chadir; /* Character search direction */
+ wchar_t chacha; /* Character we are looking for */
+ char chatflg; /* 0 if f, 1 if t */
+} el_search_t;
+
+
+libedit_private int el_match(const wchar_t *, const wchar_t *);
+libedit_private int search_init(EditLine *);
+libedit_private void search_end(EditLine *);
+libedit_private int c_hmatch(EditLine *, const wchar_t *);
+libedit_private void c_setpat(EditLine *);
+libedit_private el_action_t ce_inc_search(EditLine *, int);
+libedit_private el_action_t cv_search(EditLine *, int);
+libedit_private el_action_t ce_search_line(EditLine *, int);
+libedit_private el_action_t cv_repeat_srch(EditLine *, wint_t);
+libedit_private el_action_t cv_csearch(EditLine *, int, wint_t, int, int);
+
+#endif /* _h_el_search */
diff --git a/third_party/heimdal/lib/libedit/src/shlib_version b/third_party/heimdal/lib/libedit/src/shlib_version
new file mode 100644
index 0000000..303609d
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/shlib_version
@@ -0,0 +1,5 @@
+# $NetBSD: shlib_version,v 1.19 2013/01/22 20:23:21 christos Exp $
+# Remember to update distrib/sets/lists/base/shl.* when changing
+#
+major=3
+minor=1
diff --git a/third_party/heimdal/lib/libedit/src/sig.c b/third_party/heimdal/lib/libedit/src/sig.c
new file mode 100644
index 0000000..83742a3
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/sig.c
@@ -0,0 +1,205 @@
+/* $NetBSD: sig.c,v 1.26 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)sig.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: sig.c,v 1.26 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * sig.c: Signal handling stuff.
+ * our policy is to trap all signals, set a good state
+ * and pass the ball to our caller.
+ */
+#include <errno.h>
+#include <stdlib.h>
+
+#include "el.h"
+#include "common.h"
+
+static EditLine *sel = NULL;
+
+static const int sighdl[] = {
+#define _DO(a) (a),
+ ALLSIGS
+#undef _DO
+ - 1
+};
+
+static void sig_handler(int);
+
+/* sig_handler():
+ * This is the handler called for all signals
+ * XXX: we cannot pass any data so we just store the old editline
+ * state in a private variable
+ */
+static void
+sig_handler(int signo)
+{
+ int i, save_errno;
+ sigset_t nset, oset;
+
+ save_errno = errno;
+ (void) sigemptyset(&nset);
+ (void) sigaddset(&nset, signo);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ sel->el_signal->sig_no = signo;
+
+ switch (signo) {
+ case SIGCONT:
+ tty_rawmode(sel);
+ if (ed_redisplay(sel, 0) == CC_REFRESH)
+ re_refresh(sel);
+ terminal__flush(sel);
+ break;
+
+ case SIGWINCH:
+ el_resize(sel);
+ break;
+
+ default:
+ tty_cookedmode(sel);
+ break;
+ }
+
+ for (i = 0; sighdl[i] != -1; i++)
+ if (signo == sighdl[i])
+ break;
+
+ (void) sigaction(signo, &sel->el_signal->sig_action[i], NULL);
+ sel->el_signal->sig_action[i].sa_handler = SIG_ERR;
+ sel->el_signal->sig_action[i].sa_flags = 0;
+ sigemptyset(&sel->el_signal->sig_action[i].sa_mask);
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+ (void) kill(0, signo);
+ errno = save_errno;
+}
+
+
+/* sig_init():
+ * Initialize all signal stuff
+ */
+libedit_private int
+sig_init(EditLine *el)
+{
+ size_t i;
+ sigset_t *nset, oset;
+
+ el->el_signal = el_malloc(sizeof(*el->el_signal));
+ if (el->el_signal == NULL)
+ return -1;
+
+ nset = &el->el_signal->sig_set;
+ (void) sigemptyset(nset);
+#define _DO(a) (void) sigaddset(nset, a);
+ ALLSIGS
+#undef _DO
+ (void) sigprocmask(SIG_BLOCK, nset, &oset);
+
+ for (i = 0; sighdl[i] != -1; i++) {
+ el->el_signal->sig_action[i].sa_handler = SIG_ERR;
+ el->el_signal->sig_action[i].sa_flags = 0;
+ sigemptyset(&el->el_signal->sig_action[i].sa_mask);
+ }
+
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+
+ return 0;
+}
+
+
+/* sig_end():
+ * Clear all signal stuff
+ */
+libedit_private void
+sig_end(EditLine *el)
+{
+
+ el_free(el->el_signal);
+ el->el_signal = NULL;
+}
+
+
+/* sig_set():
+ * set all the signal handlers
+ */
+libedit_private void
+sig_set(EditLine *el)
+{
+ size_t i;
+ sigset_t oset;
+ struct sigaction osa, nsa;
+
+ nsa.sa_handler = sig_handler;
+ nsa.sa_flags = 0;
+ sigemptyset(&nsa.sa_mask);
+
+ (void) sigprocmask(SIG_BLOCK, &el->el_signal->sig_set, &oset);
+
+ for (i = 0; sighdl[i] != -1; i++) {
+ /* This could happen if we get interrupted */
+ if (sigaction(sighdl[i], &nsa, &osa) != -1 &&
+ osa.sa_handler != sig_handler)
+ el->el_signal->sig_action[i] = osa;
+ }
+ sel = el;
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
+
+/* sig_clr():
+ * clear all the signal handlers
+ */
+libedit_private void
+sig_clr(EditLine *el)
+{
+ size_t i;
+ sigset_t oset;
+
+ (void) sigprocmask(SIG_BLOCK, &el->el_signal->sig_set, &oset);
+
+ for (i = 0; sighdl[i] != -1; i++)
+ if (el->el_signal->sig_action[i].sa_handler != SIG_ERR)
+ (void)sigaction(sighdl[i],
+ &el->el_signal->sig_action[i], NULL);
+
+ sel = NULL; /* we are going to die if the handler is
+ * called */
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+}
diff --git a/third_party/heimdal/lib/libedit/src/sig.h b/third_party/heimdal/lib/libedit/src/sig.h
new file mode 100644
index 0000000..5ee453f
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/sig.h
@@ -0,0 +1,70 @@
+/* $NetBSD: sig.h,v 1.11 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sig.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.sig.h: Signal handling functions
+ */
+#ifndef _h_el_sig
+#define _h_el_sig
+
+#include <signal.h>
+
+/*
+ * Define here all the signals we are going to handle
+ * The _DO macro is used to iterate in the source code
+ */
+#define ALLSIGS \
+ _DO(SIGINT) \
+ _DO(SIGTSTP) \
+ _DO(SIGQUIT) \
+ _DO(SIGHUP) \
+ _DO(SIGTERM) \
+ _DO(SIGCONT) \
+ _DO(SIGWINCH)
+#define ALLSIGSNO 7
+
+typedef struct {
+ struct sigaction sig_action[ALLSIGSNO];
+ sigset_t sig_set;
+ volatile sig_atomic_t sig_no;
+} *el_signal_t;
+
+libedit_private void sig_end(EditLine*);
+libedit_private int sig_init(EditLine*);
+libedit_private void sig_set(EditLine*);
+libedit_private void sig_clr(EditLine*);
+
+#endif /* _h_el_sig */
diff --git a/third_party/heimdal/lib/libedit/src/sys.h b/third_party/heimdal/lib/libedit/src/sys.h
new file mode 100644
index 0000000..4005781
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/sys.h
@@ -0,0 +1,112 @@
+/* $NetBSD: sys.h,v 1.27 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sys.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * sys.h: Put all the stupid compiler and system dependencies here...
+ */
+#ifndef _h_sys
+#define _h_sys
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
+# define __attribute__(A)
+#endif
+
+#ifndef __BEGIN_DECLS
+# ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+# else
+# define __BEGIN_DECLS
+# define __END_DECLS
+# endif
+#endif
+
+/* If your compiler does not support this, define it to be empty. */
+#define libedit_private __attribute__((__visibility__("hidden")))
+
+#ifndef __arraycount
+# define __arraycount(a) (sizeof(a) / sizeof(*(a)))
+#endif
+
+#include <stdio.h>
+
+#ifndef HAVE_STRLCAT
+#define strlcat libedit_strlcat
+size_t strlcat(char *dst, const char *src, size_t size);
+#endif
+
+#ifndef HAVE_STRLCPY
+#define strlcpy libedit_strlcpy
+size_t strlcpy(char *dst, const char *src, size_t size);
+#endif
+
+#ifndef HAVE_GETLINE
+#define getline libedit_getline
+ssize_t getline(char **line, size_t *len, FILE *fp);
+#endif
+
+#ifndef _DIAGASSERT
+#define _DIAGASSERT(x)
+#endif
+
+#ifndef __RCSID
+#define __RCSID(x)
+#endif
+
+#ifndef HAVE_U_INT32_T
+typedef unsigned int u_int32_t;
+#endif
+
+#ifndef HAVE_SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
+
+#define REGEX /* Use POSIX.2 regular expression functions */
+#undef REGEXP /* Use UNIX V8 regular expression functions */
+
+#endif /* _h_sys */
diff --git a/third_party/heimdal/lib/libedit/src/terminal.c b/third_party/heimdal/lib/libedit/src/terminal.c
new file mode 100644
index 0000000..5d2271f
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/terminal.c
@@ -0,0 +1,1691 @@
+/* $NetBSD: terminal.c,v 1.32 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95";
+#else
+__RCSID("$NetBSD: terminal.c,v 1.32 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * terminal.c: Editor/termcap-curses interface
+ * We have to declare a static variable here, since the
+ * termcap putchar routine does not take an argument!
+ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_TERMCAP_H
+#include <termcap.h>
+#endif
+#ifdef HAVE_CURSES_H
+#include <curses.h>
+#elif HAVE_NCURSES_H
+#include <ncurses.h>
+#endif
+
+/* Solaris's term.h does horrid things. */
+#if defined(HAVE_TERM_H) && !defined(__sun) && !defined(HAVE_TERMCAP_H)
+#include <term.h>
+#endif
+
+#ifdef _REENTRANT
+#include <pthread.h>
+#endif
+
+#include "el.h"
+#include "fcns.h"
+
+/*
+ * IMPORTANT NOTE: these routines are allowed to look at the current screen
+ * and the current position assuming that it is correct. If this is not
+ * true, then the update will be WRONG! This is (should be) a valid
+ * assumption...
+ */
+
+#define TC_BUFSIZE ((size_t)2048)
+
+#define GoodStr(a) (el->el_terminal.t_str[a] != NULL && \
+ el->el_terminal.t_str[a][0] != '\0')
+#define Str(a) el->el_terminal.t_str[a]
+#define Val(a) el->el_terminal.t_val[a]
+
+static const struct termcapstr {
+ const char *name;
+ const char *long_name;
+} tstr[] = {
+#define T_al 0
+ { "al", "add new blank line" },
+#define T_bl 1
+ { "bl", "audible bell" },
+#define T_cd 2
+ { "cd", "clear to bottom" },
+#define T_ce 3
+ { "ce", "clear to end of line" },
+#define T_ch 4
+ { "ch", "cursor to horiz pos" },
+#define T_cl 5
+ { "cl", "clear screen" },
+#define T_dc 6
+ { "dc", "delete a character" },
+#define T_dl 7
+ { "dl", "delete a line" },
+#define T_dm 8
+ { "dm", "start delete mode" },
+#define T_ed 9
+ { "ed", "end delete mode" },
+#define T_ei 10
+ { "ei", "end insert mode" },
+#define T_fs 11
+ { "fs", "cursor from status line" },
+#define T_ho 12
+ { "ho", "home cursor" },
+#define T_ic 13
+ { "ic", "insert character" },
+#define T_im 14
+ { "im", "start insert mode" },
+#define T_ip 15
+ { "ip", "insert padding" },
+#define T_kd 16
+ { "kd", "sends cursor down" },
+#define T_kl 17
+ { "kl", "sends cursor left" },
+#define T_kr 18
+ { "kr", "sends cursor right" },
+#define T_ku 19
+ { "ku", "sends cursor up" },
+#define T_md 20
+ { "md", "begin bold" },
+#define T_me 21
+ { "me", "end attributes" },
+#define T_nd 22
+ { "nd", "non destructive space" },
+#define T_se 23
+ { "se", "end standout" },
+#define T_so 24
+ { "so", "begin standout" },
+#define T_ts 25
+ { "ts", "cursor to status line" },
+#define T_up 26
+ { "up", "cursor up one" },
+#define T_us 27
+ { "us", "begin underline" },
+#define T_ue 28
+ { "ue", "end underline" },
+#define T_vb 29
+ { "vb", "visible bell" },
+#define T_DC 30
+ { "DC", "delete multiple chars" },
+#define T_DO 31
+ { "DO", "cursor down multiple" },
+#define T_IC 32
+ { "IC", "insert multiple chars" },
+#define T_LE 33
+ { "LE", "cursor left multiple" },
+#define T_RI 34
+ { "RI", "cursor right multiple" },
+#define T_UP 35
+ { "UP", "cursor up multiple" },
+#define T_kh 36
+ { "kh", "send cursor home" },
+#define T_at7 37
+ { "@7", "send cursor end" },
+#define T_kD 38
+ { "kD", "send cursor delete" },
+#define T_str 39
+ { NULL, NULL }
+};
+
+static const struct termcapval {
+ const char *name;
+ const char *long_name;
+} tval[] = {
+#define T_am 0
+ { "am", "has automatic margins" },
+#define T_pt 1
+ { "pt", "has physical tabs" },
+#define T_li 2
+ { "li", "Number of lines" },
+#define T_co 3
+ { "co", "Number of columns" },
+#define T_km 4
+ { "km", "Has meta key" },
+#define T_xt 5
+ { "xt", "Tab chars destructive" },
+#define T_xn 6
+ { "xn", "newline ignored at right margin" },
+#define T_MT 7
+ { "MT", "Has meta key" }, /* XXX? */
+#define T_val 8
+ { NULL, NULL, }
+};
+/* do two or more of the attributes use me */
+
+static void terminal_setflags(EditLine *);
+static int terminal_rebuffer_display(EditLine *);
+static void terminal_free_display(EditLine *);
+static int terminal_alloc_display(EditLine *);
+static void terminal_alloc(EditLine *, const struct termcapstr *,
+ const char *);
+static void terminal_init_arrow(EditLine *);
+static void terminal_reset_arrow(EditLine *);
+static int terminal_putc(int);
+static void terminal_tputs(EditLine *, const char *, int);
+
+#ifdef _REENTRANT
+static pthread_mutex_t terminal_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+static FILE *terminal_outfile = NULL;
+
+#ifndef HAVE_TGETENT
+/* provide a stub curses which fails all calls if we have no tgetent et al */
+#define tgoto(x, y, z) (char *)0
+#define tgetstr(x, y) (char *)0
+#define tgetent(x, y) -1;
+#define tputs(x, y, z) -1
+#define tgetflag(x) -1
+#define tgetnum(x) -1
+#endif
+
+/* terminal_setflags():
+ * Set the terminal capability flags
+ */
+static void
+terminal_setflags(EditLine *el)
+{
+ EL_FLAGS = 0;
+ if (el->el_tty.t_tabs)
+ EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0;
+
+ EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0;
+ EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0;
+ EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0;
+ EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ?
+ TERM_CAN_INSERT : 0;
+ EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0;
+ EL_FLAGS |= Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0;
+ EL_FLAGS |= Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 0;
+
+ if (GoodStr(T_me) && GoodStr(T_ue))
+ EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ?
+ TERM_CAN_ME : 0;
+ else
+ EL_FLAGS &= ~TERM_CAN_ME;
+ if (GoodStr(T_me) && GoodStr(T_se))
+ EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ?
+ TERM_CAN_ME : 0;
+
+
+#ifdef DEBUG_SCREEN
+ if (!EL_CAN_UP) {
+ (void) fprintf(el->el_errfile,
+ "WARNING: Your terminal cannot move up.\n");
+ (void) fprintf(el->el_errfile,
+ "Editing may be odd for long lines.\n");
+ }
+ if (!EL_CAN_CEOL)
+ (void) fprintf(el->el_errfile, "no clear EOL capability.\n");
+ if (!EL_CAN_DELETE)
+ (void) fprintf(el->el_errfile, "no delete char capability.\n");
+ if (!EL_CAN_INSERT)
+ (void) fprintf(el->el_errfile, "no insert char capability.\n");
+#endif /* DEBUG_SCREEN */
+}
+
+/* terminal_init():
+ * Initialize the terminal stuff
+ */
+libedit_private int
+terminal_init(EditLine *el)
+{
+
+ el->el_terminal.t_buf = el_malloc(TC_BUFSIZE *
+ sizeof(*el->el_terminal.t_buf));
+ if (el->el_terminal.t_buf == NULL)
+ goto fail1;
+ el->el_terminal.t_cap = el_malloc(TC_BUFSIZE *
+ sizeof(*el->el_terminal.t_cap));
+ if (el->el_terminal.t_cap == NULL)
+ goto fail2;
+ el->el_terminal.t_fkey = el_malloc(A_K_NKEYS *
+ sizeof(*el->el_terminal.t_fkey));
+ if (el->el_terminal.t_fkey == NULL)
+ goto fail3;
+ el->el_terminal.t_loc = 0;
+ el->el_terminal.t_str = el_malloc(T_str *
+ sizeof(*el->el_terminal.t_str));
+ if (el->el_terminal.t_str == NULL)
+ goto fail4;
+ (void) memset(el->el_terminal.t_str, 0, T_str *
+ sizeof(*el->el_terminal.t_str));
+ el->el_terminal.t_val = el_malloc(T_val *
+ sizeof(*el->el_terminal.t_val));
+ if (el->el_terminal.t_val == NULL)
+ goto fail5;
+ (void) memset(el->el_terminal.t_val, 0, T_val *
+ sizeof(*el->el_terminal.t_val));
+ (void) terminal_set(el, NULL);
+ terminal_init_arrow(el);
+ return 0;
+fail5:
+ free(el->el_terminal.t_str);
+ el->el_terminal.t_str = NULL;
+fail4:
+ free(el->el_terminal.t_fkey);
+ el->el_terminal.t_fkey = NULL;
+fail3:
+ free(el->el_terminal.t_cap);
+ el->el_terminal.t_cap = NULL;
+fail2:
+ free(el->el_terminal.t_buf);
+ el->el_terminal.t_buf = NULL;
+fail1:
+ return -1;
+}
+
+/* terminal_end():
+ * Clean up the terminal stuff
+ */
+libedit_private void
+terminal_end(EditLine *el)
+{
+
+ el_free(el->el_terminal.t_buf);
+ el->el_terminal.t_buf = NULL;
+ el_free(el->el_terminal.t_cap);
+ el->el_terminal.t_cap = NULL;
+ el->el_terminal.t_loc = 0;
+ el_free(el->el_terminal.t_str);
+ el->el_terminal.t_str = NULL;
+ el_free(el->el_terminal.t_val);
+ el->el_terminal.t_val = NULL;
+ el_free(el->el_terminal.t_fkey);
+ el->el_terminal.t_fkey = NULL;
+ terminal_free_display(el);
+}
+
+
+/* terminal_alloc():
+ * Maintain a string pool for termcap strings
+ */
+static void
+terminal_alloc(EditLine *el, const struct termcapstr *t, const char *cap)
+{
+ char termbuf[TC_BUFSIZE];
+ size_t tlen, clen;
+ char **tlist = el->el_terminal.t_str;
+ char **tmp, **str = &tlist[t - tstr];
+
+ (void) memset(termbuf, 0, sizeof(termbuf));
+ if (cap == NULL || *cap == '\0') {
+ *str = NULL;
+ return;
+ } else
+ clen = strlen(cap);
+
+ tlen = *str == NULL ? 0 : strlen(*str);
+
+ /*
+ * New string is shorter; no need to allocate space
+ */
+ if (clen <= tlen) {
+ if (*str)
+ (void) strcpy(*str, cap); /* XXX strcpy is safe */
+ return;
+ }
+ /*
+ * New string is longer; see if we have enough space to append
+ */
+ if (el->el_terminal.t_loc + 3 < TC_BUFSIZE) {
+ /* XXX strcpy is safe */
+ (void) strcpy(*str = &el->el_terminal.t_buf[
+ el->el_terminal.t_loc], cap);
+ el->el_terminal.t_loc += clen + 1; /* one for \0 */
+ return;
+ }
+ /*
+ * Compact our buffer; no need to check compaction, cause we know it
+ * fits...
+ */
+ tlen = 0;
+ for (tmp = tlist; tmp < &tlist[T_str]; tmp++)
+ if (*tmp != NULL && **tmp != '\0' && *tmp != *str) {
+ char *ptr;
+
+ for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++)
+ continue;
+ termbuf[tlen++] = '\0';
+ }
+ memcpy(el->el_terminal.t_buf, termbuf, TC_BUFSIZE);
+ el->el_terminal.t_loc = tlen;
+ if (el->el_terminal.t_loc + 3 >= TC_BUFSIZE) {
+ (void) fprintf(el->el_errfile,
+ "Out of termcap string space.\n");
+ return;
+ }
+ /* XXX strcpy is safe */
+ (void) strcpy(*str = &el->el_terminal.t_buf[el->el_terminal.t_loc],
+ cap);
+ el->el_terminal.t_loc += (size_t)clen + 1; /* one for \0 */
+ return;
+}
+
+
+/* terminal_rebuffer_display():
+ * Rebuffer the display after the screen changed size
+ */
+static int
+terminal_rebuffer_display(EditLine *el)
+{
+ coord_t *c = &el->el_terminal.t_size;
+
+ terminal_free_display(el);
+
+ c->h = Val(T_co);
+ c->v = Val(T_li);
+
+ if (terminal_alloc_display(el) == -1)
+ return -1;
+ return 0;
+}
+
+
+/* terminal_alloc_display():
+ * Allocate a new display.
+ */
+static int
+terminal_alloc_display(EditLine *el)
+{
+ int i;
+ wchar_t **b;
+ coord_t *c = &el->el_terminal.t_size;
+
+ b = el_malloc(sizeof(*b) * (size_t)(c->v + 1));
+ if (b == NULL)
+ goto done;
+ for (i = 0; i < c->v; i++) {
+ b[i] = el_malloc(sizeof(**b) * (size_t)(c->h + 1));
+ if (b[i] == NULL) {
+ while (--i >= 0)
+ el_free(b[i]);
+ el_free(b);
+ goto done;
+ }
+ }
+ b[c->v] = NULL;
+ el->el_display = b;
+
+ b = el_malloc(sizeof(*b) * (size_t)(c->v + 1));
+ if (b == NULL)
+ goto done;
+ for (i = 0; i < c->v; i++) {
+ b[i] = el_malloc(sizeof(**b) * (size_t)(c->h + 1));
+ if (b[i] == NULL) {
+ while (--i >= 0)
+ el_free(b[i]);
+ el_free(b);
+ goto done;
+ }
+ }
+ b[c->v] = NULL;
+ el->el_vdisplay = b;
+ return 0;
+done:
+ terminal_free_display(el);
+ return -1;
+}
+
+
+/* terminal_free_display():
+ * Free the display buffers
+ */
+static void
+terminal_free_display(EditLine *el)
+{
+ wchar_t **b;
+ wchar_t **bufp;
+
+ b = el->el_display;
+ el->el_display = NULL;
+ if (b != NULL) {
+ for (bufp = b; *bufp != NULL; bufp++)
+ el_free(*bufp);
+ el_free(b);
+ }
+ b = el->el_vdisplay;
+ el->el_vdisplay = NULL;
+ if (b != NULL) {
+ for (bufp = b; *bufp != NULL; bufp++)
+ el_free(*bufp);
+ el_free(b);
+ }
+}
+
+
+/* terminal_move_to_line():
+ * move to line <where> (first line == 0)
+ * as efficiently as possible
+ */
+libedit_private void
+terminal_move_to_line(EditLine *el, int where)
+{
+ int del;
+
+ if (where == el->el_cursor.v)
+ return;
+
+ if (where > el->el_terminal.t_size.v) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "%s: where is ridiculous: %d\r\n", __func__, where);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ if ((del = where - el->el_cursor.v) > 0) {
+ while (del > 0) {
+ if (EL_HAS_AUTO_MARGINS &&
+ el->el_display[el->el_cursor.v][0] != '\0') {
+ size_t h = (size_t)
+ (el->el_terminal.t_size.h - 1);
+ for (; h > 0 &&
+ el->el_display[el->el_cursor.v][h] ==
+ MB_FILL_CHAR;
+ h--)
+ continue;
+ /* move without newline */
+ terminal_move_to_char(el, (int)h);
+ terminal_overwrite(el, &el->el_display
+ [el->el_cursor.v][el->el_cursor.h],
+ (size_t)(el->el_terminal.t_size.h -
+ el->el_cursor.h));
+ /* updates Cursor */
+ del--;
+ } else {
+ if ((del > 1) && GoodStr(T_DO)) {
+ terminal_tputs(el, tgoto(Str(T_DO), del,
+ del), del);
+ del = 0;
+ } else {
+ for (; del > 0; del--)
+ terminal__putc(el, '\n');
+ /* because the \n will become \r\n */
+ el->el_cursor.h = 0;
+ }
+ }
+ }
+ } else { /* del < 0 */
+ if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up)))
+ terminal_tputs(el, tgoto(Str(T_UP), -del, -del), -del);
+ else {
+ if (GoodStr(T_up))
+ for (; del < 0; del++)
+ terminal_tputs(el, Str(T_up), 1);
+ }
+ }
+ el->el_cursor.v = where;/* now where is here */
+}
+
+
+/* terminal_move_to_char():
+ * Move to the character position specified
+ */
+libedit_private void
+terminal_move_to_char(EditLine *el, int where)
+{
+ int del, i;
+
+mc_again:
+ if (where == el->el_cursor.h)
+ return;
+
+ if (where > el->el_terminal.t_size.h) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "%s: where is ridiculous: %d\r\n", __func__, where);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ if (!where) { /* if where is first column */
+ terminal__putc(el, '\r'); /* do a CR */
+ el->el_cursor.h = 0;
+ return;
+ }
+ del = where - el->el_cursor.h;
+
+ if ((del < -4 || del > 4) && GoodStr(T_ch))
+ /* go there directly */
+ terminal_tputs(el, tgoto(Str(T_ch), where, where), where);
+ else {
+ if (del > 0) { /* moving forward */
+ if ((del > 4) && GoodStr(T_RI))
+ terminal_tputs(el, tgoto(Str(T_RI), del, del),
+ del);
+ else {
+ /* if I can do tabs, use them */
+ if (EL_CAN_TAB) {
+ if ((el->el_cursor.h & 0370) !=
+ (where & ~0x7)
+ && (el->el_display[
+ el->el_cursor.v][where & 0370] !=
+ MB_FILL_CHAR)
+ ) {
+ /* if not within tab stop */
+ for (i =
+ (el->el_cursor.h & 0370);
+ i < (where & ~0x7);
+ i += 8)
+ terminal__putc(el,
+ '\t');
+ /* then tab over */
+ el->el_cursor.h = where & ~0x7;
+ }
+ }
+ /*
+ * it's usually cheaper to just write the
+ * chars, so we do.
+ */
+ /*
+ * NOTE THAT terminal_overwrite() WILL CHANGE
+ * el->el_cursor.h!!!
+ */
+ terminal_overwrite(el, &el->el_display[
+ el->el_cursor.v][el->el_cursor.h],
+ (size_t)(where - el->el_cursor.h));
+
+ }
+ } else { /* del < 0 := moving backward */
+ if ((-del > 4) && GoodStr(T_LE))
+ terminal_tputs(el, tgoto(Str(T_LE), -del, -del),
+ -del);
+ else { /* can't go directly there */
+ /*
+ * if the "cost" is greater than the "cost"
+ * from col 0
+ */
+ if (EL_CAN_TAB ?
+ ((unsigned int)-del >
+ (((unsigned int) where >> 3) +
+ (where & 07)))
+ : (-del > where)) {
+ terminal__putc(el, '\r');/* do a CR */
+ el->el_cursor.h = 0;
+ goto mc_again; /* and try again */
+ }
+ for (i = 0; i < -del; i++)
+ terminal__putc(el, '\b');
+ }
+ }
+ }
+ el->el_cursor.h = where; /* now where is here */
+}
+
+
+/* terminal_overwrite():
+ * Overstrike num characters
+ * Assumes MB_FILL_CHARs are present to keep the column count correct
+ */
+libedit_private void
+terminal_overwrite(EditLine *el, const wchar_t *cp, size_t n)
+{
+ if (n == 0)
+ return;
+
+ if (n > (size_t)el->el_terminal.t_size.h) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "%s: n is ridiculous: %zu\r\n", __func__, n);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+
+ do {
+ /* terminal__putc() ignores any MB_FILL_CHARs */
+ terminal__putc(el, *cp++);
+ el->el_cursor.h++;
+ } while (--n);
+
+ if (el->el_cursor.h >= el->el_terminal.t_size.h) { /* wrap? */
+ if (EL_HAS_AUTO_MARGINS) { /* yes */
+ el->el_cursor.h = 0;
+ el->el_cursor.v++;
+ if (EL_HAS_MAGIC_MARGINS) {
+ /* force the wrap to avoid the "magic"
+ * situation */
+ wchar_t c;
+ if ((c = el->el_display[el->el_cursor.v]
+ [el->el_cursor.h]) != '\0') {
+ terminal_overwrite(el, &c, (size_t)1);
+ while (el->el_display[el->el_cursor.v]
+ [el->el_cursor.h] == MB_FILL_CHAR)
+ el->el_cursor.h++;
+ } else {
+ terminal__putc(el, ' ');
+ el->el_cursor.h = 1;
+ }
+ }
+ } else /* no wrap, but cursor stays on screen */
+ el->el_cursor.h = el->el_terminal.t_size.h - 1;
+ }
+}
+
+
+/* terminal_deletechars():
+ * Delete num characters
+ */
+libedit_private void
+terminal_deletechars(EditLine *el, int num)
+{
+ if (num <= 0)
+ return;
+
+ if (!EL_CAN_DELETE) {
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile, " ERROR: cannot delete \n");
+#endif /* DEBUG_EDIT */
+ return;
+ }
+ if (num > el->el_terminal.t_size.h) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "%s: num is ridiculous: %d\r\n", __func__, num);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ if (GoodStr(T_DC)) /* if I have multiple delete */
+ if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more
+ * expen. */
+ terminal_tputs(el, tgoto(Str(T_DC), num, num), num);
+ return;
+ }
+ if (GoodStr(T_dm)) /* if I have delete mode */
+ terminal_tputs(el, Str(T_dm), 1);
+
+ if (GoodStr(T_dc)) /* else do one at a time */
+ while (num--)
+ terminal_tputs(el, Str(T_dc), 1);
+
+ if (GoodStr(T_ed)) /* if I have delete mode */
+ terminal_tputs(el, Str(T_ed), 1);
+}
+
+
+/* terminal_insertwrite():
+ * Puts terminal in insert character mode or inserts num
+ * characters in the line
+ * Assumes MB_FILL_CHARs are present to keep column count correct
+ */
+libedit_private void
+terminal_insertwrite(EditLine *el, wchar_t *cp, int num)
+{
+ if (num <= 0)
+ return;
+ if (!EL_CAN_INSERT) {
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile, " ERROR: cannot insert \n");
+#endif /* DEBUG_EDIT */
+ return;
+ }
+ if (num > el->el_terminal.t_size.h) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "%s: num is ridiculous: %d\r\n", __func__, num);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ if (GoodStr(T_IC)) /* if I have multiple insert */
+ if ((num > 1) || !GoodStr(T_ic)) {
+ /* if ic would be more expensive */
+ terminal_tputs(el, tgoto(Str(T_IC), num, num), num);
+ terminal_overwrite(el, cp, (size_t)num);
+ /* this updates el_cursor.h */
+ return;
+ }
+ if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */
+ terminal_tputs(el, Str(T_im), 1);
+
+ el->el_cursor.h += num;
+ do
+ terminal__putc(el, *cp++);
+ while (--num);
+
+ if (GoodStr(T_ip)) /* have to make num chars insert */
+ terminal_tputs(el, Str(T_ip), 1);
+
+ terminal_tputs(el, Str(T_ei), 1);
+ return;
+ }
+ do {
+ if (GoodStr(T_ic)) /* have to make num chars insert */
+ terminal_tputs(el, Str(T_ic), 1);
+
+ terminal__putc(el, *cp++);
+
+ el->el_cursor.h++;
+
+ if (GoodStr(T_ip)) /* have to make num chars insert */
+ terminal_tputs(el, Str(T_ip), 1);
+ /* pad the inserted char */
+
+ } while (--num);
+}
+
+
+/* terminal_clear_EOL():
+ * clear to end of line. There are num characters to clear
+ */
+libedit_private void
+terminal_clear_EOL(EditLine *el, int num)
+{
+ int i;
+
+ if (EL_CAN_CEOL && GoodStr(T_ce))
+ terminal_tputs(el, Str(T_ce), 1);
+ else {
+ for (i = 0; i < num; i++)
+ terminal__putc(el, ' ');
+ el->el_cursor.h += num; /* have written num spaces */
+ }
+}
+
+
+/* terminal_clear_screen():
+ * Clear the screen
+ */
+libedit_private void
+terminal_clear_screen(EditLine *el)
+{ /* clear the whole screen and home */
+
+ if (GoodStr(T_cl))
+ /* send the clear screen code */
+ terminal_tputs(el, Str(T_cl), Val(T_li));
+ else if (GoodStr(T_ho) && GoodStr(T_cd)) {
+ terminal_tputs(el, Str(T_ho), Val(T_li)); /* home */
+ /* clear to bottom of screen */
+ terminal_tputs(el, Str(T_cd), Val(T_li));
+ } else {
+ terminal__putc(el, '\r');
+ terminal__putc(el, '\n');
+ }
+}
+
+
+/* terminal_beep():
+ * Beep the way the terminal wants us
+ */
+libedit_private void
+terminal_beep(EditLine *el)
+{
+ if (GoodStr(T_bl))
+ /* what termcap says we should use */
+ terminal_tputs(el, Str(T_bl), 1);
+ else
+ terminal__putc(el, '\007'); /* an ASCII bell; ^G */
+}
+
+
+libedit_private void
+terminal_get(EditLine *el, const char **term)
+{
+ *term = el->el_terminal.t_name;
+}
+
+
+/* terminal_set():
+ * Read in the terminal capabilities from the requested terminal
+ */
+libedit_private int
+terminal_set(EditLine *el, const char *term)
+{
+ int i;
+ char buf[TC_BUFSIZE];
+ char *area;
+ const struct termcapstr *t;
+ sigset_t oset, nset;
+ int lins, cols;
+
+ (void) sigemptyset(&nset);
+ (void) sigaddset(&nset, SIGWINCH);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ area = buf;
+
+
+ if (term == NULL)
+ term = getenv("TERM");
+
+ if (!term || !term[0])
+ term = "dumb";
+
+ if (strcmp(term, "emacs") == 0)
+ el->el_flags |= EDIT_DISABLED;
+
+ (void) memset(el->el_terminal.t_cap, 0, TC_BUFSIZE);
+
+ i = tgetent(el->el_terminal.t_cap, term);
+
+ if (i <= 0) {
+ if (i == -1)
+ (void) fprintf(el->el_errfile,
+ "Cannot read termcap database;\n");
+ else if (i == 0)
+ (void) fprintf(el->el_errfile,
+ "No entry for terminal type \"%s\";\n", term);
+ (void) fprintf(el->el_errfile,
+ "using dumb terminal settings.\n");
+ Val(T_co) = 80; /* do a dumb terminal */
+ Val(T_pt) = Val(T_km) = Val(T_li) = 0;
+ Val(T_xt) = Val(T_MT);
+ for (t = tstr; t->name != NULL; t++)
+ terminal_alloc(el, t, NULL);
+ } else {
+ /* auto/magic margins */
+ Val(T_am) = tgetflag("am");
+ Val(T_xn) = tgetflag("xn");
+ /* Can we tab */
+ Val(T_pt) = tgetflag("pt");
+ Val(T_xt) = tgetflag("xt");
+ /* do we have a meta? */
+ Val(T_km) = tgetflag("km");
+ Val(T_MT) = tgetflag("MT");
+ /* Get the size */
+ Val(T_co) = tgetnum("co");
+ Val(T_li) = tgetnum("li");
+ for (t = tstr; t->name != NULL; t++) {
+ /* XXX: some systems' tgetstr needs non const */
+ terminal_alloc(el, t, tgetstr(strchr(t->name, *t->name),
+ &area));
+ }
+ }
+
+ if (Val(T_co) < 2)
+ Val(T_co) = 80; /* just in case */
+ if (Val(T_li) < 1)
+ Val(T_li) = 24;
+
+ el->el_terminal.t_size.v = Val(T_co);
+ el->el_terminal.t_size.h = Val(T_li);
+
+ terminal_setflags(el);
+
+ /* get the correct window size */
+ (void) terminal_get_size(el, &lins, &cols);
+ if (terminal_change_size(el, lins, cols) == -1)
+ return -1;
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+ terminal_bind_arrow(el);
+ el->el_terminal.t_name = term;
+ return i <= 0 ? -1 : 0;
+}
+
+
+/* terminal_get_size():
+ * Return the new window size in lines and cols, and
+ * true if the size was changed.
+ */
+libedit_private int
+terminal_get_size(EditLine *el, int *lins, int *cols)
+{
+
+ *cols = Val(T_co);
+ *lins = Val(T_li);
+
+#ifdef TIOCGWINSZ
+ {
+ struct winsize ws;
+ if (ioctl(el->el_infd, TIOCGWINSZ, &ws) != -1) {
+ if (ws.ws_col)
+ *cols = ws.ws_col;
+ if (ws.ws_row)
+ *lins = ws.ws_row;
+ }
+ }
+#endif
+#ifdef TIOCGSIZE
+ {
+ struct ttysize ts;
+ if (ioctl(el->el_infd, TIOCGSIZE, &ts) != -1) {
+ if (ts.ts_cols)
+ *cols = ts.ts_cols;
+ if (ts.ts_lines)
+ *lins = ts.ts_lines;
+ }
+ }
+#endif
+ return Val(T_co) != *cols || Val(T_li) != *lins;
+}
+
+
+/* terminal_change_size():
+ * Change the size of the terminal
+ */
+libedit_private int
+terminal_change_size(EditLine *el, int lins, int cols)
+{
+ /*
+ * Just in case
+ */
+ Val(T_co) = (cols < 2) ? 80 : cols;
+ Val(T_li) = (lins < 1) ? 24 : lins;
+
+ /* re-make display buffers */
+ if (terminal_rebuffer_display(el) == -1)
+ return -1;
+ re_clear_display(el);
+ return 0;
+}
+
+
+/* terminal_init_arrow():
+ * Initialize the arrow key bindings from termcap
+ */
+static void
+terminal_init_arrow(EditLine *el)
+{
+ funckey_t *arrow = el->el_terminal.t_fkey;
+
+ arrow[A_K_DN].name = L"down";
+ arrow[A_K_DN].key = T_kd;
+ arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY;
+ arrow[A_K_DN].type = XK_CMD;
+
+ arrow[A_K_UP].name = L"up";
+ arrow[A_K_UP].key = T_ku;
+ arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY;
+ arrow[A_K_UP].type = XK_CMD;
+
+ arrow[A_K_LT].name = L"left";
+ arrow[A_K_LT].key = T_kl;
+ arrow[A_K_LT].fun.cmd = ED_PREV_CHAR;
+ arrow[A_K_LT].type = XK_CMD;
+
+ arrow[A_K_RT].name = L"right";
+ arrow[A_K_RT].key = T_kr;
+ arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR;
+ arrow[A_K_RT].type = XK_CMD;
+
+ arrow[A_K_HO].name = L"home";
+ arrow[A_K_HO].key = T_kh;
+ arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG;
+ arrow[A_K_HO].type = XK_CMD;
+
+ arrow[A_K_EN].name = L"end";
+ arrow[A_K_EN].key = T_at7;
+ arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END;
+ arrow[A_K_EN].type = XK_CMD;
+
+ arrow[A_K_DE].name = L"delete";
+ arrow[A_K_DE].key = T_kD;
+ arrow[A_K_DE].fun.cmd = ED_DELETE_NEXT_CHAR;
+ arrow[A_K_DE].type = XK_CMD;
+}
+
+
+/* terminal_reset_arrow():
+ * Reset arrow key bindings
+ */
+static void
+terminal_reset_arrow(EditLine *el)
+{
+ funckey_t *arrow = el->el_terminal.t_fkey;
+ static const wchar_t strA[] = L"\033[A";
+ static const wchar_t strB[] = L"\033[B";
+ static const wchar_t strC[] = L"\033[C";
+ static const wchar_t strD[] = L"\033[D";
+ static const wchar_t strH[] = L"\033[H";
+ static const wchar_t strF[] = L"\033[F";
+ static const wchar_t stOA[] = L"\033OA";
+ static const wchar_t stOB[] = L"\033OB";
+ static const wchar_t stOC[] = L"\033OC";
+ static const wchar_t stOD[] = L"\033OD";
+ static const wchar_t stOH[] = L"\033OH";
+ static const wchar_t stOF[] = L"\033OF";
+
+ keymacro_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
+ keymacro_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
+ keymacro_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
+ keymacro_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
+ keymacro_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ keymacro_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+ keymacro_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
+ keymacro_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
+ keymacro_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
+ keymacro_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
+ keymacro_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ keymacro_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+
+ if (el->el_map.type != MAP_VI)
+ return;
+ keymacro_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type);
+ keymacro_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type);
+ keymacro_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type);
+ keymacro_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type);
+ keymacro_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ keymacro_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+ keymacro_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type);
+ keymacro_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type);
+ keymacro_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type);
+ keymacro_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type);
+ keymacro_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ keymacro_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+}
+
+
+/* terminal_set_arrow():
+ * Set an arrow key binding
+ */
+libedit_private int
+terminal_set_arrow(EditLine *el, const wchar_t *name, keymacro_value_t *fun,
+ int type)
+{
+ funckey_t *arrow = el->el_terminal.t_fkey;
+ int i;
+
+ for (i = 0; i < A_K_NKEYS; i++)
+ if (wcscmp(name, arrow[i].name) == 0) {
+ arrow[i].fun = *fun;
+ arrow[i].type = type;
+ return 0;
+ }
+ return -1;
+}
+
+
+/* terminal_clear_arrow():
+ * Clear an arrow key binding
+ */
+libedit_private int
+terminal_clear_arrow(EditLine *el, const wchar_t *name)
+{
+ funckey_t *arrow = el->el_terminal.t_fkey;
+ int i;
+
+ for (i = 0; i < A_K_NKEYS; i++)
+ if (wcscmp(name, arrow[i].name) == 0) {
+ arrow[i].type = XK_NOD;
+ return 0;
+ }
+ return -1;
+}
+
+
+/* terminal_print_arrow():
+ * Print the arrow key bindings
+ */
+libedit_private void
+terminal_print_arrow(EditLine *el, const wchar_t *name)
+{
+ int i;
+ funckey_t *arrow = el->el_terminal.t_fkey;
+
+ for (i = 0; i < A_K_NKEYS; i++)
+ if (*name == '\0' || wcscmp(name, arrow[i].name) == 0)
+ if (arrow[i].type != XK_NOD)
+ keymacro_kprint(el, arrow[i].name,
+ &arrow[i].fun, arrow[i].type);
+}
+
+
+/* terminal_bind_arrow():
+ * Bind the arrow keys
+ */
+libedit_private void
+terminal_bind_arrow(EditLine *el)
+{
+ el_action_t *map;
+ const el_action_t *dmap;
+ int i, j;
+ char *p;
+ funckey_t *arrow = el->el_terminal.t_fkey;
+
+ /* Check if the components needed are initialized */
+ if (el->el_terminal.t_buf == NULL || el->el_map.key == NULL)
+ return;
+
+ map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key;
+ dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs;
+
+ terminal_reset_arrow(el);
+
+ for (i = 0; i < A_K_NKEYS; i++) {
+ wchar_t wt_str[VISUAL_WIDTH_MAX];
+ wchar_t *px;
+ size_t n;
+
+ p = el->el_terminal.t_str[arrow[i].key];
+ if (!p || !*p)
+ continue;
+ for (n = 0; n < VISUAL_WIDTH_MAX && p[n]; ++n)
+ wt_str[n] = p[n];
+ while (n < VISUAL_WIDTH_MAX)
+ wt_str[n++] = '\0';
+ px = wt_str;
+ j = (unsigned char) *p;
+ /*
+ * Assign the arrow keys only if:
+ *
+ * 1. They are multi-character arrow keys and the user
+ * has not re-assigned the leading character, or
+ * has re-assigned the leading character to be
+ * ED_SEQUENCE_LEAD_IN
+ * 2. They are single arrow keys pointing to an
+ * unassigned key.
+ */
+ if (arrow[i].type == XK_NOD)
+ keymacro_clear(el, map, px);
+ else {
+ if (p[1] && (dmap[j] == map[j] ||
+ map[j] == ED_SEQUENCE_LEAD_IN)) {
+ keymacro_add(el, px, &arrow[i].fun,
+ arrow[i].type);
+ map[j] = ED_SEQUENCE_LEAD_IN;
+ } else if (map[j] == ED_UNASSIGNED) {
+ keymacro_clear(el, map, px);
+ if (arrow[i].type == XK_CMD)
+ map[j] = arrow[i].fun.cmd;
+ else
+ keymacro_add(el, px, &arrow[i].fun,
+ arrow[i].type);
+ }
+ }
+ }
+}
+
+/* terminal_putc():
+ * Add a character
+ */
+static int
+terminal_putc(int c)
+{
+ if (terminal_outfile == NULL)
+ return -1;
+ return fputc(c, terminal_outfile);
+}
+
+static void
+terminal_tputs(EditLine *el, const char *cap, int affcnt)
+{
+#ifdef _REENTRANT
+ pthread_mutex_lock(&terminal_mutex);
+#endif
+ terminal_outfile = el->el_outfile;
+ (void)tputs(cap, affcnt, terminal_putc);
+#ifdef _REENTRANT
+ pthread_mutex_unlock(&terminal_mutex);
+#endif
+}
+
+/* terminal__putc():
+ * Add a character
+ */
+libedit_private int
+terminal__putc(EditLine *el, wint_t c)
+{
+ char buf[MB_LEN_MAX +1];
+ ssize_t i;
+ if (c == (wint_t)MB_FILL_CHAR)
+ return 0;
+ i = ct_encode_char(buf, (size_t)MB_LEN_MAX, c);
+ if (i <= 0)
+ return (int)i;
+ buf[i] = '\0';
+ return fputs(buf, el->el_outfile);
+}
+
+/* terminal__flush():
+ * Flush output
+ */
+libedit_private void
+terminal__flush(EditLine *el)
+{
+
+ (void) fflush(el->el_outfile);
+}
+
+/* terminal_writec():
+ * Write the given character out, in a human readable form
+ */
+libedit_private void
+terminal_writec(EditLine *el, wint_t c)
+{
+ wchar_t visbuf[VISUAL_WIDTH_MAX +1];
+ ssize_t vcnt = ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
+ if (vcnt < 0)
+ vcnt = 0;
+ visbuf[vcnt] = '\0';
+ terminal_overwrite(el, visbuf, (size_t)vcnt);
+ terminal__flush(el);
+}
+
+
+/* terminal_telltc():
+ * Print the current termcap characteristics
+ */
+libedit_private int
+/*ARGSUSED*/
+terminal_telltc(EditLine *el, int argc __attribute__((__unused__)),
+ const wchar_t **argv __attribute__((__unused__)))
+{
+ const struct termcapstr *t;
+ char **ts;
+
+ (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n");
+ (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n");
+ (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n",
+ Val(T_co), Val(T_li));
+ (void) fprintf(el->el_outfile,
+ "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no");
+ (void) fprintf(el->el_outfile,
+ "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not ");
+ (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n",
+ EL_HAS_AUTO_MARGINS ? "has" : "does not have");
+ if (EL_HAS_AUTO_MARGINS)
+ (void) fprintf(el->el_outfile, "\tIt %s magic margins\n",
+ EL_HAS_MAGIC_MARGINS ? "has" : "does not have");
+
+ for (t = tstr, ts = el->el_terminal.t_str; t->name != NULL; t++, ts++) {
+ const char *ub;
+ if (*ts && **ts) {
+ ub = ct_encode_string(ct_visual_string(
+ ct_decode_string(*ts, &el->el_scratch),
+ &el->el_visual), &el->el_scratch);
+ } else {
+ ub = "(empty)";
+ }
+ (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n",
+ t->long_name, t->name, ub);
+ }
+ (void) fputc('\n', el->el_outfile);
+ return 0;
+}
+
+
+/* terminal_settc():
+ * Change the current terminal characteristics
+ */
+libedit_private int
+/*ARGSUSED*/
+terminal_settc(EditLine *el, int argc __attribute__((__unused__)),
+ const wchar_t **argv)
+{
+ const struct termcapstr *ts;
+ const struct termcapval *tv;
+ char what[8], how[8];
+
+ if (argv == NULL || argv[1] == NULL || argv[2] == NULL)
+ return -1;
+
+ strncpy(what, ct_encode_string(argv[1], &el->el_scratch), sizeof(what));
+ what[sizeof(what) - 1] = '\0';
+ strncpy(how, ct_encode_string(argv[2], &el->el_scratch), sizeof(how));
+ how[sizeof(how) - 1] = '\0';
+
+ /*
+ * Do the strings first
+ */
+ for (ts = tstr; ts->name != NULL; ts++)
+ if (strcmp(ts->name, what) == 0)
+ break;
+
+ if (ts->name != NULL) {
+ terminal_alloc(el, ts, how);
+ terminal_setflags(el);
+ return 0;
+ }
+ /*
+ * Do the numeric ones second
+ */
+ for (tv = tval; tv->name != NULL; tv++)
+ if (strcmp(tv->name, what) == 0)
+ break;
+
+ if (tv->name != NULL)
+ return -1;
+
+ if (tv == &tval[T_pt] || tv == &tval[T_km] ||
+ tv == &tval[T_am] || tv == &tval[T_xn]) {
+ if (strcmp(how, "yes") == 0)
+ el->el_terminal.t_val[tv - tval] = 1;
+ else if (strcmp(how, "no") == 0)
+ el->el_terminal.t_val[tv - tval] = 0;
+ else {
+ (void) fprintf(el->el_errfile,
+ "%ls: Bad value `%s'.\n", argv[0], how);
+ return -1;
+ }
+ terminal_setflags(el);
+ if (terminal_change_size(el, Val(T_li), Val(T_co)) == -1)
+ return -1;
+ return 0;
+ } else {
+ long i;
+ char *ep;
+
+ i = strtol(how, &ep, 10);
+ if (*ep != '\0') {
+ (void) fprintf(el->el_errfile,
+ "%ls: Bad value `%s'.\n", argv[0], how);
+ return -1;
+ }
+ el->el_terminal.t_val[tv - tval] = (int) i;
+ el->el_terminal.t_size.v = Val(T_co);
+ el->el_terminal.t_size.h = Val(T_li);
+ if (tv == &tval[T_co] || tv == &tval[T_li])
+ if (terminal_change_size(el, Val(T_li), Val(T_co))
+ == -1)
+ return -1;
+ return 0;
+ }
+}
+
+
+/* terminal_gettc():
+ * Get the current terminal characteristics
+ */
+libedit_private int
+/*ARGSUSED*/
+terminal_gettc(EditLine *el, int argc __attribute__((__unused__)), char **argv)
+{
+ const struct termcapstr *ts;
+ const struct termcapval *tv;
+ char *what;
+ void *how;
+
+ if (argv == NULL || argv[1] == NULL || argv[2] == NULL)
+ return -1;
+
+ what = argv[1];
+ how = argv[2];
+
+ /*
+ * Do the strings first
+ */
+ for (ts = tstr; ts->name != NULL; ts++)
+ if (strcmp(ts->name, what) == 0)
+ break;
+
+ if (ts->name != NULL) {
+ *(char **)how = el->el_terminal.t_str[ts - tstr];
+ return 0;
+ }
+ /*
+ * Do the numeric ones second
+ */
+ for (tv = tval; tv->name != NULL; tv++)
+ if (strcmp(tv->name, what) == 0)
+ break;
+
+ if (tv->name == NULL)
+ return -1;
+
+ if (tv == &tval[T_pt] || tv == &tval[T_km] ||
+ tv == &tval[T_am] || tv == &tval[T_xn]) {
+ static char yes[] = "yes";
+ static char no[] = "no";
+ if (el->el_terminal.t_val[tv - tval])
+ *(char **)how = yes;
+ else
+ *(char **)how = no;
+ return 0;
+ } else {
+ *(int *)how = el->el_terminal.t_val[tv - tval];
+ return 0;
+ }
+}
+
+/* terminal_echotc():
+ * Print the termcap string out with variable substitution
+ */
+libedit_private int
+/*ARGSUSED*/
+terminal_echotc(EditLine *el, int argc __attribute__((__unused__)),
+ const wchar_t **argv)
+{
+ char *cap, *scap;
+ wchar_t *ep;
+ int arg_need, arg_cols, arg_rows;
+ int verbose = 0, silent = 0;
+ char *area;
+ static const char fmts[] = "%s\n", fmtd[] = "%d\n";
+ const struct termcapstr *t;
+ char buf[TC_BUFSIZE];
+ long i;
+
+ area = buf;
+
+ if (argv == NULL || argv[1] == NULL)
+ return -1;
+ argv++;
+
+ if (argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 's':
+ silent = 1;
+ break;
+ default:
+ /* stderror(ERR_NAME | ERR_TCUSAGE); */
+ break;
+ }
+ argv++;
+ }
+ if (!*argv || *argv[0] == '\0')
+ return 0;
+ if (wcscmp(*argv, L"tabs") == 0) {
+ (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no");
+ return 0;
+ } else if (wcscmp(*argv, L"meta") == 0) {
+ (void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no");
+ return 0;
+ } else if (wcscmp(*argv, L"xn") == 0) {
+ (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ?
+ "yes" : "no");
+ return 0;
+ } else if (wcscmp(*argv, L"am") == 0) {
+ (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ?
+ "yes" : "no");
+ return 0;
+ } else if (wcscmp(*argv, L"baud") == 0) {
+ (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed);
+ return 0;
+ } else if (wcscmp(*argv, L"rows") == 0 ||
+ wcscmp(*argv, L"lines") == 0) {
+ (void) fprintf(el->el_outfile, fmtd, Val(T_li));
+ return 0;
+ } else if (wcscmp(*argv, L"cols") == 0) {
+ (void) fprintf(el->el_outfile, fmtd, Val(T_co));
+ return 0;
+ }
+ /*
+ * Try to use our local definition first
+ */
+ scap = NULL;
+ for (t = tstr; t->name != NULL; t++)
+ if (strcmp(t->name,
+ ct_encode_string(*argv, &el->el_scratch)) == 0) {
+ scap = el->el_terminal.t_str[t - tstr];
+ break;
+ }
+ if (t->name == NULL) {
+ /* XXX: some systems' tgetstr needs non const */
+ scap = tgetstr(ct_encode_string(*argv, &el->el_scratch), &area);
+ }
+ if (!scap || scap[0] == '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Termcap parameter `%ls' not found.\n",
+ *argv);
+ return -1;
+ }
+ /*
+ * Count home many values we need for this capability.
+ */
+ for (cap = scap, arg_need = 0; *cap; cap++)
+ if (*cap == '%')
+ switch (*++cap) {
+ case 'd':
+ case '2':
+ case '3':
+ case '.':
+ case '+':
+ arg_need++;
+ break;
+ case '%':
+ case '>':
+ case 'i':
+ case 'r':
+ case 'n':
+ case 'B':
+ case 'D':
+ break;
+ default:
+ /*
+ * hpux has lot's of them...
+ */
+ if (verbose)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: unknown termcap %% `%c'.\n",
+ *cap);
+ /* This is bad, but I won't complain */
+ break;
+ }
+
+ switch (arg_need) {
+ case 0:
+ argv++;
+ if (*argv && *argv[0]) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Extra argument `%ls'.\n",
+ *argv);
+ return -1;
+ }
+ terminal_tputs(el, scap, 1);
+ break;
+ case 1:
+ argv++;
+ if (!*argv || *argv[0] == '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Missing argument.\n");
+ return -1;
+ }
+ arg_cols = 0;
+ i = wcstol(*argv, &ep, 10);
+ if (*ep != '\0' || i < 0) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Bad value `%ls' for rows.\n",
+ *argv);
+ return -1;
+ }
+ arg_rows = (int) i;
+ argv++;
+ if (*argv && *argv[0]) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Extra argument `%ls"
+ "'.\n", *argv);
+ return -1;
+ }
+ terminal_tputs(el, tgoto(scap, arg_cols, arg_rows), 1);
+ break;
+ default:
+ /* This is wrong, but I will ignore it... */
+ if (verbose)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Too many required arguments (%d).\n",
+ arg_need);
+ /* FALLTHROUGH */
+ case 2:
+ argv++;
+ if (!*argv || *argv[0] == '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Missing argument.\n");
+ return -1;
+ }
+ i = wcstol(*argv, &ep, 10);
+ if (*ep != '\0' || i < 0) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Bad value `%ls' for cols.\n",
+ *argv);
+ return -1;
+ }
+ arg_cols = (int) i;
+ argv++;
+ if (!*argv || *argv[0] == '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Missing argument.\n");
+ return -1;
+ }
+ i = wcstol(*argv, &ep, 10);
+ if (*ep != '\0' || i < 0) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Bad value `%ls' for rows.\n",
+ *argv);
+ return -1;
+ }
+ arg_rows = (int) i;
+ if (*ep != '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Bad value `%ls'.\n", *argv);
+ return -1;
+ }
+ argv++;
+ if (*argv && *argv[0]) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Extra argument `%ls"
+ "'.\n", *argv);
+ return -1;
+ }
+ terminal_tputs(el, tgoto(scap, arg_cols, arg_rows), arg_rows);
+ break;
+ }
+ return 0;
+}
diff --git a/third_party/heimdal/lib/libedit/src/terminal.h b/third_party/heimdal/lib/libedit/src/terminal.h
new file mode 100644
index 0000000..ae61beb
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/terminal.h
@@ -0,0 +1,125 @@
+/* $NetBSD: terminal.h,v 1.9 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)term.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.term.h: Termcap header
+ */
+#ifndef _h_el_terminal
+#define _h_el_terminal
+
+typedef struct { /* Symbolic function key bindings */
+ const wchar_t *name; /* name of the key */
+ int key; /* Index in termcap table */
+ keymacro_value_t fun; /* Function bound to it */
+ int type; /* Type of function */
+} funckey_t;
+
+typedef struct {
+ const char *t_name; /* the terminal name */
+ coord_t t_size; /* # lines and cols */
+ int t_flags;
+#define TERM_CAN_INSERT 0x001 /* Has insert cap */
+#define TERM_CAN_DELETE 0x002 /* Has delete cap */
+#define TERM_CAN_CEOL 0x004 /* Has CEOL cap */
+#define TERM_CAN_TAB 0x008 /* Can use tabs */
+#define TERM_CAN_ME 0x010 /* Can turn all attrs. */
+#define TERM_CAN_UP 0x020 /* Can move up */
+#define TERM_HAS_META 0x040 /* Has a meta key */
+#define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */
+#define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */
+ char *t_buf; /* Termcap buffer */
+ size_t t_loc; /* location used */
+ char **t_str; /* termcap strings */
+ int *t_val; /* termcap values */
+ char *t_cap; /* Termcap buffer */
+ funckey_t *t_fkey; /* Array of keys */
+} el_terminal_t;
+
+/*
+ * fKey indexes
+ */
+#define A_K_DN 0
+#define A_K_UP 1
+#define A_K_LT 2
+#define A_K_RT 3
+#define A_K_HO 4
+#define A_K_EN 5
+#define A_K_DE 6
+#define A_K_NKEYS 7
+
+libedit_private void terminal_move_to_line(EditLine *, int);
+libedit_private void terminal_move_to_char(EditLine *, int);
+libedit_private void terminal_clear_EOL(EditLine *, int);
+libedit_private void terminal_overwrite(EditLine *, const wchar_t *, size_t);
+libedit_private void terminal_insertwrite(EditLine *, wchar_t *, int);
+libedit_private void terminal_deletechars(EditLine *, int);
+libedit_private void terminal_clear_screen(EditLine *);
+libedit_private void terminal_beep(EditLine *);
+libedit_private int terminal_change_size(EditLine *, int, int);
+libedit_private int terminal_get_size(EditLine *, int *, int *);
+libedit_private int terminal_init(EditLine *);
+libedit_private void terminal_bind_arrow(EditLine *);
+libedit_private void terminal_print_arrow(EditLine *, const wchar_t *);
+libedit_private int terminal_clear_arrow(EditLine *, const wchar_t *);
+libedit_private int terminal_set_arrow(EditLine *, const wchar_t *,
+ keymacro_value_t *, int);
+libedit_private void terminal_end(EditLine *);
+libedit_private void terminal_get(EditLine *, const char **);
+libedit_private int terminal_set(EditLine *, const char *);
+libedit_private int terminal_settc(EditLine *, int, const wchar_t **);
+libedit_private int terminal_gettc(EditLine *, int, char **);
+libedit_private int terminal_telltc(EditLine *, int, const wchar_t **);
+libedit_private int terminal_echotc(EditLine *, int, const wchar_t **);
+libedit_private void terminal_writec(EditLine *, wint_t);
+libedit_private int terminal__putc(EditLine *, wint_t);
+libedit_private void terminal__flush(EditLine *);
+
+/*
+ * Easy access macros
+ */
+#define EL_FLAGS (el)->el_terminal.t_flags
+
+#define EL_CAN_INSERT (EL_FLAGS & TERM_CAN_INSERT)
+#define EL_CAN_DELETE (EL_FLAGS & TERM_CAN_DELETE)
+#define EL_CAN_CEOL (EL_FLAGS & TERM_CAN_CEOL)
+#define EL_CAN_TAB (EL_FLAGS & TERM_CAN_TAB)
+#define EL_CAN_ME (EL_FLAGS & TERM_CAN_ME)
+#define EL_CAN_UP (EL_FLAGS & TERM_CAN_UP)
+#define EL_HAS_META (EL_FLAGS & TERM_HAS_META)
+#define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS)
+#define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS)
+
+#endif /* _h_el_terminal */
diff --git a/third_party/heimdal/lib/libedit/src/tokenizer.c b/third_party/heimdal/lib/libedit/src/tokenizer.c
new file mode 100644
index 0000000..1853224
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/tokenizer.c
@@ -0,0 +1,466 @@
+/* $NetBSD: tokenizer.c,v 1.28 2016/04/11 18:56:31 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: tokenizer.c,v 1.28 2016/04/11 18:56:31 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/* We build this file twice, once as NARROW, once as WIDE. */
+/*
+ * tokenize.c: Bourne shell like tokenizer
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "histedit.h"
+
+typedef enum {
+ Q_none, Q_single, Q_double, Q_one, Q_doubleone
+} quote_t;
+
+#define TOK_KEEP 1
+#define TOK_EAT 2
+
+#define WINCR 20
+#define AINCR 10
+
+#define IFS STR("\t \n")
+
+#define tok_malloc(a) malloc(a)
+#define tok_free(a) free(a)
+#define tok_realloc(a, b) realloc(a, b)
+
+#ifdef NARROWCHAR
+#define Char char
+#define FUN(prefix, rest) prefix ## _ ## rest
+#define TYPE(type) type
+#define STR(x) x
+#define Strchr(s, c) strchr(s, c)
+#define tok_strdup(s) strdup(s)
+#else
+#define Char wchar_t
+#define FUN(prefix, rest) prefix ## _w ## rest
+#define TYPE(type) type ## W
+#define STR(x) L ## x
+#define Strchr(s, c) wcschr(s, c)
+#define tok_strdup(s) wcsdup(s)
+#endif
+
+struct TYPE(tokenizer) {
+ Char *ifs; /* In field separator */
+ size_t argc, amax; /* Current and maximum number of args */
+ Char **argv; /* Argument list */
+ Char *wptr, *wmax; /* Space and limit on the word buffer */
+ Char *wstart; /* Beginning of next word */
+ Char *wspace; /* Space of word buffer */
+ quote_t quote; /* Quoting state */
+ int flags; /* flags; */
+};
+
+
+static void FUN(tok,finish)(TYPE(Tokenizer) *);
+
+
+/* FUN(tok,finish)():
+ * Finish a word in the tokenizer.
+ */
+static void
+FUN(tok,finish)(TYPE(Tokenizer) *tok)
+{
+
+ *tok->wptr = '\0';
+ if ((tok->flags & TOK_KEEP) || tok->wptr != tok->wstart) {
+ tok->argv[tok->argc++] = tok->wstart;
+ tok->argv[tok->argc] = NULL;
+ tok->wstart = ++tok->wptr;
+ }
+ tok->flags &= ~TOK_KEEP;
+}
+
+
+/* FUN(tok,init)():
+ * Initialize the tokenizer
+ */
+TYPE(Tokenizer) *
+FUN(tok,init)(const Char *ifs)
+{
+ TYPE(Tokenizer) *tok = tok_malloc(sizeof(*tok));
+
+ if (tok == NULL)
+ return NULL;
+ tok->ifs = tok_strdup(ifs ? ifs : IFS);
+ if (tok->ifs == NULL) {
+ tok_free(tok);
+ return NULL;
+ }
+ tok->argc = 0;
+ tok->amax = AINCR;
+ tok->argv = tok_malloc(sizeof(*tok->argv) * tok->amax);
+ if (tok->argv == NULL) {
+ tok_free(tok->ifs);
+ tok_free(tok);
+ return NULL;
+ }
+ tok->argv[0] = NULL;
+ tok->wspace = tok_malloc(WINCR * sizeof(*tok->wspace));
+ if (tok->wspace == NULL) {
+ tok_free(tok->argv);
+ tok_free(tok->ifs);
+ tok_free(tok);
+ return NULL;
+ }
+ tok->wmax = tok->wspace + WINCR;
+ tok->wstart = tok->wspace;
+ tok->wptr = tok->wspace;
+ tok->flags = 0;
+ tok->quote = Q_none;
+
+ return tok;
+}
+
+
+/* FUN(tok,reset)():
+ * Reset the tokenizer
+ */
+void
+FUN(tok,reset)(TYPE(Tokenizer) *tok)
+{
+
+ tok->argc = 0;
+ tok->wstart = tok->wspace;
+ tok->wptr = tok->wspace;
+ tok->flags = 0;
+ tok->quote = Q_none;
+}
+
+
+/* FUN(tok,end)():
+ * Clean up
+ */
+void
+FUN(tok,end)(TYPE(Tokenizer) *tok)
+{
+
+ tok_free(tok->ifs);
+ tok_free(tok->wspace);
+ tok_free(tok->argv);
+ tok_free(tok);
+}
+
+
+
+/* FUN(tok,line)():
+ * Bourne shell (sh(1)) like tokenizing
+ * Arguments:
+ * tok current tokenizer state (setup with FUN(tok,init)())
+ * line line to parse
+ * Returns:
+ * -1 Internal error
+ * 3 Quoted return
+ * 2 Unmatched double quote
+ * 1 Unmatched single quote
+ * 0 Ok
+ * Modifies (if return value is 0):
+ * argc number of arguments
+ * argv argument array
+ * cursorc if !NULL, argv element containing cursor
+ * cursorv if !NULL, offset in argv[cursorc] of cursor
+ */
+int
+FUN(tok,line)(TYPE(Tokenizer) *tok, const TYPE(LineInfo) *line,
+ int *argc, const Char ***argv, int *cursorc, int *cursoro)
+{
+ const Char *ptr;
+ int cc, co;
+
+ cc = co = -1;
+ ptr = line->buffer;
+ for (ptr = line->buffer; ;ptr++) {
+ if (ptr >= line->lastchar)
+ ptr = STR("");
+ if (ptr == line->cursor) {
+ cc = (int)tok->argc;
+ co = (int)(tok->wptr - tok->wstart);
+ }
+ switch (*ptr) {
+ case '\'':
+ tok->flags |= TOK_KEEP;
+ tok->flags &= ~TOK_EAT;
+ switch (tok->quote) {
+ case Q_none:
+ tok->quote = Q_single; /* Enter single quote
+ * mode */
+ break;
+
+ case Q_single: /* Exit single quote mode */
+ tok->quote = Q_none;
+ break;
+
+ case Q_one: /* Quote this ' */
+ tok->quote = Q_none;
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_double: /* Stay in double quote mode */
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_doubleone: /* Quote this ' */
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ case '"':
+ tok->flags &= ~TOK_EAT;
+ tok->flags |= TOK_KEEP;
+ switch (tok->quote) {
+ case Q_none: /* Enter double quote mode */
+ tok->quote = Q_double;
+ break;
+
+ case Q_double: /* Exit double quote mode */
+ tok->quote = Q_none;
+ break;
+
+ case Q_one: /* Quote this " */
+ tok->quote = Q_none;
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_single: /* Stay in single quote mode */
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_doubleone: /* Quote this " */
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ case '\\':
+ tok->flags |= TOK_KEEP;
+ tok->flags &= ~TOK_EAT;
+ switch (tok->quote) {
+ case Q_none: /* Quote next character */
+ tok->quote = Q_one;
+ break;
+
+ case Q_double: /* Quote next character */
+ tok->quote = Q_doubleone;
+ break;
+
+ case Q_one: /* Quote this, restore state */
+ *tok->wptr++ = *ptr;
+ tok->quote = Q_none;
+ break;
+
+ case Q_single: /* Stay in single quote mode */
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_doubleone: /* Quote this \ */
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ case '\n':
+ tok->flags &= ~TOK_EAT;
+ switch (tok->quote) {
+ case Q_none:
+ goto tok_line_outok;
+
+ case Q_single:
+ case Q_double:
+ *tok->wptr++ = *ptr; /* Add the return */
+ break;
+
+ case Q_doubleone: /* Back to double, eat the '\n' */
+ tok->flags |= TOK_EAT;
+ tok->quote = Q_double;
+ break;
+
+ case Q_one: /* No quote, more eat the '\n' */
+ tok->flags |= TOK_EAT;
+ tok->quote = Q_none;
+ break;
+
+ default:
+ return 0;
+ }
+ break;
+
+ case '\0':
+ switch (tok->quote) {
+ case Q_none:
+ /* Finish word and return */
+ if (tok->flags & TOK_EAT) {
+ tok->flags &= ~TOK_EAT;
+ return 3;
+ }
+ goto tok_line_outok;
+
+ case Q_single:
+ return 1;
+
+ case Q_double:
+ return 2;
+
+ case Q_doubleone:
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_one:
+ tok->quote = Q_none;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ default:
+ tok->flags &= ~TOK_EAT;
+ switch (tok->quote) {
+ case Q_none:
+ if (Strchr(tok->ifs, *ptr) != NULL)
+ FUN(tok,finish)(tok);
+ else
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_single:
+ case Q_double:
+ *tok->wptr++ = *ptr;
+ break;
+
+
+ case Q_doubleone:
+ *tok->wptr++ = '\\';
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_one:
+ tok->quote = Q_none;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return -1;
+
+ }
+ break;
+ }
+
+ if (tok->wptr >= tok->wmax - 4) {
+ size_t size = (size_t)(tok->wmax - tok->wspace + WINCR);
+ Char *s = tok_realloc(tok->wspace,
+ size * sizeof(*s));
+ if (s == NULL)
+ return -1;
+
+ if (s != tok->wspace) {
+ size_t i;
+ for (i = 0; i < tok->argc; i++) {
+ tok->argv[i] =
+ (tok->argv[i] - tok->wspace) + s;
+ }
+ tok->wptr = (tok->wptr - tok->wspace) + s;
+ tok->wstart = (tok->wstart - tok->wspace) + s;
+ tok->wspace = s;
+ }
+ tok->wmax = s + size;
+ }
+ if (tok->argc >= tok->amax - 4) {
+ Char **p;
+ tok->amax += AINCR;
+ p = tok_realloc(tok->argv, tok->amax * sizeof(*p));
+ if (p == NULL) {
+ tok->amax -= AINCR;
+ return -1;
+ }
+ tok->argv = p;
+ }
+ }
+ tok_line_outok:
+ if (cc == -1 && co == -1) {
+ cc = (int)tok->argc;
+ co = (int)(tok->wptr - tok->wstart);
+ }
+ if (cursorc != NULL)
+ *cursorc = cc;
+ if (cursoro != NULL)
+ *cursoro = co;
+ FUN(tok,finish)(tok);
+ *argv = (const Char **)tok->argv;
+ *argc = (int)tok->argc;
+ return 0;
+}
+
+/* FUN(tok,str)():
+ * Simpler version of tok_line, taking a NUL terminated line
+ * and splitting into words, ignoring cursor state.
+ */
+int
+FUN(tok,str)(TYPE(Tokenizer) *tok, const Char *line, int *argc,
+ const Char ***argv)
+{
+ TYPE(LineInfo) li;
+
+ memset(&li, 0, sizeof(li));
+ li.buffer = line;
+ li.cursor = li.lastchar = Strchr(line, '\0');
+ return FUN(tok,line)(tok, &li, argc, argv, NULL, NULL);
+}
diff --git a/third_party/heimdal/lib/libedit/src/tokenizern.c b/third_party/heimdal/lib/libedit/src/tokenizern.c
new file mode 100644
index 0000000..5846b60
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/tokenizern.c
@@ -0,0 +1,3 @@
+#include "config.h"
+#define NARROWCHAR
+#include "tokenizer.c"
diff --git a/third_party/heimdal/lib/libedit/src/tty.c b/third_party/heimdal/lib/libedit/src/tty.c
new file mode 100644
index 0000000..f524da4
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/tty.c
@@ -0,0 +1,1342 @@
+/* $NetBSD: tty.c,v 1.65 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: tty.c,v 1.65 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * tty.c: tty interface stuff
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h> /* for abort */
+#include <string.h>
+#include <strings.h> /* for ffs */
+#include <unistd.h> /* for isatty */
+
+#include "el.h"
+#include "fcns.h"
+#include "parse.h"
+
+typedef struct ttymodes_t {
+ const char *m_name;
+ unsigned int m_value;
+ int m_type;
+} ttymodes_t;
+
+typedef struct ttymap_t {
+ wint_t nch, och; /* Internal and termio rep of chars */
+ el_action_t bind[3]; /* emacs, vi, and vi-cmd */
+} ttymap_t;
+
+
+static const ttyperm_t ttyperm = {
+ {
+ {"iflag:", ICRNL, (INLCR | IGNCR)},
+ {"oflag:", (OPOST | ONLCR), ONLRET},
+ {"cflag:", 0, 0},
+ {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
+ (NOFLSH | ECHONL | EXTPROC | FLUSHO)},
+ {"chars:", 0, 0},
+ },
+ {
+ {"iflag:", (INLCR | ICRNL), IGNCR},
+ {"oflag:", (OPOST | ONLCR), ONLRET},
+ {"cflag:", 0, 0},
+ {"lflag:", ISIG,
+ (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
+ {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
+ C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
+ C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
+ },
+ {
+ {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
+ {"oflag:", 0, 0},
+ {"cflag:", 0, 0},
+ {"lflag:", 0, ISIG | IEXTEN},
+ {"chars:", 0, 0},
+ }
+};
+
+static const ttychar_t ttychar = {
+ {
+ CINTR, CQUIT, CERASE, CKILL,
+ CEOF, CEOL, CEOL2, CSWTCH,
+ CDSWTCH, CERASE2, CSTART, CSTOP,
+ CWERASE, CSUSP, CDSUSP, CREPRINT,
+ CDISCARD, CLNEXT, CSTATUS, CPAGE,
+ CPGOFF, CKILL2, CBRK, CMIN,
+ CTIME
+ },
+ {
+ CINTR, CQUIT, CERASE, CKILL,
+ _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
+ _POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
+ _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
+ CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
+ _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
+ 0
+ },
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0
+ }
+};
+
+static const ttymap_t tty_map[] = {
+#ifdef VERASE
+ {C_ERASE, VERASE,
+ {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
+#endif /* VERASE */
+#ifdef VERASE2
+ {C_ERASE2, VERASE2,
+ {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
+#endif /* VERASE2 */
+#ifdef VKILL
+ {C_KILL, VKILL,
+ {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
+#endif /* VKILL */
+#ifdef VKILL2
+ {C_KILL2, VKILL2,
+ {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
+#endif /* VKILL2 */
+#ifdef VEOF
+ {C_EOF, VEOF,
+ {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
+#endif /* VEOF */
+#ifdef VWERASE
+ {C_WERASE, VWERASE,
+ {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
+#endif /* VWERASE */
+#ifdef VREPRINT
+ {C_REPRINT, VREPRINT,
+ {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
+#endif /* VREPRINT */
+#ifdef VLNEXT
+ {C_LNEXT, VLNEXT,
+ {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
+#endif /* VLNEXT */
+ {(wint_t)-1, (wint_t)-1,
+ {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
+};
+
+static const ttymodes_t ttymodes[] = {
+#ifdef IGNBRK
+ {"ignbrk", IGNBRK, MD_INP},
+#endif /* IGNBRK */
+#ifdef BRKINT
+ {"brkint", BRKINT, MD_INP},
+#endif /* BRKINT */
+#ifdef IGNPAR
+ {"ignpar", IGNPAR, MD_INP},
+#endif /* IGNPAR */
+#ifdef PARMRK
+ {"parmrk", PARMRK, MD_INP},
+#endif /* PARMRK */
+#ifdef INPCK
+ {"inpck", INPCK, MD_INP},
+#endif /* INPCK */
+#ifdef ISTRIP
+ {"istrip", ISTRIP, MD_INP},
+#endif /* ISTRIP */
+#ifdef INLCR
+ {"inlcr", INLCR, MD_INP},
+#endif /* INLCR */
+#ifdef IGNCR
+ {"igncr", IGNCR, MD_INP},
+#endif /* IGNCR */
+#ifdef ICRNL
+ {"icrnl", ICRNL, MD_INP},
+#endif /* ICRNL */
+#ifdef IUCLC
+ {"iuclc", IUCLC, MD_INP},
+#endif /* IUCLC */
+#ifdef IXON
+ {"ixon", IXON, MD_INP},
+#endif /* IXON */
+#ifdef IXANY
+ {"ixany", IXANY, MD_INP},
+#endif /* IXANY */
+#ifdef IXOFF
+ {"ixoff", IXOFF, MD_INP},
+#endif /* IXOFF */
+#ifdef IMAXBEL
+ {"imaxbel", IMAXBEL, MD_INP},
+#endif /* IMAXBEL */
+
+#ifdef OPOST
+ {"opost", OPOST, MD_OUT},
+#endif /* OPOST */
+#ifdef OLCUC
+ {"olcuc", OLCUC, MD_OUT},
+#endif /* OLCUC */
+#ifdef ONLCR
+ {"onlcr", ONLCR, MD_OUT},
+#endif /* ONLCR */
+#ifdef OCRNL
+ {"ocrnl", OCRNL, MD_OUT},
+#endif /* OCRNL */
+#ifdef ONOCR
+ {"onocr", ONOCR, MD_OUT},
+#endif /* ONOCR */
+#ifdef ONOEOT
+ {"onoeot", ONOEOT, MD_OUT},
+#endif /* ONOEOT */
+#ifdef ONLRET
+ {"onlret", ONLRET, MD_OUT},
+#endif /* ONLRET */
+#ifdef OFILL
+ {"ofill", OFILL, MD_OUT},
+#endif /* OFILL */
+#ifdef OFDEL
+ {"ofdel", OFDEL, MD_OUT},
+#endif /* OFDEL */
+#ifdef NLDLY
+ {"nldly", NLDLY, MD_OUT},
+#endif /* NLDLY */
+#ifdef CRDLY
+ {"crdly", CRDLY, MD_OUT},
+#endif /* CRDLY */
+#ifdef TABDLY
+ {"tabdly", TABDLY, MD_OUT},
+#endif /* TABDLY */
+#ifdef XTABS
+ {"xtabs", XTABS, MD_OUT},
+#endif /* XTABS */
+#ifdef BSDLY
+ {"bsdly", BSDLY, MD_OUT},
+#endif /* BSDLY */
+#ifdef VTDLY
+ {"vtdly", VTDLY, MD_OUT},
+#endif /* VTDLY */
+#ifdef FFDLY
+ {"ffdly", FFDLY, MD_OUT},
+#endif /* FFDLY */
+#ifdef PAGEOUT
+ {"pageout", PAGEOUT, MD_OUT},
+#endif /* PAGEOUT */
+#ifdef WRAP
+ {"wrap", WRAP, MD_OUT},
+#endif /* WRAP */
+
+#ifdef CIGNORE
+ {"cignore", CIGNORE, MD_CTL},
+#endif /* CBAUD */
+#ifdef CBAUD
+ {"cbaud", CBAUD, MD_CTL},
+#endif /* CBAUD */
+#ifdef CSTOPB
+ {"cstopb", CSTOPB, MD_CTL},
+#endif /* CSTOPB */
+#ifdef CREAD
+ {"cread", CREAD, MD_CTL},
+#endif /* CREAD */
+#ifdef PARENB
+ {"parenb", PARENB, MD_CTL},
+#endif /* PARENB */
+#ifdef PARODD
+ {"parodd", PARODD, MD_CTL},
+#endif /* PARODD */
+#ifdef HUPCL
+ {"hupcl", HUPCL, MD_CTL},
+#endif /* HUPCL */
+#ifdef CLOCAL
+ {"clocal", CLOCAL, MD_CTL},
+#endif /* CLOCAL */
+#ifdef LOBLK
+ {"loblk", LOBLK, MD_CTL},
+#endif /* LOBLK */
+#ifdef CIBAUD
+ {"cibaud", CIBAUD, MD_CTL},
+#endif /* CIBAUD */
+#ifdef CRTSCTS
+#ifdef CCTS_OFLOW
+ {"ccts_oflow", CCTS_OFLOW, MD_CTL},
+#else
+ {"crtscts", CRTSCTS, MD_CTL},
+#endif /* CCTS_OFLOW */
+#endif /* CRTSCTS */
+#ifdef CRTS_IFLOW
+ {"crts_iflow", CRTS_IFLOW, MD_CTL},
+#endif /* CRTS_IFLOW */
+#ifdef CDTRCTS
+ {"cdtrcts", CDTRCTS, MD_CTL},
+#endif /* CDTRCTS */
+#ifdef MDMBUF
+ {"mdmbuf", MDMBUF, MD_CTL},
+#endif /* MDMBUF */
+#ifdef RCV1EN
+ {"rcv1en", RCV1EN, MD_CTL},
+#endif /* RCV1EN */
+#ifdef XMT1EN
+ {"xmt1en", XMT1EN, MD_CTL},
+#endif /* XMT1EN */
+
+#ifdef ISIG
+ {"isig", ISIG, MD_LIN},
+#endif /* ISIG */
+#ifdef ICANON
+ {"icanon", ICANON, MD_LIN},
+#endif /* ICANON */
+#ifdef XCASE
+ {"xcase", XCASE, MD_LIN},
+#endif /* XCASE */
+#ifdef ECHO
+ {"echo", ECHO, MD_LIN},
+#endif /* ECHO */
+#ifdef ECHOE
+ {"echoe", ECHOE, MD_LIN},
+#endif /* ECHOE */
+#ifdef ECHOK
+ {"echok", ECHOK, MD_LIN},
+#endif /* ECHOK */
+#ifdef ECHONL
+ {"echonl", ECHONL, MD_LIN},
+#endif /* ECHONL */
+#ifdef NOFLSH
+ {"noflsh", NOFLSH, MD_LIN},
+#endif /* NOFLSH */
+#ifdef TOSTOP
+ {"tostop", TOSTOP, MD_LIN},
+#endif /* TOSTOP */
+#ifdef ECHOCTL
+ {"echoctl", ECHOCTL, MD_LIN},
+#endif /* ECHOCTL */
+#ifdef ECHOPRT
+ {"echoprt", ECHOPRT, MD_LIN},
+#endif /* ECHOPRT */
+#ifdef ECHOKE
+ {"echoke", ECHOKE, MD_LIN},
+#endif /* ECHOKE */
+#ifdef DEFECHO
+ {"defecho", DEFECHO, MD_LIN},
+#endif /* DEFECHO */
+#ifdef FLUSHO
+ {"flusho", FLUSHO, MD_LIN},
+#endif /* FLUSHO */
+#ifdef PENDIN
+ {"pendin", PENDIN, MD_LIN},
+#endif /* PENDIN */
+#ifdef IEXTEN
+ {"iexten", IEXTEN, MD_LIN},
+#endif /* IEXTEN */
+#ifdef NOKERNINFO
+ {"nokerninfo", NOKERNINFO, MD_LIN},
+#endif /* NOKERNINFO */
+#ifdef ALTWERASE
+ {"altwerase", ALTWERASE, MD_LIN},
+#endif /* ALTWERASE */
+#ifdef EXTPROC
+ {"extproc", EXTPROC, MD_LIN},
+#endif /* EXTPROC */
+
+#if defined(VINTR)
+ {"intr", C_SH(C_INTR), MD_CHAR},
+#endif /* VINTR */
+#if defined(VQUIT)
+ {"quit", C_SH(C_QUIT), MD_CHAR},
+#endif /* VQUIT */
+#if defined(VERASE)
+ {"erase", C_SH(C_ERASE), MD_CHAR},
+#endif /* VERASE */
+#if defined(VKILL)
+ {"kill", C_SH(C_KILL), MD_CHAR},
+#endif /* VKILL */
+#if defined(VEOF)
+ {"eof", C_SH(C_EOF), MD_CHAR},
+#endif /* VEOF */
+#if defined(VEOL)
+ {"eol", C_SH(C_EOL), MD_CHAR},
+#endif /* VEOL */
+#if defined(VEOL2)
+ {"eol2", C_SH(C_EOL2), MD_CHAR},
+#endif /* VEOL2 */
+#if defined(VSWTCH)
+ {"swtch", C_SH(C_SWTCH), MD_CHAR},
+#endif /* VSWTCH */
+#if defined(VDSWTCH)
+ {"dswtch", C_SH(C_DSWTCH), MD_CHAR},
+#endif /* VDSWTCH */
+#if defined(VERASE2)
+ {"erase2", C_SH(C_ERASE2), MD_CHAR},
+#endif /* VERASE2 */
+#if defined(VSTART)
+ {"start", C_SH(C_START), MD_CHAR},
+#endif /* VSTART */
+#if defined(VSTOP)
+ {"stop", C_SH(C_STOP), MD_CHAR},
+#endif /* VSTOP */
+#if defined(VWERASE)
+ {"werase", C_SH(C_WERASE), MD_CHAR},
+#endif /* VWERASE */
+#if defined(VSUSP)
+ {"susp", C_SH(C_SUSP), MD_CHAR},
+#endif /* VSUSP */
+#if defined(VDSUSP)
+ {"dsusp", C_SH(C_DSUSP), MD_CHAR},
+#endif /* VDSUSP */
+#if defined(VREPRINT)
+ {"reprint", C_SH(C_REPRINT), MD_CHAR},
+#endif /* VREPRINT */
+#if defined(VDISCARD)
+ {"discard", C_SH(C_DISCARD), MD_CHAR},
+#endif /* VDISCARD */
+#if defined(VLNEXT)
+ {"lnext", C_SH(C_LNEXT), MD_CHAR},
+#endif /* VLNEXT */
+#if defined(VSTATUS)
+ {"status", C_SH(C_STATUS), MD_CHAR},
+#endif /* VSTATUS */
+#if defined(VPAGE)
+ {"page", C_SH(C_PAGE), MD_CHAR},
+#endif /* VPAGE */
+#if defined(VPGOFF)
+ {"pgoff", C_SH(C_PGOFF), MD_CHAR},
+#endif /* VPGOFF */
+#if defined(VKILL2)
+ {"kill2", C_SH(C_KILL2), MD_CHAR},
+#endif /* VKILL2 */
+#if defined(VBRK)
+ {"brk", C_SH(C_BRK), MD_CHAR},
+#endif /* VBRK */
+#if defined(VMIN)
+ {"min", C_SH(C_MIN), MD_CHAR},
+#endif /* VMIN */
+#if defined(VTIME)
+ {"time", C_SH(C_TIME), MD_CHAR},
+#endif /* VTIME */
+ {NULL, 0, -1},
+};
+
+
+
+#define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
+#define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
+#define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
+
+static int tty_getty(EditLine *, struct termios *);
+static int tty_setty(EditLine *, int, const struct termios *);
+static int tty__getcharindex(int);
+static void tty__getchar(struct termios *, unsigned char *);
+static void tty__setchar(struct termios *, unsigned char *);
+static speed_t tty__getspeed(struct termios *);
+static int tty_setup(EditLine *);
+static void tty_setup_flags(EditLine *, struct termios *, int);
+
+#define t_qu t_ts
+
+/* tty_getty():
+ * Wrapper for tcgetattr to handle EINTR
+ */
+static int
+tty_getty(EditLine *el, struct termios *t)
+{
+ int rv;
+ while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
+ continue;
+ return rv;
+}
+
+/* tty_setty():
+ * Wrapper for tcsetattr to handle EINTR
+ */
+static int
+tty_setty(EditLine *el, int action, const struct termios *t)
+{
+ int rv;
+ while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
+ continue;
+ return rv;
+}
+
+/* tty_setup():
+ * Get the tty parameters and initialize the editing state
+ */
+static int
+tty_setup(EditLine *el)
+{
+ int rst = 1;
+
+ if (el->el_flags & EDIT_DISABLED)
+ return 0;
+
+ if (el->el_tty.t_initialized)
+ return -1;
+
+ if (!isatty(el->el_outfd)) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__,
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ if (tty_getty(el, &el->el_tty.t_or) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or;
+
+ el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
+ el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
+ el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
+
+ tty_setup_flags(el, &el->el_tty.t_ex, EX_IO);
+
+ /*
+ * Reset the tty chars to reasonable defaults
+ * If they are disabled, then enable them.
+ */
+ if (rst) {
+ if (tty__cooked_mode(&el->el_tty.t_ts)) {
+ tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
+ /*
+ * Don't affect CMIN and CTIME for the editor mode
+ */
+ for (rst = 0; rst < C_NCC - 2; rst++)
+ if (el->el_tty.t_c[TS_IO][rst] !=
+ el->el_tty.t_vdisable
+ && el->el_tty.t_c[ED_IO][rst] !=
+ el->el_tty.t_vdisable)
+ el->el_tty.t_c[ED_IO][rst] =
+ el->el_tty.t_c[TS_IO][rst];
+ for (rst = 0; rst < C_NCC; rst++)
+ if (el->el_tty.t_c[TS_IO][rst] !=
+ el->el_tty.t_vdisable)
+ el->el_tty.t_c[EX_IO][rst] =
+ el->el_tty.t_c[TS_IO][rst];
+ }
+ tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
+ if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
+ __func__, strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ }
+
+ tty_setup_flags(el, &el->el_tty.t_ed, ED_IO);
+
+ tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
+ tty_bind_char(el, 1);
+ el->el_tty.t_initialized = 1;
+ return 0;
+}
+
+libedit_private int
+tty_init(EditLine *el)
+{
+
+ el->el_tty.t_mode = EX_IO;
+ el->el_tty.t_vdisable = _POSIX_VDISABLE;
+ el->el_tty.t_initialized = 0;
+ (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
+ (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
+ return tty_setup(el);
+}
+
+
+/* tty_end():
+ * Restore the tty to its original settings
+ */
+libedit_private void
+/*ARGSUSED*/
+tty_end(EditLine *el)
+{
+ if (el->el_flags & EDIT_DISABLED)
+ return;
+
+ if (!el->el_tty.t_initialized)
+ return;
+
+ if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile,
+ "%s: tty_setty: %s\n", __func__, strerror(errno));
+#endif /* DEBUG_TTY */
+ }
+}
+
+
+/* tty__getspeed():
+ * Get the tty speed
+ */
+static speed_t
+tty__getspeed(struct termios *td)
+{
+ speed_t spd;
+
+ if ((spd = cfgetispeed(td)) == 0)
+ spd = cfgetospeed(td);
+ return spd;
+}
+
+/* tty__getspeed():
+ * Return the index of the asked char in the c_cc array
+ */
+static int
+tty__getcharindex(int i)
+{
+ switch (i) {
+#ifdef VINTR
+ case C_INTR:
+ return VINTR;
+#endif /* VINTR */
+#ifdef VQUIT
+ case C_QUIT:
+ return VQUIT;
+#endif /* VQUIT */
+#ifdef VERASE
+ case C_ERASE:
+ return VERASE;
+#endif /* VERASE */
+#ifdef VKILL
+ case C_KILL:
+ return VKILL;
+#endif /* VKILL */
+#ifdef VEOF
+ case C_EOF:
+ return VEOF;
+#endif /* VEOF */
+#ifdef VEOL
+ case C_EOL:
+ return VEOL;
+#endif /* VEOL */
+#ifdef VEOL2
+ case C_EOL2:
+ return VEOL2;
+#endif /* VEOL2 */
+#ifdef VSWTCH
+ case C_SWTCH:
+ return VSWTCH;
+#endif /* VSWTCH */
+#ifdef VDSWTCH
+ case C_DSWTCH:
+ return VDSWTCH;
+#endif /* VDSWTCH */
+#ifdef VERASE2
+ case C_ERASE2:
+ return VERASE2;
+#endif /* VERASE2 */
+#ifdef VSTART
+ case C_START:
+ return VSTART;
+#endif /* VSTART */
+#ifdef VSTOP
+ case C_STOP:
+ return VSTOP;
+#endif /* VSTOP */
+#ifdef VWERASE
+ case C_WERASE:
+ return VWERASE;
+#endif /* VWERASE */
+#ifdef VSUSP
+ case C_SUSP:
+ return VSUSP;
+#endif /* VSUSP */
+#ifdef VDSUSP
+ case C_DSUSP:
+ return VDSUSP;
+#endif /* VDSUSP */
+#ifdef VREPRINT
+ case C_REPRINT:
+ return VREPRINT;
+#endif /* VREPRINT */
+#ifdef VDISCARD
+ case C_DISCARD:
+ return VDISCARD;
+#endif /* VDISCARD */
+#ifdef VLNEXT
+ case C_LNEXT:
+ return VLNEXT;
+#endif /* VLNEXT */
+#ifdef VSTATUS
+ case C_STATUS:
+ return VSTATUS;
+#endif /* VSTATUS */
+#ifdef VPAGE
+ case C_PAGE:
+ return VPAGE;
+#endif /* VPAGE */
+#ifdef VPGOFF
+ case C_PGOFF:
+ return VPGOFF;
+#endif /* VPGOFF */
+#ifdef VKILL2
+ case C_KILL2:
+ return VKILL2;
+#endif /* KILL2 */
+#ifdef VMIN
+ case C_MIN:
+ return VMIN;
+#endif /* VMIN */
+#ifdef VTIME
+ case C_TIME:
+ return VTIME;
+#endif /* VTIME */
+ default:
+ return -1;
+ }
+}
+
+/* tty__getchar():
+ * Get the tty characters
+ */
+static void
+tty__getchar(struct termios *td, unsigned char *s)
+{
+
+#ifdef VINTR
+ s[C_INTR] = td->c_cc[VINTR];
+#endif /* VINTR */
+#ifdef VQUIT
+ s[C_QUIT] = td->c_cc[VQUIT];
+#endif /* VQUIT */
+#ifdef VERASE
+ s[C_ERASE] = td->c_cc[VERASE];
+#endif /* VERASE */
+#ifdef VKILL
+ s[C_KILL] = td->c_cc[VKILL];
+#endif /* VKILL */
+#ifdef VEOF
+ s[C_EOF] = td->c_cc[VEOF];
+#endif /* VEOF */
+#ifdef VEOL
+ s[C_EOL] = td->c_cc[VEOL];
+#endif /* VEOL */
+#ifdef VEOL2
+ s[C_EOL2] = td->c_cc[VEOL2];
+#endif /* VEOL2 */
+#ifdef VSWTCH
+ s[C_SWTCH] = td->c_cc[VSWTCH];
+#endif /* VSWTCH */
+#ifdef VDSWTCH
+ s[C_DSWTCH] = td->c_cc[VDSWTCH];
+#endif /* VDSWTCH */
+#ifdef VERASE2
+ s[C_ERASE2] = td->c_cc[VERASE2];
+#endif /* VERASE2 */
+#ifdef VSTART
+ s[C_START] = td->c_cc[VSTART];
+#endif /* VSTART */
+#ifdef VSTOP
+ s[C_STOP] = td->c_cc[VSTOP];
+#endif /* VSTOP */
+#ifdef VWERASE
+ s[C_WERASE] = td->c_cc[VWERASE];
+#endif /* VWERASE */
+#ifdef VSUSP
+ s[C_SUSP] = td->c_cc[VSUSP];
+#endif /* VSUSP */
+#ifdef VDSUSP
+ s[C_DSUSP] = td->c_cc[VDSUSP];
+#endif /* VDSUSP */
+#ifdef VREPRINT
+ s[C_REPRINT] = td->c_cc[VREPRINT];
+#endif /* VREPRINT */
+#ifdef VDISCARD
+ s[C_DISCARD] = td->c_cc[VDISCARD];
+#endif /* VDISCARD */
+#ifdef VLNEXT
+ s[C_LNEXT] = td->c_cc[VLNEXT];
+#endif /* VLNEXT */
+#ifdef VSTATUS
+ s[C_STATUS] = td->c_cc[VSTATUS];
+#endif /* VSTATUS */
+#ifdef VPAGE
+ s[C_PAGE] = td->c_cc[VPAGE];
+#endif /* VPAGE */
+#ifdef VPGOFF
+ s[C_PGOFF] = td->c_cc[VPGOFF];
+#endif /* VPGOFF */
+#ifdef VKILL2
+ s[C_KILL2] = td->c_cc[VKILL2];
+#endif /* KILL2 */
+#ifdef VMIN
+ s[C_MIN] = td->c_cc[VMIN];
+#endif /* VMIN */
+#ifdef VTIME
+ s[C_TIME] = td->c_cc[VTIME];
+#endif /* VTIME */
+} /* tty__getchar */
+
+
+/* tty__setchar():
+ * Set the tty characters
+ */
+static void
+tty__setchar(struct termios *td, unsigned char *s)
+{
+
+#ifdef VINTR
+ td->c_cc[VINTR] = s[C_INTR];
+#endif /* VINTR */
+#ifdef VQUIT
+ td->c_cc[VQUIT] = s[C_QUIT];
+#endif /* VQUIT */
+#ifdef VERASE
+ td->c_cc[VERASE] = s[C_ERASE];
+#endif /* VERASE */
+#ifdef VKILL
+ td->c_cc[VKILL] = s[C_KILL];
+#endif /* VKILL */
+#ifdef VEOF
+ td->c_cc[VEOF] = s[C_EOF];
+#endif /* VEOF */
+#ifdef VEOL
+ td->c_cc[VEOL] = s[C_EOL];
+#endif /* VEOL */
+#ifdef VEOL2
+ td->c_cc[VEOL2] = s[C_EOL2];
+#endif /* VEOL2 */
+#ifdef VSWTCH
+ td->c_cc[VSWTCH] = s[C_SWTCH];
+#endif /* VSWTCH */
+#ifdef VDSWTCH
+ td->c_cc[VDSWTCH] = s[C_DSWTCH];
+#endif /* VDSWTCH */
+#ifdef VERASE2
+ td->c_cc[VERASE2] = s[C_ERASE2];
+#endif /* VERASE2 */
+#ifdef VSTART
+ td->c_cc[VSTART] = s[C_START];
+#endif /* VSTART */
+#ifdef VSTOP
+ td->c_cc[VSTOP] = s[C_STOP];
+#endif /* VSTOP */
+#ifdef VWERASE
+ td->c_cc[VWERASE] = s[C_WERASE];
+#endif /* VWERASE */
+#ifdef VSUSP
+ td->c_cc[VSUSP] = s[C_SUSP];
+#endif /* VSUSP */
+#ifdef VDSUSP
+ td->c_cc[VDSUSP] = s[C_DSUSP];
+#endif /* VDSUSP */
+#ifdef VREPRINT
+ td->c_cc[VREPRINT] = s[C_REPRINT];
+#endif /* VREPRINT */
+#ifdef VDISCARD
+ td->c_cc[VDISCARD] = s[C_DISCARD];
+#endif /* VDISCARD */
+#ifdef VLNEXT
+ td->c_cc[VLNEXT] = s[C_LNEXT];
+#endif /* VLNEXT */
+#ifdef VSTATUS
+ td->c_cc[VSTATUS] = s[C_STATUS];
+#endif /* VSTATUS */
+#ifdef VPAGE
+ td->c_cc[VPAGE] = s[C_PAGE];
+#endif /* VPAGE */
+#ifdef VPGOFF
+ td->c_cc[VPGOFF] = s[C_PGOFF];
+#endif /* VPGOFF */
+#ifdef VKILL2
+ td->c_cc[VKILL2] = s[C_KILL2];
+#endif /* VKILL2 */
+#ifdef VMIN
+ td->c_cc[VMIN] = s[C_MIN];
+#endif /* VMIN */
+#ifdef VTIME
+ td->c_cc[VTIME] = s[C_TIME];
+#endif /* VTIME */
+} /* tty__setchar */
+
+
+/* tty_bind_char():
+ * Rebind the editline functions
+ */
+libedit_private void
+tty_bind_char(EditLine *el, int force)
+{
+
+ unsigned char *t_n = el->el_tty.t_c[ED_IO];
+ unsigned char *t_o = el->el_tty.t_ed.c_cc;
+ wchar_t new[2], old[2];
+ const ttymap_t *tp;
+ el_action_t *map, *alt;
+ const el_action_t *dmap, *dalt;
+ new[1] = old[1] = '\0';
+
+ map = el->el_map.key;
+ alt = el->el_map.alt;
+ if (el->el_map.type == MAP_VI) {
+ dmap = el->el_map.vii;
+ dalt = el->el_map.vic;
+ } else {
+ dmap = el->el_map.emacs;
+ dalt = NULL;
+ }
+
+ for (tp = tty_map; tp->nch != (wint_t)-1; tp++) {
+ new[0] = (wchar_t)t_n[tp->nch];
+ old[0] = (wchar_t)t_o[tp->och];
+ if (new[0] == old[0] && !force)
+ continue;
+ /* Put the old default binding back, and set the new binding */
+ keymacro_clear(el, map, old);
+ map[(unsigned char)old[0]] = dmap[(unsigned char)old[0]];
+ keymacro_clear(el, map, new);
+ /* MAP_VI == 1, MAP_EMACS == 0... */
+ map[(unsigned char)new[0]] = tp->bind[el->el_map.type];
+ if (dalt) {
+ keymacro_clear(el, alt, old);
+ alt[(unsigned char)old[0]] =
+ dalt[(unsigned char)old[0]];
+ keymacro_clear(el, alt, new);
+ alt[(unsigned char)new[0]] =
+ tp->bind[el->el_map.type + 1];
+ }
+ }
+}
+
+
+static tcflag_t *
+tty__get_flag(struct termios *t, int kind) {
+ switch (kind) {
+ case MD_INP:
+ return &t->c_iflag;
+ case MD_OUT:
+ return &t->c_oflag;
+ case MD_CTL:
+ return &t->c_cflag;
+ case MD_LIN:
+ return &t->c_lflag;
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+}
+
+
+static tcflag_t
+tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind)
+{
+ f &= ~el->el_tty.t_t[mode][kind].t_clrmask;
+ f |= el->el_tty.t_t[mode][kind].t_setmask;
+ return f;
+}
+
+
+static void
+tty_update_flags(EditLine *el, int kind)
+{
+ tcflag_t *tt, *ed, *ex;
+ tt = tty__get_flag(&el->el_tty.t_ts, kind);
+ ed = tty__get_flag(&el->el_tty.t_ed, kind);
+ ex = tty__get_flag(&el->el_tty.t_ex, kind);
+
+ if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) {
+ *ed = tty_update_flag(el, *tt, ED_IO, kind);
+ *ex = tty_update_flag(el, *tt, EX_IO, kind);
+ }
+}
+
+
+static void
+tty_update_char(EditLine *el, int mode, int c) {
+ if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c)))
+ && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c]))
+ el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c];
+ if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c))
+ el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable;
+}
+
+
+/* tty_rawmode():
+ * Set terminal into 1 character at a time mode.
+ */
+libedit_private int
+tty_rawmode(EditLine *el)
+{
+
+ if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
+ return 0;
+
+ if (el->el_flags & EDIT_DISABLED)
+ return 0;
+
+ if (tty_getty(el, &el->el_tty.t_ts) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ /*
+ * We always keep up with the eight bit setting and the speed of the
+ * tty. But we only believe changes that are made to cooked mode!
+ */
+ el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
+ el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
+
+ if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
+ tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
+ (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
+ (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
+ (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
+ (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
+ }
+ if (tty__cooked_mode(&el->el_tty.t_ts)) {
+ int i;
+
+ for (i = MD_INP; i <= MD_LIN; i++)
+ tty_update_flags(el, i);
+
+ if (tty__gettabs(&el->el_tty.t_ex) == 0)
+ el->el_tty.t_tabs = 0;
+ else
+ el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
+
+ tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
+ /*
+ * Check if the user made any changes.
+ * If he did, then propagate the changes to the
+ * edit and execute data structures.
+ */
+ for (i = 0; i < C_NCC; i++)
+ if (el->el_tty.t_c[TS_IO][i] !=
+ el->el_tty.t_c[EX_IO][i])
+ break;
+
+ if (i != C_NCC) {
+ /*
+ * Propagate changes only to the unlibedit_private
+ * chars that have been modified just now.
+ */
+ for (i = 0; i < C_NCC; i++)
+ tty_update_char(el, ED_IO, i);
+
+ tty_bind_char(el, 0);
+ tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
+
+ for (i = 0; i < C_NCC; i++)
+ tty_update_char(el, EX_IO, i);
+
+ tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
+ }
+ }
+ if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ el->el_tty.t_mode = ED_IO;
+ return 0;
+}
+
+
+/* tty_cookedmode():
+ * Set the tty back to normal mode
+ */
+libedit_private int
+tty_cookedmode(EditLine *el)
+{ /* set tty in normal setup */
+
+ if (el->el_tty.t_mode == EX_IO)
+ return 0;
+
+ if (el->el_flags & EDIT_DISABLED)
+ return 0;
+
+ if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ el->el_tty.t_mode = EX_IO;
+ return 0;
+}
+
+
+/* tty_quotemode():
+ * Turn on quote mode
+ */
+libedit_private int
+tty_quotemode(EditLine *el)
+{
+ if (el->el_tty.t_mode == QU_IO)
+ return 0;
+
+ el->el_tty.t_qu = el->el_tty.t_ed;
+
+ tty_setup_flags(el, &el->el_tty.t_qu, QU_IO);
+
+ if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ el->el_tty.t_mode = QU_IO;
+ return 0;
+}
+
+
+/* tty_noquotemode():
+ * Turn off quote mode
+ */
+libedit_private int
+tty_noquotemode(EditLine *el)
+{
+
+ if (el->el_tty.t_mode != QU_IO)
+ return 0;
+ if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ el->el_tty.t_mode = ED_IO;
+ return 0;
+}
+
+
+/* tty_stty():
+ * Stty builtin
+ */
+libedit_private int
+/*ARGSUSED*/
+tty_stty(EditLine *el, int argc __attribute__((__unused__)),
+ const wchar_t **argv)
+{
+ const ttymodes_t *m;
+ char x;
+ int aflag = 0;
+ const wchar_t *s, *d;
+ char name[EL_BUFSIZ];
+ struct termios *tios = &el->el_tty.t_ex;
+ int z = EX_IO;
+
+ if (argv == NULL)
+ return -1;
+ strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+
+ while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
+ switch (argv[0][1]) {
+ case 'a':
+ aflag++;
+ argv++;
+ break;
+ case 'd':
+ argv++;
+ tios = &el->el_tty.t_ed;
+ z = ED_IO;
+ break;
+ case 'x':
+ argv++;
+ tios = &el->el_tty.t_ex;
+ z = EX_IO;
+ break;
+ case 'q':
+ argv++;
+ tios = &el->el_tty.t_ts;
+ z = QU_IO;
+ break;
+ default:
+ (void) fprintf(el->el_errfile,
+ "%s: Unknown switch `%lc'.\n",
+ name, (wint_t)argv[0][1]);
+ return -1;
+ }
+
+ if (!argv || !*argv) {
+ int i = -1;
+ size_t len = 0, st = 0, cu;
+ for (m = ttymodes; m->m_name; m++) {
+ if (m->m_type != i) {
+ (void) fprintf(el->el_outfile, "%s%s",
+ i != -1 ? "\n" : "",
+ el->el_tty.t_t[z][m->m_type].t_name);
+ i = m->m_type;
+ st = len =
+ strlen(el->el_tty.t_t[z][m->m_type].t_name);
+ }
+ if (i != -1) {
+ x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
+ ? '+' : '\0';
+
+ if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
+ x = '-';
+ } else {
+ x = '\0';
+ }
+
+ if (x != '\0' || aflag) {
+
+ cu = strlen(m->m_name) + (x != '\0') + 1;
+
+ if (len + cu >=
+ (size_t)el->el_terminal.t_size.h) {
+ (void) fprintf(el->el_outfile, "\n%*s",
+ (int)st, "");
+ len = st + cu;
+ } else
+ len += cu;
+
+ if (x != '\0')
+ (void) fprintf(el->el_outfile, "%c%s ",
+ x, m->m_name);
+ else
+ (void) fprintf(el->el_outfile, "%s ",
+ m->m_name);
+ }
+ }
+ (void) fprintf(el->el_outfile, "\n");
+ return 0;
+ }
+ while (argv && (s = *argv++)) {
+ const wchar_t *p;
+ switch (*s) {
+ case '+':
+ case '-':
+ x = (char)*s++;
+ break;
+ default:
+ x = '\0';
+ break;
+ }
+ d = s;
+ p = wcschr(s, L'=');
+ for (m = ttymodes; m->m_name; m++)
+ if ((p ? strncmp(m->m_name, ct_encode_string(d,
+ &el->el_scratch), (size_t)(p - d)) :
+ strcmp(m->m_name, ct_encode_string(d,
+ &el->el_scratch))) == 0 &&
+ (p == NULL || m->m_type == MD_CHAR))
+ break;
+
+ if (!m->m_name) {
+ (void) fprintf(el->el_errfile,
+ "%s: Invalid argument `%ls'.\n", name, d);
+ return -1;
+ }
+ if (p) {
+ int c = ffs((int)m->m_value);
+ int v = *++p ? parse__escape(&p) :
+ el->el_tty.t_vdisable;
+ assert(c != 0);
+ c--;
+ c = tty__getcharindex(c);
+ assert(c != -1);
+ tios->c_cc[c] = (cc_t)v;
+ continue;
+ }
+ switch (x) {
+ case '+':
+ el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
+ el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
+ break;
+ case '-':
+ el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
+ el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
+ break;
+ default:
+ el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
+ el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
+ break;
+ }
+ }
+
+ tty_setup_flags(el, tios, z);
+ if (el->el_tty.t_mode == z) {
+ if (tty_setty(el, TCSADRAIN, tios) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
+ __func__, strerror(errno));
+#endif /* DEBUG_TTY */
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+#ifdef notyet
+/* tty_printchar():
+ * DEbugging routine to print the tty characters
+ */
+static void
+tty_printchar(EditLine *el, unsigned char *s)
+{
+ ttyperm_t *m;
+ int i;
+
+ for (i = 0; i < C_NCC; i++) {
+ for (m = el->el_tty.t_t; m->m_name; m++)
+ if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
+ break;
+ if (m->m_name)
+ (void) fprintf(el->el_errfile, "%s ^%c ",
+ m->m_name, s[i] + 'A' - 1);
+ if (i % 5 == 0)
+ (void) fprintf(el->el_errfile, "\n");
+ }
+ (void) fprintf(el->el_errfile, "\n");
+}
+#endif /* notyet */
+
+
+static void
+tty_setup_flags(EditLine *el, struct termios *tios, int mode)
+{
+ int kind;
+ for (kind = MD_INP; kind <= MD_LIN; kind++) {
+ tcflag_t *f = tty__get_flag(tios, kind);
+ *f = tty_update_flag(el, *f, mode, kind);
+ }
+}
diff --git a/third_party/heimdal/lib/libedit/src/tty.h b/third_party/heimdal/lib/libedit/src/tty.h
new file mode 100644
index 0000000..2603e1a
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/tty.h
@@ -0,0 +1,481 @@
+/* $NetBSD: tty.h,v 1.21 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tty.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * el.tty.h: Local terminal header
+ */
+#ifndef _h_el_tty
+#define _h_el_tty
+
+#include <termios.h>
+#include <unistd.h>
+
+/* Define our own since everyone gets it wrong! */
+#define CONTROL(A) ((A) & 037)
+
+/*
+ * Aix compatible names
+ */
+# if defined(VWERSE) && !defined(VWERASE)
+# define VWERASE VWERSE
+# endif /* VWERSE && !VWERASE */
+
+# if defined(VDISCRD) && !defined(VDISCARD)
+# define VDISCARD VDISCRD
+# endif /* VDISCRD && !VDISCARD */
+
+# if defined(VFLUSHO) && !defined(VDISCARD)
+# define VDISCARD VFLUSHO
+# endif /* VFLUSHO && VDISCARD */
+
+# if defined(VSTRT) && !defined(VSTART)
+# define VSTART VSTRT
+# endif /* VSTRT && ! VSTART */
+
+# if defined(VSTAT) && !defined(VSTATUS)
+# define VSTATUS VSTAT
+# endif /* VSTAT && ! VSTATUS */
+
+# ifndef ONLRET
+# define ONLRET 0
+# endif /* ONLRET */
+
+# ifndef TAB3
+# ifdef OXTABS
+# define TAB3 OXTABS
+# else
+# define TAB3 0
+# endif /* OXTABS */
+# endif /* !TAB3 */
+
+# if defined(OXTABS) && !defined(XTABS)
+# define XTABS OXTABS
+# endif /* OXTABS && !XTABS */
+
+# ifndef ONLCR
+# define ONLCR 0
+# endif /* ONLCR */
+
+# ifndef IEXTEN
+# define IEXTEN 0
+# endif /* IEXTEN */
+
+# ifndef ECHOCTL
+# define ECHOCTL 0
+# endif /* ECHOCTL */
+
+# ifndef PARENB
+# define PARENB 0
+# endif /* PARENB */
+
+# ifndef EXTPROC
+# define EXTPROC 0
+# endif /* EXTPROC */
+
+# ifndef FLUSHO
+# define FLUSHO 0
+# endif /* FLUSHO */
+
+
+# if defined(VDISABLE) && !defined(_POSIX_VDISABLE)
+# define _POSIX_VDISABLE VDISABLE
+# endif /* VDISABLE && ! _POSIX_VDISABLE */
+
+/*
+ * Work around ISC's definition of IEXTEN which is
+ * XCASE!
+ */
+# ifdef ISC
+# if defined(IEXTEN) && defined(XCASE)
+# if IEXTEN == XCASE
+# undef IEXTEN
+# define IEXTEN 0
+# endif /* IEXTEN == XCASE */
+# endif /* IEXTEN && XCASE */
+# if defined(IEXTEN) && !defined(XCASE)
+# define XCASE IEXTEN
+# undef IEXTEN
+# define IEXTEN 0
+# endif /* IEXTEN && !XCASE */
+# endif /* ISC */
+
+/*
+ * Work around convex weirdness where turning off IEXTEN makes us
+ * lose all postprocessing!
+ */
+#if defined(convex) || defined(__convex__)
+# if defined(IEXTEN) && IEXTEN != 0
+# undef IEXTEN
+# define IEXTEN 0
+# endif /* IEXTEN != 0 */
+#endif /* convex || __convex__ */
+
+/*
+ * So that we don't lose job control.
+ */
+#ifdef __SVR4
+# undef CSWTCH
+#endif
+
+#ifndef _POSIX_VDISABLE
+# define _POSIX_VDISABLE ((unsigned char) -1)
+#endif /* _POSIX_VDISABLE */
+
+#if !defined(CREPRINT) && defined(CRPRNT)
+# define CREPRINT CRPRNT
+#endif /* !CREPRINT && CRPRNT */
+#if !defined(CDISCARD) && defined(CFLUSH)
+# define CDISCARD CFLUSH
+#endif /* !CDISCARD && CFLUSH */
+
+#ifndef CINTR
+# define CINTR CONTROL('c')
+#endif /* CINTR */
+#ifndef CQUIT
+# define CQUIT 034 /* ^\ */
+#endif /* CQUIT */
+#ifndef CERASE
+# define CERASE 0177 /* ^? */
+#endif /* CERASE */
+#ifndef CKILL
+# define CKILL CONTROL('u')
+#endif /* CKILL */
+#ifndef CEOF
+# define CEOF CONTROL('d')
+#endif /* CEOF */
+#ifndef CEOL
+# define CEOL _POSIX_VDISABLE
+#endif /* CEOL */
+#ifndef CEOL2
+# define CEOL2 _POSIX_VDISABLE
+#endif /* CEOL2 */
+#ifndef CSWTCH
+# define CSWTCH _POSIX_VDISABLE
+#endif /* CSWTCH */
+#ifndef CDSWTCH
+# define CDSWTCH _POSIX_VDISABLE
+#endif /* CDSWTCH */
+#ifndef CERASE2
+# define CERASE2 _POSIX_VDISABLE
+#endif /* CERASE2 */
+#ifndef CSTART
+# define CSTART CONTROL('q')
+#endif /* CSTART */
+#ifndef CSTOP
+# define CSTOP CONTROL('s')
+#endif /* CSTOP */
+#ifndef CSUSP
+# define CSUSP CONTROL('z')
+#endif /* CSUSP */
+#ifndef CDSUSP
+# define CDSUSP CONTROL('y')
+#endif /* CDSUSP */
+
+#ifdef hpux
+
+# ifndef CREPRINT
+# define CREPRINT _POSIX_VDISABLE
+# endif /* CREPRINT */
+# ifndef CDISCARD
+# define CDISCARD _POSIX_VDISABLE
+# endif /* CDISCARD */
+# ifndef CLNEXT
+# define CLNEXT _POSIX_VDISABLE
+# endif /* CLNEXT */
+# ifndef CWERASE
+# define CWERASE _POSIX_VDISABLE
+# endif /* CWERASE */
+
+#else /* !hpux */
+
+# ifndef CREPRINT
+# define CREPRINT CONTROL('r')
+# endif /* CREPRINT */
+# ifndef CDISCARD
+# define CDISCARD CONTROL('o')
+# endif /* CDISCARD */
+# ifndef CLNEXT
+# define CLNEXT CONTROL('v')
+# endif /* CLNEXT */
+# ifndef CWERASE
+# define CWERASE CONTROL('w')
+# endif /* CWERASE */
+
+#endif /* hpux */
+
+#ifndef CSTATUS
+# define CSTATUS CONTROL('t')
+#endif /* CSTATUS */
+#ifndef CPAGE
+# define CPAGE ' '
+#endif /* CPAGE */
+#ifndef CPGOFF
+# define CPGOFF CONTROL('m')
+#endif /* CPGOFF */
+#ifndef CKILL2
+# define CKILL2 _POSIX_VDISABLE
+#endif /* CKILL2 */
+#ifndef CBRK
+# ifndef masscomp
+# define CBRK 0377
+# else
+# define CBRK '\0'
+# endif /* masscomp */
+#endif /* CBRK */
+#ifndef CMIN
+# define CMIN CEOF
+#endif /* CMIN */
+#ifndef CTIME
+# define CTIME CEOL
+#endif /* CTIME */
+
+/*
+ * Fix for sun inconsistency. On termio VSUSP and the rest of the
+ * ttychars > NCC are defined. So we undefine them.
+ */
+#if defined(TERMIO) || defined(POSIX)
+# if defined(POSIX) && defined(NCCS)
+# define NUMCC NCCS
+# else
+# ifdef NCC
+# define NUMCC NCC
+# endif /* NCC */
+# endif /* POSIX && NCCS */
+# ifdef NUMCC
+# ifdef VINTR
+# if NUMCC <= VINTR
+# undef VINTR
+# endif /* NUMCC <= VINTR */
+# endif /* VINTR */
+# ifdef VQUIT
+# if NUMCC <= VQUIT
+# undef VQUIT
+# endif /* NUMCC <= VQUIT */
+# endif /* VQUIT */
+# ifdef VERASE
+# if NUMCC <= VERASE
+# undef VERASE
+# endif /* NUMCC <= VERASE */
+# endif /* VERASE */
+# ifdef VKILL
+# if NUMCC <= VKILL
+# undef VKILL
+# endif /* NUMCC <= VKILL */
+# endif /* VKILL */
+# ifdef VEOF
+# if NUMCC <= VEOF
+# undef VEOF
+# endif /* NUMCC <= VEOF */
+# endif /* VEOF */
+# ifdef VEOL
+# if NUMCC <= VEOL
+# undef VEOL
+# endif /* NUMCC <= VEOL */
+# endif /* VEOL */
+# ifdef VEOL2
+# if NUMCC <= VEOL2
+# undef VEOL2
+# endif /* NUMCC <= VEOL2 */
+# endif /* VEOL2 */
+# ifdef VSWTCH
+# if NUMCC <= VSWTCH
+# undef VSWTCH
+# endif /* NUMCC <= VSWTCH */
+# endif /* VSWTCH */
+# ifdef VDSWTCH
+# if NUMCC <= VDSWTCH
+# undef VDSWTCH
+# endif /* NUMCC <= VDSWTCH */
+# endif /* VDSWTCH */
+# ifdef VERASE2
+# if NUMCC <= VERASE2
+# undef VERASE2
+# endif /* NUMCC <= VERASE2 */
+# endif /* VERASE2 */
+# ifdef VSTART
+# if NUMCC <= VSTART
+# undef VSTART
+# endif /* NUMCC <= VSTART */
+# endif /* VSTART */
+# ifdef VSTOP
+# if NUMCC <= VSTOP
+# undef VSTOP
+# endif /* NUMCC <= VSTOP */
+# endif /* VSTOP */
+# ifdef VWERASE
+# if NUMCC <= VWERASE
+# undef VWERASE
+# endif /* NUMCC <= VWERASE */
+# endif /* VWERASE */
+# ifdef VSUSP
+# if NUMCC <= VSUSP
+# undef VSUSP
+# endif /* NUMCC <= VSUSP */
+# endif /* VSUSP */
+# ifdef VDSUSP
+# if NUMCC <= VDSUSP
+# undef VDSUSP
+# endif /* NUMCC <= VDSUSP */
+# endif /* VDSUSP */
+# ifdef VREPRINT
+# if NUMCC <= VREPRINT
+# undef VREPRINT
+# endif /* NUMCC <= VREPRINT */
+# endif /* VREPRINT */
+# ifdef VDISCARD
+# if NUMCC <= VDISCARD
+# undef VDISCARD
+# endif /* NUMCC <= VDISCARD */
+# endif /* VDISCARD */
+# ifdef VLNEXT
+# if NUMCC <= VLNEXT
+# undef VLNEXT
+# endif /* NUMCC <= VLNEXT */
+# endif /* VLNEXT */
+# ifdef VSTATUS
+# if NUMCC <= VSTATUS
+# undef VSTATUS
+# endif /* NUMCC <= VSTATUS */
+# endif /* VSTATUS */
+# ifdef VPAGE
+# if NUMCC <= VPAGE
+# undef VPAGE
+# endif /* NUMCC <= VPAGE */
+# endif /* VPAGE */
+# ifdef VPGOFF
+# if NUMCC <= VPGOFF
+# undef VPGOFF
+# endif /* NUMCC <= VPGOFF */
+# endif /* VPGOFF */
+# ifdef VKILL2
+# if NUMCC <= VKILL2
+# undef VKILL2
+# endif /* NUMCC <= VKILL2 */
+# endif /* VKILL2 */
+# ifdef VBRK
+# if NUMCC <= VBRK
+# undef VBRK
+# endif /* NUMCC <= VBRK */
+# endif /* VBRK */
+# ifdef VMIN
+# if NUMCC <= VMIN
+# undef VMIN
+# endif /* NUMCC <= VMIN */
+# endif /* VMIN */
+# ifdef VTIME
+# if NUMCC <= VTIME
+# undef VTIME
+# endif /* NUMCC <= VTIME */
+# endif /* VTIME */
+# endif /* NUMCC */
+#endif /* !POSIX */
+
+#define C_INTR 0
+#define C_QUIT 1
+#define C_ERASE 2
+#define C_KILL 3
+#define C_EOF 4
+#define C_EOL 5
+#define C_EOL2 6
+#define C_SWTCH 7
+#define C_DSWTCH 8
+#define C_ERASE2 9
+#define C_START 10
+#define C_STOP 11
+#define C_WERASE 12
+#define C_SUSP 13
+#define C_DSUSP 14
+#define C_REPRINT 15
+#define C_DISCARD 16
+#define C_LNEXT 17
+#define C_STATUS 18
+#define C_PAGE 19
+#define C_PGOFF 20
+#define C_KILL2 21
+#define C_BRK 22
+#define C_MIN 23
+#define C_TIME 24
+#define C_NCC 25
+#define C_SH(A) ((unsigned int)(1 << (A)))
+
+/*
+ * Terminal dependend data structures
+ */
+#define EX_IO 0 /* while we are executing */
+#define ED_IO 1 /* while we are editing */
+#define TS_IO 2 /* new mode from terminal */
+#define QU_IO 2 /* used only for quoted chars */
+#define NN_IO 3 /* The number of entries */
+
+/* Don't re-order */
+#define MD_INP 0
+#define MD_OUT 1
+#define MD_CTL 2
+#define MD_LIN 3
+#define MD_CHAR 4
+#define MD_NN 5
+
+typedef struct {
+ const char *t_name;
+ unsigned int t_setmask;
+ unsigned int t_clrmask;
+} ttyperm_t[NN_IO][MD_NN];
+
+typedef unsigned char ttychar_t[NN_IO][C_NCC];
+
+libedit_private int tty_init(EditLine *);
+libedit_private void tty_end(EditLine *);
+libedit_private int tty_stty(EditLine *, int, const wchar_t **);
+libedit_private int tty_rawmode(EditLine *);
+libedit_private int tty_cookedmode(EditLine *);
+libedit_private int tty_quotemode(EditLine *);
+libedit_private int tty_noquotemode(EditLine *);
+libedit_private void tty_bind_char(EditLine *, int);
+
+typedef struct {
+ ttyperm_t t_t;
+ ttychar_t t_c;
+ struct termios t_or, t_ex, t_ed, t_ts;
+ int t_tabs;
+ int t_eight;
+ speed_t t_speed;
+ unsigned char t_mode;
+ unsigned char t_vdisable;
+ unsigned char t_initialized;
+} el_tty_t;
+
+
+#endif /* _h_el_tty */
diff --git a/third_party/heimdal/lib/libedit/src/unvis.c b/third_party/heimdal/lib/libedit/src/unvis.c
new file mode 100644
index 0000000..719f86a
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/unvis.c
@@ -0,0 +1,553 @@
+/* $NetBSD: unvis.c,v 1.44 2014/09/26 15:43:36 roy Exp $ */
+
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: unvis.c,v 1.44 2014/09/26 15:43:36 roy Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <vis.h>
+
+#if !HAVE_VIS
+/*
+ * decode driven by state machine
+ */
+#define S_GROUND 0 /* haven't seen escape char */
+#define S_START 1 /* start decoding special sequence */
+#define S_META 2 /* metachar started (M) */
+#define S_META1 3 /* metachar more, regular char (-) */
+#define S_CTRL 4 /* control char started (^) */
+#define S_OCTAL2 5 /* octal digit 2 */
+#define S_OCTAL3 6 /* octal digit 3 */
+#define S_HEX 7 /* mandatory hex digit */
+#define S_HEX1 8 /* http hex digit */
+#define S_HEX2 9 /* http hex digit 2 */
+#define S_MIME1 10 /* mime hex digit 1 */
+#define S_MIME2 11 /* mime hex digit 2 */
+#define S_EATCRNL 12 /* mime eating CRNL */
+#define S_AMP 13 /* seen & */
+#define S_NUMBER 14 /* collecting number */
+#define S_STRING 15 /* collecting string */
+
+#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10))
+#define XTOD(c) (isdigit(c) ? (c - '0') : ((c - 'A') + 10))
+
+/*
+ * RFC 1866
+ */
+static const struct nv {
+ char name[7];
+ uint8_t value;
+} nv[] = {
+ { "AElig", 198 }, /* capital AE diphthong (ligature) */
+ { "Aacute", 193 }, /* capital A, acute accent */
+ { "Acirc", 194 }, /* capital A, circumflex accent */
+ { "Agrave", 192 }, /* capital A, grave accent */
+ { "Aring", 197 }, /* capital A, ring */
+ { "Atilde", 195 }, /* capital A, tilde */
+ { "Auml", 196 }, /* capital A, dieresis or umlaut mark */
+ { "Ccedil", 199 }, /* capital C, cedilla */
+ { "ETH", 208 }, /* capital Eth, Icelandic */
+ { "Eacute", 201 }, /* capital E, acute accent */
+ { "Ecirc", 202 }, /* capital E, circumflex accent */
+ { "Egrave", 200 }, /* capital E, grave accent */
+ { "Euml", 203 }, /* capital E, dieresis or umlaut mark */
+ { "Iacute", 205 }, /* capital I, acute accent */
+ { "Icirc", 206 }, /* capital I, circumflex accent */
+ { "Igrave", 204 }, /* capital I, grave accent */
+ { "Iuml", 207 }, /* capital I, dieresis or umlaut mark */
+ { "Ntilde", 209 }, /* capital N, tilde */
+ { "Oacute", 211 }, /* capital O, acute accent */
+ { "Ocirc", 212 }, /* capital O, circumflex accent */
+ { "Ograve", 210 }, /* capital O, grave accent */
+ { "Oslash", 216 }, /* capital O, slash */
+ { "Otilde", 213 }, /* capital O, tilde */
+ { "Ouml", 214 }, /* capital O, dieresis or umlaut mark */
+ { "THORN", 222 }, /* capital THORN, Icelandic */
+ { "Uacute", 218 }, /* capital U, acute accent */
+ { "Ucirc", 219 }, /* capital U, circumflex accent */
+ { "Ugrave", 217 }, /* capital U, grave accent */
+ { "Uuml", 220 }, /* capital U, dieresis or umlaut mark */
+ { "Yacute", 221 }, /* capital Y, acute accent */
+ { "aacute", 225 }, /* small a, acute accent */
+ { "acirc", 226 }, /* small a, circumflex accent */
+ { "acute", 180 }, /* acute accent */
+ { "aelig", 230 }, /* small ae diphthong (ligature) */
+ { "agrave", 224 }, /* small a, grave accent */
+ { "amp", 38 }, /* ampersand */
+ { "aring", 229 }, /* small a, ring */
+ { "atilde", 227 }, /* small a, tilde */
+ { "auml", 228 }, /* small a, dieresis or umlaut mark */
+ { "brvbar", 166 }, /* broken (vertical) bar */
+ { "ccedil", 231 }, /* small c, cedilla */
+ { "cedil", 184 }, /* cedilla */
+ { "cent", 162 }, /* cent sign */
+ { "copy", 169 }, /* copyright sign */
+ { "curren", 164 }, /* general currency sign */
+ { "deg", 176 }, /* degree sign */
+ { "divide", 247 }, /* divide sign */
+ { "eacute", 233 }, /* small e, acute accent */
+ { "ecirc", 234 }, /* small e, circumflex accent */
+ { "egrave", 232 }, /* small e, grave accent */
+ { "eth", 240 }, /* small eth, Icelandic */
+ { "euml", 235 }, /* small e, dieresis or umlaut mark */
+ { "frac12", 189 }, /* fraction one-half */
+ { "frac14", 188 }, /* fraction one-quarter */
+ { "frac34", 190 }, /* fraction three-quarters */
+ { "gt", 62 }, /* greater than */
+ { "iacute", 237 }, /* small i, acute accent */
+ { "icirc", 238 }, /* small i, circumflex accent */
+ { "iexcl", 161 }, /* inverted exclamation mark */
+ { "igrave", 236 }, /* small i, grave accent */
+ { "iquest", 191 }, /* inverted question mark */
+ { "iuml", 239 }, /* small i, dieresis or umlaut mark */
+ { "laquo", 171 }, /* angle quotation mark, left */
+ { "lt", 60 }, /* less than */
+ { "macr", 175 }, /* macron */
+ { "micro", 181 }, /* micro sign */
+ { "middot", 183 }, /* middle dot */
+ { "nbsp", 160 }, /* no-break space */
+ { "not", 172 }, /* not sign */
+ { "ntilde", 241 }, /* small n, tilde */
+ { "oacute", 243 }, /* small o, acute accent */
+ { "ocirc", 244 }, /* small o, circumflex accent */
+ { "ograve", 242 }, /* small o, grave accent */
+ { "ordf", 170 }, /* ordinal indicator, feminine */
+ { "ordm", 186 }, /* ordinal indicator, masculine */
+ { "oslash", 248 }, /* small o, slash */
+ { "otilde", 245 }, /* small o, tilde */
+ { "ouml", 246 }, /* small o, dieresis or umlaut mark */
+ { "para", 182 }, /* pilcrow (paragraph sign) */
+ { "plusmn", 177 }, /* plus-or-minus sign */
+ { "pound", 163 }, /* pound sterling sign */
+ { "quot", 34 }, /* double quote */
+ { "raquo", 187 }, /* angle quotation mark, right */
+ { "reg", 174 }, /* registered sign */
+ { "sect", 167 }, /* section sign */
+ { "shy", 173 }, /* soft hyphen */
+ { "sup1", 185 }, /* superscript one */
+ { "sup2", 178 }, /* superscript two */
+ { "sup3", 179 }, /* superscript three */
+ { "szlig", 223 }, /* small sharp s, German (sz ligature) */
+ { "thorn", 254 }, /* small thorn, Icelandic */
+ { "times", 215 }, /* multiply sign */
+ { "uacute", 250 }, /* small u, acute accent */
+ { "ucirc", 251 }, /* small u, circumflex accent */
+ { "ugrave", 249 }, /* small u, grave accent */
+ { "uml", 168 }, /* umlaut (dieresis) */
+ { "uuml", 252 }, /* small u, dieresis or umlaut mark */
+ { "yacute", 253 }, /* small y, acute accent */
+ { "yen", 165 }, /* yen sign */
+ { "yuml", 255 }, /* small y, dieresis or umlaut mark */
+};
+
+/*
+ * unvis - decode characters previously encoded by vis
+ */
+int
+unvis(char *cp, int c, int *astate, int flag)
+{
+ unsigned char uc = (unsigned char)c;
+ unsigned char st, ia, is, lc;
+
+/*
+ * Bottom 8 bits of astate hold the state machine state.
+ * Top 8 bits hold the current character in the http 1866 nv string decoding
+ */
+#define GS(a) ((a) & 0xff)
+#define SS(a, b) (((uint32_t)(a) << 24) | (b))
+#define GI(a) ((uint32_t)(a) >> 24)
+
+ _DIAGASSERT(cp != NULL);
+ _DIAGASSERT(astate != NULL);
+ st = GS(*astate);
+
+ if (flag & UNVIS_END) {
+ switch (st) {
+ case S_OCTAL2:
+ case S_OCTAL3:
+ case S_HEX2:
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case S_GROUND:
+ return UNVIS_NOCHAR;
+ default:
+ return UNVIS_SYNBAD;
+ }
+ }
+
+ switch (st) {
+
+ case S_GROUND:
+ *cp = 0;
+ if ((flag & VIS_NOESCAPE) == 0 && c == '\\') {
+ *astate = SS(0, S_START);
+ return UNVIS_NOCHAR;
+ }
+ if ((flag & VIS_HTTP1808) && c == '%') {
+ *astate = SS(0, S_HEX1);
+ return UNVIS_NOCHAR;
+ }
+ if ((flag & VIS_HTTP1866) && c == '&') {
+ *astate = SS(0, S_AMP);
+ return UNVIS_NOCHAR;
+ }
+ if ((flag & VIS_MIMESTYLE) && c == '=') {
+ *astate = SS(0, S_MIME1);
+ return UNVIS_NOCHAR;
+ }
+ *cp = c;
+ return UNVIS_VALID;
+
+ case S_START:
+ switch(c) {
+ case '\\':
+ *cp = c;
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ *cp = (c - '0');
+ *astate = SS(0, S_OCTAL2);
+ return UNVIS_NOCHAR;
+ case 'M':
+ *cp = (char)0200;
+ *astate = SS(0, S_META);
+ return UNVIS_NOCHAR;
+ case '^':
+ *astate = SS(0, S_CTRL);
+ return UNVIS_NOCHAR;
+ case 'n':
+ *cp = '\n';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 'r':
+ *cp = '\r';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 'b':
+ *cp = '\b';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 'a':
+ *cp = '\007';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 'v':
+ *cp = '\v';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 't':
+ *cp = '\t';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 'f':
+ *cp = '\f';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 's':
+ *cp = ' ';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 'E':
+ *cp = '\033';
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ case 'x':
+ *astate = SS(0, S_HEX);
+ return UNVIS_NOCHAR;
+ case '\n':
+ /*
+ * hidden newline
+ */
+ *astate = SS(0, S_GROUND);
+ return UNVIS_NOCHAR;
+ case '$':
+ /*
+ * hidden marker
+ */
+ *astate = SS(0, S_GROUND);
+ return UNVIS_NOCHAR;
+ default:
+ if (isgraph(c)) {
+ *cp = c;
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ }
+ }
+ goto bad;
+
+ case S_META:
+ if (c == '-')
+ *astate = SS(0, S_META1);
+ else if (c == '^')
+ *astate = SS(0, S_CTRL);
+ else
+ goto bad;
+ return UNVIS_NOCHAR;
+
+ case S_META1:
+ *astate = SS(0, S_GROUND);
+ *cp |= c;
+ return UNVIS_VALID;
+
+ case S_CTRL:
+ if (c == '?')
+ *cp |= 0177;
+ else
+ *cp |= c & 037;
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+
+ case S_OCTAL2: /* second possible octal digit */
+ if (isoctal(uc)) {
+ /*
+ * yes - and maybe a third
+ */
+ *cp = (*cp << 3) + (c - '0');
+ *astate = SS(0, S_OCTAL3);
+ return UNVIS_NOCHAR;
+ }
+ /*
+ * no - done with current sequence, push back passed char
+ */
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALIDPUSH;
+
+ case S_OCTAL3: /* third possible octal digit */
+ *astate = SS(0, S_GROUND);
+ if (isoctal(uc)) {
+ *cp = (*cp << 3) + (c - '0');
+ return UNVIS_VALID;
+ }
+ /*
+ * we were done, push back passed char
+ */
+ return UNVIS_VALIDPUSH;
+
+ case S_HEX:
+ if (!isxdigit(uc))
+ goto bad;
+ /*FALLTHROUGH*/
+ case S_HEX1:
+ if (isxdigit(uc)) {
+ *cp = xtod(uc);
+ *astate = SS(0, S_HEX2);
+ return UNVIS_NOCHAR;
+ }
+ /*
+ * no - done with current sequence, push back passed char
+ */
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALIDPUSH;
+
+ case S_HEX2:
+ *astate = S_GROUND;
+ if (isxdigit(uc)) {
+ *cp = xtod(uc) | (*cp << 4);
+ return UNVIS_VALID;
+ }
+ return UNVIS_VALIDPUSH;
+
+ case S_MIME1:
+ if (uc == '\n' || uc == '\r') {
+ *astate = SS(0, S_EATCRNL);
+ return UNVIS_NOCHAR;
+ }
+ if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) {
+ *cp = XTOD(uc);
+ *astate = SS(0, S_MIME2);
+ return UNVIS_NOCHAR;
+ }
+ goto bad;
+
+ case S_MIME2:
+ if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) {
+ *astate = SS(0, S_GROUND);
+ *cp = XTOD(uc) | (*cp << 4);
+ return UNVIS_VALID;
+ }
+ goto bad;
+
+ case S_EATCRNL:
+ switch (uc) {
+ case '\r':
+ case '\n':
+ return UNVIS_NOCHAR;
+ case '=':
+ *astate = SS(0, S_MIME1);
+ return UNVIS_NOCHAR;
+ default:
+ *cp = uc;
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+ }
+
+ case S_AMP:
+ *cp = 0;
+ if (uc == '#') {
+ *astate = SS(0, S_NUMBER);
+ return UNVIS_NOCHAR;
+ }
+ *astate = SS(0, S_STRING);
+ /*FALLTHROUGH*/
+
+ case S_STRING:
+ ia = *cp; /* index in the array */
+ is = GI(*astate); /* index in the string */
+ lc = is == 0 ? 0 : nv[ia].name[is - 1]; /* last character */
+
+ if (uc == ';')
+ uc = '\0';
+
+ for (; ia < __arraycount(nv); ia++) {
+ if (is != 0 && nv[ia].name[is - 1] != lc)
+ goto bad;
+ if (nv[ia].name[is] == uc)
+ break;
+ }
+
+ if (ia == __arraycount(nv))
+ goto bad;
+
+ if (uc != 0) {
+ *cp = ia;
+ *astate = SS(is + 1, S_STRING);
+ return UNVIS_NOCHAR;
+ }
+
+ *cp = nv[ia].value;
+ *astate = SS(0, S_GROUND);
+ return UNVIS_VALID;
+
+ case S_NUMBER:
+ if (uc == ';')
+ return UNVIS_VALID;
+ if (!isdigit(uc))
+ goto bad;
+ *cp += (*cp * 10) + uc - '0';
+ return UNVIS_NOCHAR;
+
+ default:
+ bad:
+ /*
+ * decoder in unknown state - (probably uninitialized)
+ */
+ *astate = SS(0, S_GROUND);
+ return UNVIS_SYNBAD;
+ }
+}
+
+/*
+ * strnunvisx - decode src into dst
+ *
+ * Number of chars decoded into dst is returned, -1 on error.
+ * Dst is null terminated.
+ */
+
+int
+strnunvisx(char *dst, size_t dlen, const char *src, int flag)
+{
+ char c;
+ char t = '\0', *start = dst;
+ int state = 0;
+
+ _DIAGASSERT(src != NULL);
+ _DIAGASSERT(dst != NULL);
+#define CHECKSPACE() \
+ do { \
+ if (dlen-- == 0) { \
+ errno = ENOSPC; \
+ return -1; \
+ } \
+ } while (/*CONSTCOND*/0)
+
+ while ((c = *src++) != '\0') {
+ again:
+ switch (unvis(&t, c, &state, flag)) {
+ case UNVIS_VALID:
+ CHECKSPACE();
+ *dst++ = t;
+ break;
+ case UNVIS_VALIDPUSH:
+ CHECKSPACE();
+ *dst++ = t;
+ goto again;
+ case 0:
+ case UNVIS_NOCHAR:
+ break;
+ case UNVIS_SYNBAD:
+ errno = EINVAL;
+ return -1;
+ default:
+ _DIAGASSERT(/*CONSTCOND*/0);
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ if (unvis(&t, c, &state, UNVIS_END) == UNVIS_VALID) {
+ CHECKSPACE();
+ *dst++ = t;
+ }
+ CHECKSPACE();
+ *dst = '\0';
+ return (int)(dst - start);
+}
+
+int
+strunvisx(char *dst, const char *src, int flag)
+{
+ return strnunvisx(dst, (size_t)~0, src, flag);
+}
+
+int
+strunvis(char *dst, const char *src)
+{
+ return strnunvisx(dst, (size_t)~0, src, 0);
+}
+
+int
+strnunvis(char *dst, size_t dlen, const char *src)
+{
+ return strnunvisx(dst, dlen, src, 0);
+}
+#endif
diff --git a/third_party/heimdal/lib/libedit/src/vi.c b/third_party/heimdal/lib/libedit/src/vi.c
new file mode 100644
index 0000000..0c37bfb
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/vi.c
@@ -0,0 +1,1157 @@
+/* $NetBSD: vi.c,v 1.62 2016/05/09 21:46:56 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if !defined(lint) && !defined(SCCSID)
+#if 0
+static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: vi.c,v 1.62 2016/05/09 21:46:56 christos Exp $");
+#endif
+#endif /* not lint && not SCCSID */
+
+/*
+ * vi.c: Vi mode commands.
+ */
+#include <sys/wait.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "el.h"
+#include "common.h"
+#include "emacs.h"
+#include "fcns.h"
+#include "vi.h"
+
+static el_action_t cv_action(EditLine *, wint_t);
+static el_action_t cv_paste(EditLine *, wint_t);
+
+/* cv_action():
+ * Handle vi actions.
+ */
+static el_action_t
+cv_action(EditLine *el, wint_t c)
+{
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ /* 'cc', 'dd' and (possibly) friends */
+ if (c != (wint_t)el->el_chared.c_vcmd.action)
+ return CC_ERROR;
+
+ if (!(c & YANK))
+ cv_undo(el);
+ cv_yank(el, el->el_line.buffer,
+ (int)(el->el_line.lastchar - el->el_line.buffer));
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_vcmd.pos = 0;
+ if (!(c & YANK)) {
+ el->el_line.lastchar = el->el_line.buffer;
+ el->el_line.cursor = el->el_line.buffer;
+ }
+ if (c & INSERT)
+ el->el_map.current = el->el_map.key;
+
+ return CC_REFRESH;
+ }
+ el->el_chared.c_vcmd.pos = el->el_line.cursor;
+ el->el_chared.c_vcmd.action = c;
+ return CC_ARGHACK;
+}
+
+/* cv_paste():
+ * Paste previous deletion before or after the cursor
+ */
+static el_action_t
+cv_paste(EditLine *el, wint_t c)
+{
+ c_kill_t *k = &el->el_chared.c_kill;
+ size_t len = (size_t)(k->last - k->buf);
+
+ if (k->buf == NULL || len == 0)
+ return CC_ERROR;
+#ifdef DEBUG_PASTE
+ (void) fprintf(el->el_errfile, "Paste: \"%.*ls\"\n", (int)len,
+ k->buf);
+#endif
+
+ cv_undo(el);
+
+ if (!c && el->el_line.cursor < el->el_line.lastchar)
+ el->el_line.cursor++;
+
+ c_insert(el, (int)len);
+ if (el->el_line.cursor + len > el->el_line.lastchar)
+ return CC_ERROR;
+ (void) memcpy(el->el_line.cursor, k->buf, len *
+ sizeof(*el->el_line.cursor));
+
+ return CC_REFRESH;
+}
+
+
+/* vi_paste_next():
+ * Vi paste previous deletion to the right of the cursor
+ * [p]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_paste_next(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ return cv_paste(el, 0);
+}
+
+
+/* vi_paste_prev():
+ * Vi paste previous deletion to the left of the cursor
+ * [P]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_paste_prev(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ return cv_paste(el, 1);
+}
+
+
+/* vi_prev_big_word():
+ * Vi move to the previous space delimited word
+ * [B]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_prev_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return CC_ERROR;
+
+ el->el_line.cursor = cv_prev_word(el->el_line.cursor,
+ el->el_line.buffer,
+ el->el_state.argument,
+ cv__isWord);
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* vi_prev_word():
+ * Vi move to the previous word
+ * [b]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return CC_ERROR;
+
+ el->el_line.cursor = cv_prev_word(el->el_line.cursor,
+ el->el_line.buffer,
+ el->el_state.argument,
+ cv__isword);
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* vi_next_big_word():
+ * Vi move to the next space delimited word
+ * [W]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_next_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor >= el->el_line.lastchar - 1)
+ return CC_ERROR;
+
+ el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
+ el->el_line.lastchar, el->el_state.argument, cv__isWord);
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* vi_next_word():
+ * Vi move to the next word
+ * [w]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor >= el->el_line.lastchar - 1)
+ return CC_ERROR;
+
+ el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
+ el->el_line.lastchar, el->el_state.argument, cv__isword);
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* vi_change_case():
+ * Vi change case of character under the cursor and advance one character
+ * [~]
+ */
+libedit_private el_action_t
+vi_change_case(EditLine *el, wint_t c)
+{
+ int i;
+
+ if (el->el_line.cursor >= el->el_line.lastchar)
+ return CC_ERROR;
+ cv_undo(el);
+ for (i = 0; i < el->el_state.argument; i++) {
+
+ c = *el->el_line.cursor;
+ if (iswupper(c))
+ *el->el_line.cursor = towlower(c);
+ else if (iswlower(c))
+ *el->el_line.cursor = towupper(c);
+
+ if (++el->el_line.cursor >= el->el_line.lastchar) {
+ el->el_line.cursor--;
+ re_fastaddc(el);
+ break;
+ }
+ re_fastaddc(el);
+ }
+ return CC_NORM;
+}
+
+
+/* vi_change_meta():
+ * Vi change prefix command
+ * [c]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_change_meta(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ /*
+ * Delete with insert == change: first we delete and then we leave in
+ * insert mode.
+ */
+ return cv_action(el, DELETE | INSERT);
+}
+
+
+/* vi_insert_at_bol():
+ * Vi enter insert mode at the beginning of line
+ * [I]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_insert_at_bol(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_line.cursor = el->el_line.buffer;
+ cv_undo(el);
+ el->el_map.current = el->el_map.key;
+ return CC_CURSOR;
+}
+
+
+/* vi_replace_char():
+ * Vi replace character under the cursor with the next character typed
+ * [r]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_replace_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor >= el->el_line.lastchar)
+ return CC_ERROR;
+
+ el->el_map.current = el->el_map.key;
+ el->el_state.inputmode = MODE_REPLACE_1;
+ cv_undo(el);
+ return CC_ARGHACK;
+}
+
+
+/* vi_replace_mode():
+ * Vi enter replace mode
+ * [R]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_replace_mode(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_map.current = el->el_map.key;
+ el->el_state.inputmode = MODE_REPLACE;
+ cv_undo(el);
+ return CC_NORM;
+}
+
+
+/* vi_substitute_char():
+ * Vi replace character under the cursor and enter insert mode
+ * [s]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_substitute_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ c_delafter(el, el->el_state.argument);
+ el->el_map.current = el->el_map.key;
+ return CC_REFRESH;
+}
+
+
+/* vi_substitute_line():
+ * Vi substitute entire line
+ * [S]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_substitute_line(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ cv_undo(el);
+ cv_yank(el, el->el_line.buffer,
+ (int)(el->el_line.lastchar - el->el_line.buffer));
+ (void) em_kill_line(el, 0);
+ el->el_map.current = el->el_map.key;
+ return CC_REFRESH;
+}
+
+
+/* vi_change_to_eol():
+ * Vi change to end of line
+ * [C]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_change_to_eol(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ cv_undo(el);
+ cv_yank(el, el->el_line.cursor,
+ (int)(el->el_line.lastchar - el->el_line.cursor));
+ (void) ed_kill_line(el, 0);
+ el->el_map.current = el->el_map.key;
+ return CC_REFRESH;
+}
+
+
+/* vi_insert():
+ * Vi enter insert mode
+ * [i]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_insert(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_map.current = el->el_map.key;
+ cv_undo(el);
+ return CC_NORM;
+}
+
+
+/* vi_add():
+ * Vi enter insert mode after the cursor
+ * [a]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_add(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ int ret;
+
+ el->el_map.current = el->el_map.key;
+ if (el->el_line.cursor < el->el_line.lastchar) {
+ el->el_line.cursor++;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ ret = CC_CURSOR;
+ } else
+ ret = CC_NORM;
+
+ cv_undo(el);
+
+ return (el_action_t)ret;
+}
+
+
+/* vi_add_at_eol():
+ * Vi enter insert mode at end of line
+ * [A]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_add_at_eol(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_map.current = el->el_map.key;
+ el->el_line.cursor = el->el_line.lastchar;
+ cv_undo(el);
+ return CC_CURSOR;
+}
+
+
+/* vi_delete_meta():
+ * Vi delete prefix command
+ * [d]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_delete_meta(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ return cv_action(el, DELETE);
+}
+
+
+/* vi_end_big_word():
+ * Vi move to the end of the current space delimited word
+ * [E]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_end_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor == el->el_line.lastchar)
+ return CC_ERROR;
+
+ el->el_line.cursor = cv__endword(el->el_line.cursor,
+ el->el_line.lastchar, el->el_state.argument, cv__isWord);
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ el->el_line.cursor++;
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* vi_end_word():
+ * Vi move to the end of the current word
+ * [e]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_end_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor == el->el_line.lastchar)
+ return CC_ERROR;
+
+ el->el_line.cursor = cv__endword(el->el_line.cursor,
+ el->el_line.lastchar, el->el_state.argument, cv__isword);
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ el->el_line.cursor++;
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* vi_undo():
+ * Vi undo last change
+ * [u]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_undo(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ c_undo_t un = el->el_chared.c_undo;
+
+ if (un.len == -1)
+ return CC_ERROR;
+
+ /* switch line buffer and undo buffer */
+ el->el_chared.c_undo.buf = el->el_line.buffer;
+ el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
+ el->el_chared.c_undo.cursor =
+ (int)(el->el_line.cursor - el->el_line.buffer);
+ el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
+ el->el_line.buffer = un.buf;
+ el->el_line.cursor = un.buf + un.cursor;
+ el->el_line.lastchar = un.buf + un.len;
+
+ return CC_REFRESH;
+}
+
+
+/* vi_command_mode():
+ * Vi enter command mode (use alternative key bindings)
+ * [<ESC>]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_command_mode(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ /* [Esc] cancels pending action */
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_vcmd.pos = 0;
+
+ el->el_state.doingarg = 0;
+
+ el->el_state.inputmode = MODE_INSERT;
+ el->el_map.current = el->el_map.alt;
+#ifdef VI_MOVE
+ if (el->el_line.cursor > el->el_line.buffer)
+ el->el_line.cursor--;
+#endif
+ return CC_CURSOR;
+}
+
+
+/* vi_zero():
+ * Vi move to the beginning of line
+ * [0]
+ */
+libedit_private el_action_t
+vi_zero(EditLine *el, wint_t c)
+{
+
+ if (el->el_state.doingarg)
+ return ed_argument_digit(el, c);
+
+ el->el_line.cursor = el->el_line.buffer;
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+
+/* vi_delete_prev_char():
+ * Vi move to previous character (backspace)
+ * [^H] in insert mode only
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_line.cursor <= el->el_line.buffer)
+ return CC_ERROR;
+
+ c_delbefore1(el);
+ el->el_line.cursor--;
+ return CC_REFRESH;
+}
+
+
+/* vi_list_or_eof():
+ * Vi list choices for completion or indicate end of file if empty line
+ * [^D]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_list_or_eof(EditLine *el, wint_t c)
+{
+
+ if (el->el_line.cursor == el->el_line.lastchar) {
+ if (el->el_line.cursor == el->el_line.buffer) {
+ terminal_writec(el, c); /* then do a EOF */
+ return CC_EOF;
+ } else {
+ /*
+ * Here we could list completions, but it is an
+ * error right now
+ */
+ terminal_beep(el);
+ return CC_ERROR;
+ }
+ } else {
+#ifdef notyet
+ re_goto_bottom(el);
+ *el->el_line.lastchar = '\0'; /* just in case */
+ return CC_LIST_CHOICES;
+#else
+ /*
+ * Just complain for now.
+ */
+ terminal_beep(el);
+ return CC_ERROR;
+#endif
+ }
+}
+
+
+/* vi_kill_line_prev():
+ * Vi cut from beginning of line to cursor
+ * [^U]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_kill_line_prev(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ wchar_t *kp, *cp;
+
+ cp = el->el_line.buffer;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.cursor)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer));
+ el->el_line.cursor = el->el_line.buffer; /* zap! */
+ return CC_REFRESH;
+}
+
+
+/* vi_search_prev():
+ * Vi search history previous
+ * [?]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ return cv_search(el, ED_SEARCH_PREV_HISTORY);
+}
+
+
+/* vi_search_next():
+ * Vi search history next
+ * [/]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ return cv_search(el, ED_SEARCH_NEXT_HISTORY);
+}
+
+
+/* vi_repeat_search_next():
+ * Vi repeat current search in the same search direction
+ * [n]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_repeat_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_search.patlen == 0)
+ return CC_ERROR;
+ else
+ return cv_repeat_srch(el, el->el_search.patdir);
+}
+
+
+/* vi_repeat_search_prev():
+ * Vi repeat current search in the opposite search direction
+ * [N]
+ */
+/*ARGSUSED*/
+libedit_private el_action_t
+vi_repeat_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ if (el->el_search.patlen == 0)
+ return CC_ERROR;
+ else
+ return (cv_repeat_srch(el,
+ el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
+ ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY));
+}
+
+
+/* vi_next_char():
+ * Vi move to the character specified next
+ * [f]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
+}
+
+
+/* vi_prev_char():
+ * Vi move to the character specified previous
+ * [F]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
+}
+
+
+/* vi_to_next_char():
+ * Vi move up to the character specified next
+ * [t]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_to_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
+}
+
+
+/* vi_to_prev_char():
+ * Vi move up to the character specified previous
+ * [T]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_to_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
+}
+
+
+/* vi_repeat_next_char():
+ * Vi repeat current character search in the same search direction
+ * [;]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_repeat_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
+ el->el_state.argument, el->el_search.chatflg);
+}
+
+
+/* vi_repeat_prev_char():
+ * Vi repeat current character search in the opposite search direction
+ * [,]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_repeat_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ el_action_t r;
+ int dir = el->el_search.chadir;
+
+ r = cv_csearch(el, -dir, el->el_search.chacha,
+ el->el_state.argument, el->el_search.chatflg);
+ el->el_search.chadir = dir;
+ return r;
+}
+
+
+/* vi_match():
+ * Vi go to matching () {} or []
+ * [%]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_match(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ const wchar_t match_chars[] = L"()[]{}";
+ wchar_t *cp;
+ size_t delta, i, count;
+ wchar_t o_ch, c_ch;
+
+ *el->el_line.lastchar = '\0'; /* just in case */
+
+ i = wcscspn(el->el_line.cursor, match_chars);
+ o_ch = el->el_line.cursor[i];
+ if (o_ch == 0)
+ return CC_ERROR;
+ delta = (size_t)(wcschr(match_chars, o_ch) - match_chars);
+ c_ch = match_chars[delta ^ 1];
+ count = 1;
+ delta = 1 - (delta & 1) * 2;
+
+ for (cp = &el->el_line.cursor[i]; count; ) {
+ cp += delta;
+ if (cp < el->el_line.buffer || cp >= el->el_line.lastchar)
+ return CC_ERROR;
+ if (*cp == o_ch)
+ count++;
+ else if (*cp == c_ch)
+ count--;
+ }
+
+ el->el_line.cursor = cp;
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ /* NB posix says char under cursor should NOT be deleted
+ for -ve delta - this is different to netbsd vi. */
+ if (delta > 0)
+ el->el_line.cursor++;
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
+
+/* vi_undo_line():
+ * Vi undo all changes to line
+ * [U]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_undo_line(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ cv_undo(el);
+ return hist_get(el);
+}
+
+/* vi_to_column():
+ * Vi go to specified column
+ * [|]
+ * NB netbsd vi goes to screen column 'n', posix says nth character
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_to_column(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_line.cursor = el->el_line.buffer;
+ el->el_state.argument--;
+ return ed_next_char(el, 0);
+}
+
+/* vi_yank_end():
+ * Vi yank to end of line
+ * [Y]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_yank_end(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ cv_yank(el, el->el_line.cursor,
+ (int)(el->el_line.lastchar - el->el_line.cursor));
+ return CC_REFRESH;
+}
+
+/* vi_yank():
+ * Vi yank
+ * [y]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_yank(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ return cv_action(el, YANK);
+}
+
+/* vi_comment_out():
+ * Vi comment out current command
+ * [#]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_comment_out(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+
+ el->el_line.cursor = el->el_line.buffer;
+ c_insert(el, 1);
+ *el->el_line.cursor = '#';
+ re_refresh(el);
+ return ed_newline(el, 0);
+}
+
+/* vi_alias():
+ * Vi include shell alias
+ * [@]
+ * NB: posix implies that we should enter insert mode, however
+ * this is against historical precedent...
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_alias(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ char alias_name[3];
+ const char *alias_text;
+
+ if (el->el_chared.c_aliasfun == NULL)
+ return CC_ERROR;
+
+ alias_name[0] = '_';
+ alias_name[2] = 0;
+ if (el_getc(el, &alias_name[1]) != 1)
+ return CC_ERROR;
+
+ alias_text = (*el->el_chared.c_aliasfun)(el->el_chared.c_aliasarg,
+ alias_name);
+ if (alias_text != NULL)
+ el_wpush(el, ct_decode_string(alias_text, &el->el_scratch));
+ return CC_NORM;
+}
+
+/* vi_to_history_line():
+ * Vi go to specified history file line.
+ * [G]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_to_history_line(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ int sv_event_no = el->el_history.eventno;
+ el_action_t rval;
+
+
+ if (el->el_history.eventno == 0) {
+ (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
+ EL_BUFSIZ);
+ el->el_history.last = el->el_history.buf +
+ (el->el_line.lastchar - el->el_line.buffer);
+ }
+
+ /* Lack of a 'count' means oldest, not 1 */
+ if (!el->el_state.doingarg) {
+ el->el_history.eventno = 0x7fffffff;
+ hist_get(el);
+ } else {
+ /* This is brain dead, all the rest of this code counts
+ * upwards going into the past. Here we need count in the
+ * other direction (to match the output of fc -l).
+ * I could change the world, but this seems to suffice.
+ */
+ el->el_history.eventno = 1;
+ if (hist_get(el) == CC_ERROR)
+ return CC_ERROR;
+ el->el_history.eventno = 1 + el->el_history.ev.num
+ - el->el_state.argument;
+ if (el->el_history.eventno < 0) {
+ el->el_history.eventno = sv_event_no;
+ return CC_ERROR;
+ }
+ }
+ rval = hist_get(el);
+ if (rval == CC_ERROR)
+ el->el_history.eventno = sv_event_no;
+ return rval;
+}
+
+/* vi_histedit():
+ * Vi edit history line with vi
+ * [v]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_histedit(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ int fd;
+ pid_t pid;
+ ssize_t st;
+ int status;
+ char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
+ char *cp = NULL;
+ size_t len;
+ wchar_t *line = NULL;
+
+ if (el->el_state.doingarg) {
+ if (vi_to_history_line(el, 0) == CC_ERROR)
+ return CC_ERROR;
+ }
+
+ fd = mkstemp(tempfile);
+ if (fd < 0)
+ return CC_ERROR;
+ len = (size_t)(el->el_line.lastchar - el->el_line.buffer);
+#define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX)
+ cp = el_malloc(TMP_BUFSIZ * sizeof(*cp));
+ if (cp == NULL)
+ goto error;
+ line = el_malloc(len * sizeof(*line) + 1);
+ if (line == NULL)
+ goto error;
+ wcsncpy(line, el->el_line.buffer, len);
+ line[len] = '\0';
+ wcstombs(cp, line, TMP_BUFSIZ - 1);
+ cp[TMP_BUFSIZ - 1] = '\0';
+ len = strlen(cp);
+ write(fd, cp, len);
+ write(fd, "\n", (size_t)1);
+ pid = fork();
+ switch (pid) {
+ case -1:
+ goto error;
+ case 0:
+ close(fd);
+ execlp("vi", "vi", tempfile, (char *)NULL);
+ exit(0);
+ /*NOTREACHED*/
+ default:
+ while (waitpid(pid, &status, 0) != pid)
+ continue;
+ lseek(fd, (off_t)0, SEEK_SET);
+ st = read(fd, cp, TMP_BUFSIZ - 1);
+ if (st > 0) {
+ cp[st] = '\0';
+ len = (size_t)(el->el_line.limit - el->el_line.buffer);
+ len = mbstowcs(el->el_line.buffer, cp, len);
+ if (len > 0 && el->el_line.buffer[len - 1] == '\n')
+ --len;
+ }
+ else
+ len = 0;
+ el->el_line.cursor = el->el_line.buffer;
+ el->el_line.lastchar = el->el_line.buffer + len;
+ el_free(cp);
+ el_free(line);
+ break;
+ }
+
+ close(fd);
+ unlink(tempfile);
+ /* return CC_REFRESH; */
+ return ed_newline(el, 0);
+error:
+ el_free(line);
+ el_free(cp);
+ close(fd);
+ unlink(tempfile);
+ return CC_ERROR;
+}
+
+/* vi_history_word():
+ * Vi append word from previous input line
+ * [_]
+ * Who knows where this one came from!
+ * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_history_word(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ const wchar_t *wp = HIST_FIRST(el);
+ const wchar_t *wep, *wsp;
+ int len;
+ wchar_t *cp;
+ const wchar_t *lim;
+
+ if (wp == NULL)
+ return CC_ERROR;
+
+ wep = wsp = NULL;
+ do {
+ while (iswspace(*wp))
+ wp++;
+ if (*wp == 0)
+ break;
+ wsp = wp;
+ while (*wp && !iswspace(*wp))
+ wp++;
+ wep = wp;
+ } while ((!el->el_state.doingarg || --el->el_state.argument > 0)
+ && *wp != 0);
+
+ if (wsp == NULL || (el->el_state.doingarg && el->el_state.argument != 0))
+ return CC_ERROR;
+
+ cv_undo(el);
+ len = (int)(wep - wsp);
+ if (el->el_line.cursor < el->el_line.lastchar)
+ el->el_line.cursor++;
+ c_insert(el, len + 1);
+ cp = el->el_line.cursor;
+ lim = el->el_line.limit;
+ if (cp < lim)
+ *cp++ = ' ';
+ while (wsp < wep && cp < lim)
+ *cp++ = *wsp++;
+ el->el_line.cursor = cp;
+
+ el->el_map.current = el->el_map.key;
+ return CC_REFRESH;
+}
+
+/* vi_redo():
+ * Vi redo last non-motion command
+ * [.]
+ */
+libedit_private el_action_t
+/*ARGSUSED*/
+vi_redo(EditLine *el, wint_t c __attribute__((__unused__)))
+{
+ c_redo_t *r = &el->el_chared.c_redo;
+
+ if (!el->el_state.doingarg && r->count) {
+ el->el_state.doingarg = 1;
+ el->el_state.argument = r->count;
+ }
+
+ el->el_chared.c_vcmd.pos = el->el_line.cursor;
+ el->el_chared.c_vcmd.action = r->action;
+ if (r->pos != r->buf) {
+ if (r->pos + 1 > r->lim)
+ /* sanity */
+ r->pos = r->lim - 1;
+ r->pos[0] = 0;
+ el_wpush(el, r->buf);
+ }
+
+ el->el_state.thiscmd = r->cmd;
+ el->el_state.thisch = r->ch;
+ return (*el->el_map.func[r->cmd])(el, r->ch);
+}
diff --git a/third_party/heimdal/lib/libedit/src/vis.c b/third_party/heimdal/lib/libedit/src/vis.c
new file mode 100644
index 0000000..1071803
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/vis.c
@@ -0,0 +1,728 @@
+/* $NetBSD: vis.c,v 1.71 2016/01/14 20:41:23 christos Exp $ */
+
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: vis.c,v 1.71 2016/01/14 20:41:23 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <assert.h>
+#include <vis.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#if !HAVE_VIS || !HAVE_SVIS
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * The reason for going through the trouble to deal with character encodings
+ * in vis(3), is that we use this to safe encode output of commands. This
+ * safe encoding varies depending on the character set. For example if we
+ * display ps output in French, we don't want to display French characters
+ * as M-foo.
+ */
+
+static wchar_t *do_svis(wchar_t *, wint_t, int, wint_t, const wchar_t *);
+
+#undef BELL
+#define BELL L'\a'
+
+#if defined(LC_C_LOCALE)
+#define iscgraph(c) isgraph_l(c, LC_C_LOCALE)
+#else
+/* Keep it simple for now, no locale stuff */
+#define iscgraph(c) isgraph(c)
+#ifdef notyet
+#include <locale.h>
+static int
+iscgraph(int c) {
+ int rv;
+ char *ol;
+
+ ol = setlocale(LC_CTYPE, "C");
+ rv = isgraph(c);
+ if (ol)
+ setlocale(LC_CTYPE, ol);
+ return rv;
+}
+#endif
+#endif
+
+#define ISGRAPH(flags, c) \
+ (((flags) & VIS_NOLOCALE) ? iscgraph(c) : iswgraph(c))
+
+#define iswoctal(c) (((u_char)(c)) >= L'0' && ((u_char)(c)) <= L'7')
+#define iswwhite(c) (c == L' ' || c == L'\t' || c == L'\n')
+#define iswsafe(c) (c == L'\b' || c == BELL || c == L'\r')
+#define xtoa(c) L"0123456789abcdef"[c]
+#define XTOA(c) L"0123456789ABCDEF"[c]
+
+#define MAXEXTRAS 30
+
+static const wchar_t char_shell[] = L"'`\";&<>()|{}]\\$!^~";
+static const wchar_t char_glob[] = L"*?[#";
+
+/*
+ * This is do_hvis, for HTTP style (RFC 1808)
+ */
+static wchar_t *
+do_hvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
+{
+ if (iswalnum(c)
+ /* safe */
+ || c == L'$' || c == L'-' || c == L'_' || c == L'.' || c == L'+'
+ /* extra */
+ || c == L'!' || c == L'*' || c == L'\'' || c == L'(' || c == L')'
+ || c == L',')
+ dst = do_svis(dst, c, flags, nextc, extra);
+ else {
+ *dst++ = L'%';
+ *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
+ *dst++ = xtoa((unsigned int)c & 0xf);
+ }
+
+ return dst;
+}
+
+/*
+ * This is do_mvis, for Quoted-Printable MIME (RFC 2045)
+ * NB: No handling of long lines or CRLF.
+ */
+static wchar_t *
+do_mvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
+{
+ if ((c != L'\n') &&
+ /* Space at the end of the line */
+ ((iswspace(c) && (nextc == L'\r' || nextc == L'\n')) ||
+ /* Out of range */
+ (!iswspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
+ /* Specific char to be escaped */
+ wcschr(L"#$@[\\]^`{|}~", c) != NULL)) {
+ *dst++ = L'=';
+ *dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
+ *dst++ = XTOA((unsigned int)c & 0xf);
+ } else
+ dst = do_svis(dst, c, flags, nextc, extra);
+ return dst;
+}
+
+/*
+ * Output single byte of multibyte character.
+ */
+static wchar_t *
+do_mbyte(wchar_t *dst, wint_t c, int flags, wint_t nextc, int iswextra)
+{
+ if (flags & VIS_CSTYLE) {
+ switch (c) {
+ case L'\n':
+ *dst++ = L'\\'; *dst++ = L'n';
+ return dst;
+ case L'\r':
+ *dst++ = L'\\'; *dst++ = L'r';
+ return dst;
+ case L'\b':
+ *dst++ = L'\\'; *dst++ = L'b';
+ return dst;
+ case BELL:
+ *dst++ = L'\\'; *dst++ = L'a';
+ return dst;
+ case L'\v':
+ *dst++ = L'\\'; *dst++ = L'v';
+ return dst;
+ case L'\t':
+ *dst++ = L'\\'; *dst++ = L't';
+ return dst;
+ case L'\f':
+ *dst++ = L'\\'; *dst++ = L'f';
+ return dst;
+ case L' ':
+ *dst++ = L'\\'; *dst++ = L's';
+ return dst;
+ case L'\0':
+ *dst++ = L'\\'; *dst++ = L'0';
+ if (iswoctal(nextc)) {
+ *dst++ = L'0';
+ *dst++ = L'0';
+ }
+ return dst;
+ /* We cannot encode these characters in VIS_CSTYLE
+ * because they special meaning */
+ case L'n':
+ case L'r':
+ case L'b':
+ case L'a':
+ case L'v':
+ case L't':
+ case L'f':
+ case L's':
+ case L'0':
+ case L'M':
+ case L'^':
+ case L'$': /* vis(1) -l */
+ break;
+ default:
+ if (ISGRAPH(flags, c) && !iswoctal(c)) {
+ *dst++ = L'\\';
+ *dst++ = c;
+ return dst;
+ }
+ }
+ }
+ if (iswextra || ((c & 0177) == L' ') || (flags & VIS_OCTAL)) {
+ *dst++ = L'\\';
+ *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + L'0';
+ *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + L'0';
+ *dst++ = (c & 07) + L'0';
+ } else {
+ if ((flags & VIS_NOSLASH) == 0)
+ *dst++ = L'\\';
+
+ if (c & 0200) {
+ c &= 0177;
+ *dst++ = L'M';
+ }
+
+ if (iswcntrl(c)) {
+ *dst++ = L'^';
+ if (c == 0177)
+ *dst++ = L'?';
+ else
+ *dst++ = c + L'@';
+ } else {
+ *dst++ = L'-';
+ *dst++ = c;
+ }
+ }
+
+ return dst;
+}
+
+/*
+ * This is do_vis, the central code of vis.
+ * dst: Pointer to the destination buffer
+ * c: Character to encode
+ * flags: Flags word
+ * nextc: The character following 'c'
+ * extra: Pointer to the list of extra characters to be
+ * backslash-protected.
+ */
+static wchar_t *
+do_svis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
+{
+ int iswextra, i, shft;
+ uint64_t bmsk, wmsk;
+
+ iswextra = wcschr(extra, c) != NULL;
+ if (!iswextra && (ISGRAPH(flags, c) || iswwhite(c) ||
+ ((flags & VIS_SAFE) && iswsafe(c)))) {
+ *dst++ = c;
+ return dst;
+ }
+
+ /* See comment in istrsenvisx() output loop, below. */
+ wmsk = 0;
+ for (i = sizeof(wmsk) - 1; i >= 0; i--) {
+ shft = i * NBBY;
+ bmsk = (uint64_t)0xffLL << shft;
+ wmsk |= bmsk;
+ if ((c & wmsk) || i == 0)
+ dst = do_mbyte(dst, (wint_t)(
+ (uint64_t)(c & bmsk) >> shft),
+ flags, nextc, iswextra);
+ }
+
+ return dst;
+}
+
+typedef wchar_t *(*visfun_t)(wchar_t *, wint_t, int, wint_t, const wchar_t *);
+
+/*
+ * Return the appropriate encoding function depending on the flags given.
+ */
+static visfun_t
+getvisfun(int flags)
+{
+ if (flags & VIS_HTTPSTYLE)
+ return do_hvis;
+ if (flags & VIS_MIMESTYLE)
+ return do_mvis;
+ return do_svis;
+}
+
+/*
+ * Expand list of extra characters to not visually encode.
+ */
+static wchar_t *
+makeextralist(int flags, const char *src)
+{
+ wchar_t *dst, *d;
+ size_t len;
+ const wchar_t *s;
+
+ len = strlen(src);
+ if ((dst = calloc(len + MAXEXTRAS, sizeof(*dst))) == NULL)
+ return NULL;
+
+ if ((flags & VIS_NOLOCALE) || mbstowcs(dst, src, len) == (size_t)-1) {
+ size_t i;
+ for (i = 0; i < len; i++)
+ dst[i] = (wchar_t)(u_char)src[i];
+ d = dst + len;
+ } else
+ d = dst + wcslen(dst);
+
+ if (flags & VIS_GLOB)
+ for (s = char_glob; *s; *d++ = *s++)
+ continue;
+
+ if (flags & VIS_SHELL)
+ for (s = char_shell; *s; *d++ = *s++)
+ continue;
+
+ if (flags & VIS_SP) *d++ = L' ';
+ if (flags & VIS_TAB) *d++ = L'\t';
+ if (flags & VIS_NL) *d++ = L'\n';
+ if ((flags & VIS_NOSLASH) == 0) *d++ = L'\\';
+ *d = L'\0';
+
+ return dst;
+}
+
+/*
+ * istrsenvisx()
+ * The main internal function.
+ * All user-visible functions call this one.
+ */
+static int
+istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,
+ int flags, const char *mbextra, int *cerr_ptr)
+{
+ wchar_t *dst, *src, *pdst, *psrc, *start, *extra;
+ size_t len, olen;
+ uint64_t bmsk, wmsk;
+ wint_t c;
+ visfun_t f;
+ int clen = 0, cerr, error = -1, i, shft;
+ char *mbdst, *mdst;
+ ssize_t mbslength, maxolen;
+
+ _DIAGASSERT(mbdstp != NULL);
+ _DIAGASSERT(mbsrc != NULL || mblength == 0);
+ _DIAGASSERT(mbextra != NULL);
+
+ /*
+ * Input (mbsrc) is a char string considered to be multibyte
+ * characters. The input loop will read this string pulling
+ * one character, possibly multiple bytes, from mbsrc and
+ * converting each to wchar_t in src.
+ *
+ * The vis conversion will be done using the wide char
+ * wchar_t string.
+ *
+ * This will then be converted back to a multibyte string to
+ * return to the caller.
+ */
+
+ /* Allocate space for the wide char strings */
+ psrc = pdst = extra = NULL;
+ mdst = NULL;
+ if ((psrc = calloc(mblength + 1, sizeof(*psrc))) == NULL)
+ return -1;
+ if ((pdst = calloc((4 * mblength) + 1, sizeof(*pdst))) == NULL)
+ goto out;
+ if (*mbdstp == NULL) {
+ if ((mdst = calloc((4 * mblength) + 1, sizeof(*mdst))) == NULL)
+ goto out;
+ *mbdstp = mdst;
+ }
+
+ mbdst = *mbdstp;
+ dst = pdst;
+ src = psrc;
+
+ if (flags & VIS_NOLOCALE) {
+ /* Do one byte at a time conversion */
+ cerr = 1;
+ } else {
+ /* Use caller's multibyte conversion error flag. */
+ cerr = cerr_ptr ? *cerr_ptr : 0;
+ }
+
+ /*
+ * Input loop.
+ * Handle up to mblength characters (not bytes). We do not
+ * stop at NULs because we may be processing a block of data
+ * that includes NULs.
+ */
+ mbslength = (ssize_t)mblength;
+ /*
+ * When inputing a single character, must also read in the
+ * next character for nextc, the look-ahead character.
+ */
+ if (mbslength == 1)
+ mbslength++;
+ while (mbslength > 0) {
+ /* Convert one multibyte character to wchar_t. */
+ if (!cerr)
+ clen = mbtowc(src, mbsrc, MB_LEN_MAX);
+ if (cerr || clen < 0) {
+ /* Conversion error, process as a byte instead. */
+ *src = (wint_t)(u_char)*mbsrc;
+ clen = 1;
+ cerr = 1;
+ }
+ if (clen == 0)
+ /*
+ * NUL in input gives 0 return value. process
+ * as single NUL byte and keep going.
+ */
+ clen = 1;
+ /* Advance buffer character pointer. */
+ src++;
+ /* Advance input pointer by number of bytes read. */
+ mbsrc += clen;
+ /* Decrement input byte count. */
+ mbslength -= clen;
+ }
+ len = src - psrc;
+ src = psrc;
+ /*
+ * In the single character input case, we will have actually
+ * processed two characters, c and nextc. Reset len back to
+ * just a single character.
+ */
+ if (mblength < len)
+ len = mblength;
+
+ /* Convert extra argument to list of characters for this mode. */
+ extra = makeextralist(flags, mbextra);
+ if (!extra) {
+ if (dlen && *dlen == 0) {
+ errno = ENOSPC;
+ goto out;
+ }
+ *mbdst = '\0'; /* can't create extra, return "" */
+ error = 0;
+ goto out;
+ }
+
+ /* Look up which processing function to call. */
+ f = getvisfun(flags);
+
+ /*
+ * Main processing loop.
+ * Call do_Xvis processing function one character at a time
+ * with next character available for look-ahead.
+ */
+ for (start = dst; len > 0; len--) {
+ c = *src++;
+ dst = (*f)(dst, c, flags, len >= 1 ? *src : L'\0', extra);
+ if (dst == NULL) {
+ errno = ENOSPC;
+ goto out;
+ }
+ }
+
+ /* Terminate the string in the buffer. */
+ *dst = L'\0';
+
+ /*
+ * Output loop.
+ * Convert wchar_t string back to multibyte output string.
+ * If we have hit a multi-byte conversion error on input,
+ * output byte-by-byte here. Else use wctomb().
+ */
+ len = wcslen(start);
+ maxolen = dlen ? *dlen : (wcslen(start) * MB_LEN_MAX + 1);
+ olen = 0;
+ for (dst = start; len > 0; len--) {
+ if (!cerr)
+ clen = wctomb(mbdst, *dst);
+ if (cerr || clen < 0) {
+ /*
+ * Conversion error, process as a byte(s) instead.
+ * Examine each byte and higher-order bytes for
+ * data. E.g.,
+ * 0x000000000000a264 -> a2 64
+ * 0x000000001f00a264 -> 1f 00 a2 64
+ */
+ clen = 0;
+ wmsk = 0;
+ for (i = sizeof(wmsk) - 1; i >= 0; i--) {
+ shft = i * NBBY;
+ bmsk = (uint64_t)0xffLL << shft;
+ wmsk |= bmsk;
+ if ((*dst & wmsk) || i == 0)
+ mbdst[clen++] = (char)(
+ (uint64_t)(*dst & bmsk) >>
+ shft);
+ }
+ cerr = 1;
+ }
+ /* If this character would exceed our output limit, stop. */
+ if (olen + clen > (size_t)maxolen)
+ break;
+ /* Advance output pointer by number of bytes written. */
+ mbdst += clen;
+ /* Advance buffer character pointer. */
+ dst++;
+ /* Incrment output character count. */
+ olen += clen;
+ }
+
+ /* Terminate the output string. */
+ *mbdst = '\0';
+
+ if (flags & VIS_NOLOCALE) {
+ /* Pass conversion error flag out. */
+ if (cerr_ptr)
+ *cerr_ptr = cerr;
+ }
+
+ free(extra);
+ free(pdst);
+ free(psrc);
+
+ return (int)olen;
+out:
+ free(extra);
+ free(pdst);
+ free(psrc);
+ free(mdst);
+ return error;
+}
+
+static int
+istrsenvisxl(char **mbdstp, size_t *dlen, const char *mbsrc,
+ int flags, const char *mbextra, int *cerr_ptr)
+{
+ return istrsenvisx(mbdstp, dlen, mbsrc,
+ mbsrc != NULL ? strlen(mbsrc) : 0, flags, mbextra, cerr_ptr);
+}
+
+#endif
+
+#if !HAVE_SVIS
+/*
+ * The "svis" variants all take an "extra" arg that is a pointer
+ * to a NUL-terminated list of characters to be encoded, too.
+ * These functions are useful e. g. to encode strings in such a
+ * way so that they are not interpreted by a shell.
+ */
+
+char *
+svis(char *mbdst, int c, int flags, int nextc, const char *mbextra)
+{
+ char cc[2];
+ int ret;
+
+ cc[0] = c;
+ cc[1] = nextc;
+
+ ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, mbextra, NULL);
+ if (ret < 0)
+ return NULL;
+ return mbdst + ret;
+}
+
+char *
+snvis(char *mbdst, size_t dlen, int c, int flags, int nextc, const char *mbextra)
+{
+ char cc[2];
+ int ret;
+
+ cc[0] = c;
+ cc[1] = nextc;
+
+ ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, mbextra, NULL);
+ if (ret < 0)
+ return NULL;
+ return mbdst + ret;
+}
+
+int
+strsvis(char *mbdst, const char *mbsrc, int flags, const char *mbextra)
+{
+ return istrsenvisxl(&mbdst, NULL, mbsrc, flags, mbextra, NULL);
+}
+
+int
+strsnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags, const char *mbextra)
+{
+ return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, mbextra, NULL);
+}
+
+int
+strsvisx(char *mbdst, const char *mbsrc, size_t len, int flags, const char *mbextra)
+{
+ return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, mbextra, NULL);
+}
+
+int
+strsnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
+ const char *mbextra)
+{
+ return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, NULL);
+}
+
+int
+strsenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
+ const char *mbextra, int *cerr_ptr)
+{
+ return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, cerr_ptr);
+}
+#endif
+
+#if !HAVE_VIS
+/*
+ * vis - visually encode characters
+ */
+char *
+vis(char *mbdst, int c, int flags, int nextc)
+{
+ char cc[2];
+ int ret;
+
+ cc[0] = c;
+ cc[1] = nextc;
+
+ ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, "", NULL);
+ if (ret < 0)
+ return NULL;
+ return mbdst + ret;
+}
+
+char *
+nvis(char *mbdst, size_t dlen, int c, int flags, int nextc)
+{
+ char cc[2];
+ int ret;
+
+ cc[0] = c;
+ cc[1] = nextc;
+
+ ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, "", NULL);
+ if (ret < 0)
+ return NULL;
+ return mbdst + ret;
+}
+
+/*
+ * strvis - visually encode characters from src into dst
+ *
+ * Dst must be 4 times the size of src to account for possible
+ * expansion. The length of dst, not including the trailing NULL,
+ * is returned.
+ */
+
+int
+strvis(char *mbdst, const char *mbsrc, int flags)
+{
+ return istrsenvisxl(&mbdst, NULL, mbsrc, flags, "", NULL);
+}
+
+int
+strnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags)
+{
+ return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, "", NULL);
+}
+
+int
+stravis(char **mbdstp, const char *mbsrc, int flags)
+{
+ *mbdstp = NULL;
+ return istrsenvisxl(mbdstp, NULL, mbsrc, flags, "", NULL);
+}
+
+/*
+ * strvisx - visually encode characters from src into dst
+ *
+ * Dst must be 4 times the size of src to account for possible
+ * expansion. The length of dst, not including the trailing NULL,
+ * is returned.
+ *
+ * Strvisx encodes exactly len characters from src into dst.
+ * This is useful for encoding a block of data.
+ */
+
+int
+strvisx(char *mbdst, const char *mbsrc, size_t len, int flags)
+{
+ return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, "", NULL);
+}
+
+int
+strnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags)
+{
+ return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", NULL);
+}
+
+int
+strenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
+ int *cerr_ptr)
+{
+ return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", cerr_ptr);
+}
+#endif
diff --git a/third_party/heimdal/lib/libedit/src/vis.h b/third_party/heimdal/lib/libedit/src/vis.h
new file mode 100644
index 0000000..ddd597b
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/vis.h
@@ -0,0 +1,120 @@
+/* $NetBSD: vis.h,v 1.24 2016/01/14 20:42:14 christos Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vis.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _VIS_H_
+#define _VIS_H_
+
+#include <sys/types.h>
+
+/*
+ * to select alternate encoding format
+ */
+#define VIS_OCTAL 0x0001 /* use octal \ddd format */
+#define VIS_CSTYLE 0x0002 /* use \[nrft0..] where appropiate */
+
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define VIS_SP 0x0004 /* also encode space */
+#define VIS_TAB 0x0008 /* also encode tab */
+#define VIS_NL 0x0010 /* also encode newline */
+#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
+#define VIS_SAFE 0x0020 /* only encode "unsafe" characters */
+
+/*
+ * other
+ */
+#define VIS_NOSLASH 0x0040 /* inhibit printing '\' */
+#define VIS_HTTP1808 0x0080 /* http-style escape % hex hex */
+#define VIS_HTTPSTYLE 0x0080 /* http-style escape % hex hex */
+#define VIS_MIMESTYLE 0x0100 /* mime-style escape = HEX HEX */
+#define VIS_HTTP1866 0x0200 /* http-style &#num; or &string; */
+#define VIS_NOESCAPE 0x0400 /* don't decode `\' */
+#define _VIS_END 0x0800 /* for unvis */
+#define VIS_GLOB 0x1000 /* encode glob(3) magic characters */
+#define VIS_SHELL 0x2000 /* encode shell special characters [not glob] */
+#define VIS_META (VIS_WHITE | VIS_GLOB | VIS_SHELL)
+#define VIS_NOLOCALE 0x4000 /* encode using the C locale */
+
+/*
+ * unvis return codes
+ */
+#define UNVIS_VALID 1 /* character valid */
+#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */
+#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */
+#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */
+#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */
+
+/*
+ * unvis flags
+ */
+#define UNVIS_END _VIS_END /* no more characters */
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+__BEGIN_DECLS
+char *vis(char *, int, int, int);
+char *nvis(char *, size_t, int, int, int);
+
+char *svis(char *, int, int, int, const char *);
+char *snvis(char *, size_t, int, int, int, const char *);
+
+int strvis(char *, const char *, int);
+int stravis(char **, const char *, int);
+int strnvis(char *, size_t, const char *, int);
+
+int strsvis(char *, const char *, int, const char *);
+int strsnvis(char *, size_t, const char *, int, const char *);
+
+int strvisx(char *, const char *, size_t, int);
+int strnvisx(char *, size_t, const char *, size_t, int);
+int strenvisx(char *, size_t, const char *, size_t, int, int *);
+
+int strsvisx(char *, const char *, size_t, int, const char *);
+int strsnvisx(char *, size_t, const char *, size_t, int, const char *);
+int strsenvisx(char *, size_t, const char *, size_t , int, const char *,
+ int *);
+
+int strunvis(char *, const char *);
+int strnunvis(char *, size_t, const char *);
+
+int strunvisx(char *, const char *, int);
+int strnunvisx(char *, size_t, const char *, int);
+
+int unvis(char *, int, int *, int);
+__END_DECLS
+
+#endif /* !_VIS_H_ */
diff --git a/third_party/heimdal/lib/libedit/src/wcsdup.c b/third_party/heimdal/lib/libedit/src/wcsdup.c
new file mode 100644
index 0000000..5cf7b59
--- /dev/null
+++ b/third_party/heimdal/lib/libedit/src/wcsdup.c
@@ -0,0 +1,43 @@
+/* $NetBSD: wcsdup.c,v 1.3 2008/05/26 13:17:48 haad Exp $ */
+
+/*
+ * Copyright (C) 2006 Aleksey Cheusov
+ *
+ * This material is provided "as is", with absolutely no warranty expressed
+ * or implied. Any use is at your own risk.
+ *
+ * Permission to use or copy this software for any purpose is hereby granted
+ * without fee. Permission to modify the code and to distribute modified
+ * code is also granted without any restrictions.
+ */
+
+#ifndef HAVE_WCSDUP
+
+#include "config.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcsdup.c,v 1.3 2008/05/26 13:17:48 haad Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <wchar.h>
+
+wchar_t *
+wcsdup(const wchar_t *str)
+{
+ wchar_t *copy;
+ size_t len;
+
+ _DIAGASSERT(str != NULL);
+
+ len = wcslen(str) + 1;
+ copy = malloc(len * sizeof (wchar_t));
+
+ if (!copy)
+ return NULL;
+
+ return wmemcpy(copy, str, len);
+}
+
+#endif