Import libedit 2019-09-10

Compared to current version in base:
- great improvements on the Unicode support
- full support for filename completion including quoting
  which means we do not need anymore our custom addition)
- Improved readline compatiblity

Upgrading libedit has been a pain in the past, because somehow we never
managed to properly cleanup the tree in lib/libedit and each merge has always
been very painful. After years of fighting give up and refresh a merge from
scrarch properly in contrib.

Note that the switch to this version will be done in another commit.
This commit is contained in:
Baptiste Daroussin 2019-09-10 14:30:10 +00:00
commit d0ef721ed3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=352136
57 changed files with 24699 additions and 0 deletions

139
contrib/libedit/Makefile Normal file
View file

@ -0,0 +1,139 @@
# $NetBSD: Makefile,v 1.65 2017/06/30 20:26:52 kre Exp $
# @(#)Makefile 8.1 (Berkeley) 6/4/93
USE_SHLIBDIR= yes
WARNS?= 5
LIB= edit
LIBDPLIBS+= terminfo ${.CURDIR}/../libterminfo
.include "bsd.own.mk"
COPTS+= -Wunused-parameter
CWARNFLAGS.gcc+= -Wconversion
CWARNFLAGS.clang+= -Wno-cast-qual
SRCS = chared.c chartype.c common.c el.c eln.c emacs.c filecomplete.c \
hist.c history.c historyn.c keymacro.c literal.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 vi.c
MAN= editline.3 editrc.5 editline.7
MLINKS= \
editline.3 el_deletestr.3 \
editline.3 el_end.3 \
editline.3 el_get.3 \
editline.3 el_getc.3 \
editline.3 el_gets.3 \
editline.3 el_init.3 \
editline.3 el_init_fd.3 \
editline.3 el_insertstr.3 \
editline.3 el_line.3 \
editline.3 el_parse.3 \
editline.3 el_push.3 \
editline.3 el_reset.3 \
editline.3 el_resize.3 \
editline.3 el_set.3 \
editline.3 el_source.3 \
editline.3 history.3 \
editline.3 history_end.3 \
editline.3 history_init.3 \
editline.3 tok_end.3 \
editline.3 tok_init.3 \
editline.3 tok_line.3 \
editline.3 tok_reset.3 \
editline.3 tok_str.3
MLINKS+= \
editline.3 el_wdeletestr.3 \
editline.3 el_wget.3 \
editline.3 el_wgetc.3 \
editline.3 el_wgets.3 \
editline.3 el_winsertstr.3 \
editline.3 el_wline.3 \
editline.3 el_wparse.3 \
editline.3 el_wpush.3 \
editline.3 el_wset.3 \
editline.3 history_w.3 \
editline.3 history_wend.3 \
editline.3 history_winit.3 \
editline.3 tok_wend.3 \
editline.3 tok_winit.3 \
editline.3 tok_wline.3 \
editline.3 tok_wreset.3 \
editline.3 tok_wstr.3
LIBEDITDIR?=${.CURDIR}
INCS= histedit.h
INCSDIR=/usr/include
CLEANFILES+=common.h.tmp emacs.h.tmp fcns.h.tmp func.h.tmp
CLEANFILES+=help.h.tmp vi.h.tmp tc1.o tc1 .depend
CPPFLAGS+=-I. -I${LIBEDITDIR}
CPPFLAGS+=-I. -I${.CURDIR}
#CPPFLAGS+=-DDEBUG_TTY -DDEBUG_KEY -DDEBUG -DDEBUG_REFRESH
#CPPFLAGS+=-DDEBUG_PASTE -DDEBUG_EDIT
AHDR=vi.h emacs.h common.h
ASRC=${LIBEDITDIR}/vi.c ${LIBEDITDIR}/emacs.c ${LIBEDITDIR}/common.c
DPSRCS+= ${AHDR} fcns.h func.h help.h
CLEANFILES+= ${AHDR} fcns.h func.h help.h
SUBDIR= readline
.depend: ${AHDR} fcns.h func.h help.h
vi.h: vi.c makelist Makefile
${_MKTARGET_CREATE}
${HOST_SH} ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/vi.c \
> ${.TARGET}.tmp && \
mv ${.TARGET}.tmp ${.TARGET}
emacs.h: emacs.c makelist Makefile
${_MKTARGET_CREATE}
${HOST_SH} ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/emacs.c \
> ${.TARGET}.tmp && \
mv ${.TARGET}.tmp ${.TARGET}
common.h: common.c makelist Makefile
${_MKTARGET_CREATE}
${HOST_SH} ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/common.c \
> ${.TARGET}.tmp && \
mv ${.TARGET}.tmp ${.TARGET}
fcns.h: ${AHDR} makelist Makefile
${_MKTARGET_CREATE}
${HOST_SH} ${LIBEDITDIR}/makelist -fh ${AHDR} > ${.TARGET}.tmp && \
mv ${.TARGET}.tmp ${.TARGET}
func.h: ${AHDR} makelist Makefile
${_MKTARGET_CREATE}
${HOST_SH} ${LIBEDITDIR}/makelist -fc ${AHDR} > ${.TARGET}.tmp && \
mv ${.TARGET}.tmp ${.TARGET}
help.h: ${ASRC} makelist Makefile
${_MKTARGET_CREATE}
${HOST_SH} ${LIBEDITDIR}/makelist -bh ${ASRC} > ${.TARGET}.tmp && \
mv ${.TARGET}.tmp ${.TARGET}
tc1.o: ${LIBEDITDIR}/TEST/tc1.c
tc1: libedit.a tc1.o
${_MKTARGET_LINK}
${CC} ${LDFLAGS} ${.ALLSRC} -o ${.TARGET} libedit.a ${LDADD} -ltermlib
.include <bsd.lib.mk>
.include <bsd.subdir.mk>
# XXX
.if defined(HAVE_GCC)
COPTS.editline.c+= -Wno-cast-qual
COPTS.literal.c+= -Wno-sign-conversion
COPTS.tokenizer.c+= -Wno-cast-qual
COPTS.tokenizern.c+= -Wno-cast-qual
.endif

View file

@ -0,0 +1,13 @@
# $NetBSD: Makefile,v 1.8 2017/10/15 18:59:00 abhinav Exp $
NOMAN=1
PROG=wtc1 test_filecompletion
CPPFLAGS=-I${.CURDIR}/..
LDADD+=-ledit -ltermlib
DPADD+=${LIBEDIT} ${LIBTERMLIB}
.ifdef DEBUG
CPPFLAGS+=-DDEBUG
.endif
.include <bsd.prog.mk>

View file

@ -0,0 +1,52 @@
/* $NetBSD: rl1.c,v 1.2 2016/02/29 00:54:19 christos Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: rl1.c,v 1.2 2016/02/29 00:54:19 christos Exp $");
#endif /* not lint */
/*
* test.c: A little test program
*/
#include <stdio.h>
#include <readline/readline.h>
int
main(int argc, char *argv[])
{
char *p;
while ((p = readline("hi$")) != NULL) {
add_history(p);
printf("%d %s\n", history_length, p);
}
return 0;
}

304
contrib/libedit/TEST/tc1.c Normal file
View file

@ -0,0 +1,304 @@
/* $NetBSD: tc1.c,v 1.7 2016/02/17 19:47:49 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"
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n");
#endif /* not lint */
#if !defined(lint) && !defined(SCCSID)
#if 0
static char sccsid[] = "@(#)test.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: tc1.c,v 1.7 2016/02/17 19:47:49 christos Exp $");
#endif
#endif /* not lint && not SCCSID */
/*
* test.c: A little test program
*/
#include <sys/wait.h>
#include <ctype.h>
#include <dirent.h>
#include <locale.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "histedit.h"
static int continuation = 0;
volatile sig_atomic_t gotsig = 0;
static unsigned char complete(EditLine *, int);
int main(int, char **);
static char *prompt(EditLine *);
static void sig(int);
static char *
prompt(EditLine *el)
{
static char a[] = "\1\033[7m\1Edit$\1\033[0m\1 ";
static char b[] = "Edit> ";
return (continuation ? b : a);
}
static void
sig(int i)
{
gotsig = i;
}
static unsigned char
complete(EditLine *el, int ch)
{
DIR *dd = opendir(".");
struct dirent *dp;
const char* ptr;
const LineInfo *lf = el_line(el);
int len;
int res = CC_ERROR;
/*
* Find the last word
*/
for (ptr = lf->cursor - 1;
!isspace((unsigned char)*ptr) && ptr > lf->buffer; ptr--)
continue;
len = lf->cursor - ++ptr;
for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
if (len > strlen(dp->d_name))
continue;
if (strncmp(dp->d_name, ptr, len) == 0) {
if (el_insertstr(el, &dp->d_name[len]) == -1)
res = CC_ERROR;
else
res = CC_REFRESH;
break;
}
}
closedir(dd);
return res;
}
int
main(int argc, char *argv[])
{
EditLine *el = NULL;
int num;
const char *buf;
Tokenizer *tok;
#if 0
int lastevent = 0;
#endif
int ncontinuation;
History *hist;
HistEvent ev;
(void) setlocale(LC_CTYPE, "");
(void) signal(SIGINT, sig);
(void) signal(SIGQUIT, sig);
(void) signal(SIGHUP, sig);
(void) signal(SIGTERM, sig);
hist = history_init(); /* Init the builtin history */
/* Remember 100 events */
history(hist, &ev, H_SETSIZE, 100);
tok = tok_init(NULL); /* Initialize the tokenizer */
/* Initialize editline */
el = el_init(*argv, stdin, stdout, stderr);
el_set(el, EL_EDITOR, "vi"); /* Default editor is vi */
el_set(el, EL_SIGNAL, 1); /* Handle signals gracefully */
el_set(el, EL_PROMPT_ESC, prompt, '\1');/* Set the prompt function */
/* Tell editline to use this history interface */
el_set(el, EL_HIST, history, hist);
/* Add a user-defined function */
el_set(el, EL_ADDFN, "ed-complete", "Complete argument", complete);
/* Bind tab to it */
el_set(el, EL_BIND, "^I", "ed-complete", NULL);
/*
* Bind j, k in vi command mode to previous and next line, instead
* of previous and next history.
*/
el_set(el, EL_BIND, "-a", "k", "ed-prev-line", NULL);
el_set(el, EL_BIND, "-a", "j", "ed-next-line", NULL);
/*
* Source the user's defaults file.
*/
el_source(el, NULL);
while ((buf = el_gets(el, &num)) != NULL && num != 0) {
int ac, cc, co;
#ifdef DEBUG
int i;
#endif
const char **av;
const LineInfo *li;
li = el_line(el);
#ifdef DEBUG
(void) fprintf(stderr, "==> got %d %s", num, buf);
(void) fprintf(stderr, " > li `%.*s_%.*s'\n",
(li->cursor - li->buffer), li->buffer,
(li->lastchar - 1 - li->cursor),
(li->cursor >= li->lastchar) ? "" : li->cursor);
#endif
if (gotsig) {
(void) fprintf(stderr, "Got signal %d.\n", (int)gotsig);
gotsig = 0;
el_reset(el);
}
if (!continuation && num == 1)
continue;
ac = cc = co = 0;
ncontinuation = tok_line(tok, li, &ac, &av, &cc, &co);
if (ncontinuation < 0) {
(void) fprintf(stderr, "Internal error\n");
continuation = 0;
continue;
}
#ifdef DEBUG
(void) fprintf(stderr, " > nc %d ac %d cc %d co %d\n",
ncontinuation, ac, cc, co);
#endif
#if 0
if (continuation) {
/*
* Append to the right event in case the user
* moved around in history.
*/
if (history(hist, &ev, H_SET, lastevent) == -1)
err(1, "%d: %s", lastevent, ev.str);
history(hist, &ev, H_ADD , buf);
} else {
history(hist, &ev, H_ENTER, buf);
lastevent = ev.num;
}
#else
/* Simpler */
history(hist, &ev, continuation ? H_APPEND : H_ENTER, buf);
#endif
continuation = ncontinuation;
ncontinuation = 0;
if (continuation)
continue;
#ifdef DEBUG
for (i = 0; i < ac; i++) {
(void) fprintf(stderr, " > arg# %2d ", i);
if (i != cc)
(void) fprintf(stderr, "`%s'\n", av[i]);
else
(void) fprintf(stderr, "`%.*s_%s'\n",
co, av[i], av[i] + co);
}
#endif
if (strcmp(av[0], "history") == 0) {
int rv;
switch (ac) {
case 1:
for (rv = history(hist, &ev, H_LAST); rv != -1;
rv = history(hist, &ev, H_PREV))
(void) fprintf(stdout, "%4d %s",
ev.num, ev.str);
break;
case 2:
if (strcmp(av[1], "clear") == 0)
history(hist, &ev, H_CLEAR);
else
goto badhist;
break;
case 3:
if (strcmp(av[1], "load") == 0)
history(hist, &ev, H_LOAD, av[2]);
else if (strcmp(av[1], "save") == 0)
history(hist, &ev, H_SAVE, av[2]);
break;
badhist:
default:
(void) fprintf(stderr,
"Bad history arguments\n");
break;
}
} else if (el_parse(el, ac, av) == -1) {
switch (fork()) {
case 0:
execvp(av[0], (char *const *)__UNCONST(av));
perror(av[0]);
_exit(1);
/*NOTREACHED*/
break;
case -1:
perror("fork");
break;
default:
if (wait(&num) == -1)
perror("wait");
(void) fprintf(stderr, "Exit %x\n", num);
break;
}
}
tok_reset(tok);
}
el_end(el);
tok_end(tok);
history_end(hist);
return (0);
}

View file

@ -0,0 +1,553 @@
/* $NetBSD: test_filecompletion.c,v 1.5 2019/09/08 05:50:58 abhinav Exp $ */
/*-
* Copyright (c) 2017 Abhinav Upadhyay <abhinav@NetBSD.org>
* 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 COPYRIGHT HOLDERS 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
* COPYRIGHT HOLDERS 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"
#include <assert.h>
#include <err.h>
#include <stdio.h>
#include <histedit.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "filecomplete.h"
#include "el.h"
typedef struct {
const wchar_t *user_typed_text; /* The actual text typed by the user on the terminal */
const char *completion_function_input ; /*the text received by fn_filename_completion_function */
const char *expanded_text[2]; /* the value to which completion_function_input should be expanded */
const wchar_t *escaped_output; /* expected escaped value of expanded_text */
} test_input;
static test_input inputs[] = {
{
/* simple test for escaping angular brackets */
L"ls ang",
"ang",
{"ang<ular>test", NULL},
L"ls ang\\<ular\\>test "
},
{
/* test angular bracket inside double quotes: ls "dq_ang */
L"ls \"dq_ang",
"dq_ang",
{"dq_ang<ular>test", NULL},
L"ls \"dq_ang<ular>test\""
},
{
/* test angular bracket inside singlq quotes: ls "sq_ang */
L"ls 'sq_ang",
"sq_ang",
{"sq_ang<ular>test", NULL},
L"ls 'sq_ang<ular>test'"
},
{
/* simple test for backslash */
L"ls back",
"back",
{"backslash\\test", NULL},
L"ls backslash\\\\test "
},
{
/* backslash inside single quotes */
L"ls 'sback",
"sback",
{"sbackslash\\test", NULL},
L"ls 'sbackslash\\test'"
},
{
/* backslash inside double quotes */
L"ls \"dback",
"dback",
{"dbackslash\\test", NULL},
L"ls \"dbackslash\\\\test\""
},
{
/* test braces */
L"ls br",
"br",
{"braces{test}", NULL},
L"ls braces\\{test\\} "
},
{
/* test braces inside single quotes */
L"ls 'sbr",
"sbr",
{"sbraces{test}", NULL},
L"ls 'sbraces{test}'"
},
{
/* test braces inside double quotes */
L"ls \"dbr",
"dbr",
{"dbraces{test}", NULL},
L"ls \"dbraces{test}\""
},
{
/* test dollar */
L"ls doll",
"doll",
{"doll$artest", NULL},
L"ls doll\\$artest "
},
{
/* test dollar inside single quotes */
L"ls 'sdoll",
"sdoll",
{"sdoll$artest", NULL},
L"ls 'sdoll$artest'"
},
{
/* test dollar inside double quotes */
L"ls \"ddoll",
"ddoll",
{"ddoll$artest", NULL},
L"ls \"ddoll\\$artest\""
},
{
/* test equals */
L"ls eq",
"eq",
{"equals==test", NULL},
L"ls equals\\=\\=test "
},
{
/* test equals inside sinqle quotes */
L"ls 'seq",
"seq",
{"sequals==test", NULL},
L"ls 'sequals==test'"
},
{
/* test equals inside double quotes */
L"ls \"deq",
"deq",
{"dequals==test", NULL},
L"ls \"dequals==test\""
},
{
/* test \n */
L"ls new",
"new",
{"new\\nline", NULL},
L"ls new\\\\nline "
},
{
/* test \n inside single quotes */
L"ls 'snew",
"snew",
{"snew\nline", NULL},
L"ls 'snew\nline'"
},
{
/* test \n inside double quotes */
L"ls \"dnew",
"dnew",
{"dnew\nline", NULL},
L"ls \"dnew\nline\""
},
{
/* test single space */
L"ls spac",
"spac",
{"space test", NULL},
L"ls space\\ test "
},
{
/* test single space inside singlq quotes */
L"ls 's_spac",
"s_spac",
{"s_space test", NULL},
L"ls 's_space test'"
},
{
/* test single space inside double quotes */
L"ls \"d_spac",
"d_spac",
{"d_space test", NULL},
L"ls \"d_space test\""
},
{
/* test multiple spaces */
L"ls multi",
"multi",
{"multi space test", NULL},
L"ls multi\\ space\\ \\ test "
},
{
/* test multiple spaces inside single quotes */
L"ls 's_multi",
"s_multi",
{"s_multi space test", NULL},
L"ls 's_multi space test'"
},
{
/* test multiple spaces inside double quotes */
L"ls \"d_multi",
"d_multi",
{"d_multi space test", NULL},
L"ls \"d_multi space test\""
},
{
/* test double quotes */
L"ls doub",
"doub",
{"doub\"quotes", NULL},
L"ls doub\\\"quotes "
},
{
/* test double quotes inside single quotes */
L"ls 's_doub",
"s_doub",
{"s_doub\"quotes", NULL},
L"ls 's_doub\"quotes'"
},
{
/* test double quotes inside double quotes */
L"ls \"d_doub",
"d_doub",
{"d_doub\"quotes", NULL},
L"ls \"d_doub\\\"quotes\""
},
{
/* test multiple double quotes */
L"ls mud",
"mud",
{"mud\"qu\"otes\"", NULL},
L"ls mud\\\"qu\\\"otes\\\" "
},
{
/* test multiple double quotes inside single quotes */
L"ls 'smud",
"smud",
{"smud\"qu\"otes\"", NULL},
L"ls 'smud\"qu\"otes\"'"
},
{
/* test multiple double quotes inside double quotes */
L"ls \"dmud",
"dmud",
{"dmud\"qu\"otes\"", NULL},
L"ls \"dmud\\\"qu\\\"otes\\\"\""
},
{
/* test one single quote */
L"ls sing",
"sing",
{"single'quote", NULL},
L"ls single\\'quote "
},
{
/* test one single quote inside single quote */
L"ls 'ssing",
"ssing",
{"ssingle'quote", NULL},
L"ls 'ssingle'\\''quote'"
},
{
/* test one single quote inside double quote */
L"ls \"dsing",
"dsing",
{"dsingle'quote", NULL},
L"ls \"dsingle'quote\""
},
{
/* test multiple single quotes */
L"ls mu_sing",
"mu_sing",
{"mu_single''quotes''", NULL},
L"ls mu_single\\'\\'quotes\\'\\' "
},
{
/* test multiple single quotes inside single quote */
L"ls 'smu_sing",
"smu_sing",
{"smu_single''quotes''", NULL},
L"ls 'smu_single'\\'''\\''quotes'\\\'''\\'''"
},
{
/* test multiple single quotes inside double quote */
L"ls \"dmu_sing",
"dmu_sing",
{"dmu_single''quotes''", NULL},
L"ls \"dmu_single''quotes''\""
},
{
/* test parenthesis */
L"ls paren",
"paren",
{"paren(test)", NULL},
L"ls paren\\(test\\) "
},
{
/* test parenthesis inside single quote */
L"ls 'sparen",
"sparen",
{"sparen(test)", NULL},
L"ls 'sparen(test)'"
},
{
/* test parenthesis inside double quote */
L"ls \"dparen",
"dparen",
{"dparen(test)", NULL},
L"ls \"dparen(test)\""
},
{
/* test pipe */
L"ls pip",
"pip",
{"pipe|test", NULL},
L"ls pipe\\|test "
},
{
/* test pipe inside single quote */
L"ls 'spip",
"spip",
{"spipe|test", NULL},
L"ls 'spipe|test'",
},
{
/* test pipe inside double quote */
L"ls \"dpip",
"dpip",
{"dpipe|test", NULL},
L"ls \"dpipe|test\""
},
{
/* test tab */
L"ls ta",
"ta",
{"tab\ttest", NULL},
L"ls tab\\\ttest "
},
{
/* test tab inside single quote */
L"ls 'sta",
"sta",
{"stab\ttest", NULL},
L"ls 'stab\ttest'"
},
{
/* test tab inside double quote */
L"ls \"dta",
"dta",
{"dtab\ttest", NULL},
L"ls \"dtab\ttest\""
},
{
/* test back tick */
L"ls tic",
"tic",
{"tick`test`", NULL},
L"ls tick\\`test\\` "
},
{
/* test back tick inside single quote */
L"ls 'stic",
"stic",
{"stick`test`", NULL},
L"ls 'stick`test`'"
},
{
/* test back tick inside double quote */
L"ls \"dtic",
"dtic",
{"dtick`test`", NULL},
L"ls \"dtick\\`test\\`\""
},
{
/* test for @ */
L"ls at",
"at",
{"atthe@rate", NULL},
L"ls atthe\\@rate "
},
{
/* test for @ inside single quote */
L"ls 'sat",
"sat",
{"satthe@rate", NULL},
L"ls 'satthe@rate'"
},
{
/* test for @ inside double quote */
L"ls \"dat",
"dat",
{"datthe@rate", NULL},
L"ls \"datthe@rate\""
},
{
/* test ; */
L"ls semi",
"semi",
{"semi;colon;test", NULL},
L"ls semi\\;colon\\;test "
},
{
/* test ; inside single quote */
L"ls 'ssemi",
"ssemi",
{"ssemi;colon;test", NULL},
L"ls 'ssemi;colon;test'"
},
{
/* test ; inside double quote */
L"ls \"dsemi",
"dsemi",
{"dsemi;colon;test", NULL},
L"ls \"dsemi;colon;test\""
},
{
/* test & */
L"ls amp",
"amp",
{"ampers&and", NULL},
L"ls ampers\\&and "
},
{
/* test & inside single quote */
L"ls 'samp",
"samp",
{"sampers&and", NULL},
L"ls 'sampers&and'"
},
{
/* test & inside double quote */
L"ls \"damp",
"damp",
{"dampers&and", NULL},
L"ls \"dampers&and\""
},
{
/* test completion when cursor at \ */
L"ls foo\\",
"foo",
{"foo bar", NULL},
L"ls foo\\ bar "
},
{
/* test completion when cursor at single quote */
L"ls foo'",
"foo'",
{"foo bar", NULL},
L"ls foo\\ bar "
},
{
/* test completion when cursor at double quote */
L"ls foo\"",
"foo\"",
{"foo bar", NULL},
L"ls foo\\ bar "
},
{
/* test multiple completion matches */
L"ls fo",
"fo",
{"foo bar", "foo baz"},
L"ls foo\\ ba"
},
{
L"ls ba",
"ba",
{"bar <bar>", "bar <baz>"},
L"ls bar\\ \\<ba"
}
};
static const wchar_t break_chars[] = L" \t\n\"\\'`@$><=;|&{(";
/*
* Custom completion function passed to fn_complet, NULLe.
* The function returns hardcoded completion matches
* based on the test cases present in inputs[] (above)
*/
static char *
mycomplet_func(const char *text, int index)
{
static int last_index = 0;
size_t i = 0;
if (last_index == 2) {
last_index = 0;
return NULL;
}
for (i = 0; i < sizeof(inputs)/sizeof(inputs[0]); i++) {
if (strcmp(text, inputs[i].completion_function_input) == 0) {
if (inputs[i].expanded_text[last_index] != NULL)
return strdup(inputs[i].expanded_text[last_index++]);
else {
last_index = 0;
return NULL;
}
}
}
return NULL;
}
int
main(int argc, char **argv)
{
EditLine *el = el_init(argv[0], stdin, stdout, stderr);
size_t i;
size_t input_len;
el_line_t line;
wchar_t *buffer = malloc(64 * sizeof(*buffer));
if (buffer == NULL)
err(EXIT_FAILURE, "malloc failed");
for (i = 0; i < sizeof(inputs)/sizeof(inputs[0]); i++) {
memset(buffer, 0, 64 * sizeof(*buffer));
input_len = wcslen(inputs[i].user_typed_text);
wmemcpy(buffer, inputs[i].user_typed_text, input_len);
buffer[input_len] = 0;
line.buffer = buffer;
line.cursor = line.buffer + input_len ;
line.lastchar = line.cursor - 1;
line.limit = line.buffer + 64 * sizeof(*buffer);
el->el_line = line;
fn_complete(el, mycomplet_func, NULL, break_chars, NULL, NULL, 10, NULL, NULL, NULL, NULL);
/*
* fn_complete would have expanded and escaped the input in el->el_line.buffer.
* We need to assert that it matches with the expected value in our test data
*/
printf("User input: %ls\t Expected output: %ls\t Generated output: %ls\n",
inputs[i].user_typed_text, inputs[i].escaped_output, el->el_line.buffer);
assert(wcscmp(el->el_line.buffer, inputs[i].escaped_output) == 0);
}
el_end(el);
return 0;
}

278
contrib/libedit/TEST/wtc1.c Normal file
View file

@ -0,0 +1,278 @@
#include <sys/wait.h>
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <limits.h>
#include <locale.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../histedit.h"
static int continuation;
volatile sig_atomic_t gotsig;
static const char hfile[] = ".whistory";
static wchar_t *
prompt(EditLine *el)
{
static wchar_t a[] = L"\1\033[7m\1Edit$\1\033[0m\1 ";
static wchar_t b[] = L"Edit> ";
return continuation ? b : a;
}
static void
sig(int i)
{
gotsig = i;
}
const char *
my_wcstombs(const wchar_t *wstr)
{
static struct {
char *str;
int len;
} buf;
int needed = wcstombs(0, wstr, 0) + 1;
if (needed > buf.len) {
buf.str = malloc(needed);
buf.len = needed;
}
wcstombs(buf.str, wstr, needed);
buf.str[needed - 1] = 0;
return buf.str;
}
static unsigned char
complete(EditLine *el, int ch)
{
DIR *dd = opendir(".");
struct dirent *dp;
const wchar_t *ptr;
char *buf, *bptr;
const LineInfoW *lf = el_wline(el);
int len, mblen, i;
unsigned char res = 0;
wchar_t dir[1024];
/* Find the last word */
for (ptr = lf->cursor -1; !iswspace(*ptr) && ptr > lf->buffer; --ptr)
continue;
len = lf->cursor - ++ptr;
/* Convert last word to multibyte encoding, so we can compare to it */
wctomb(NULL, 0); /* Reset shift state */
mblen = MB_LEN_MAX * len + 1;
buf = bptr = malloc(mblen);
if (buf == NULL)
err(1, "malloc");
for (i = 0; i < len; ++i) {
/* Note: really should test for -1 return from wctomb */
bptr += wctomb(bptr, ptr[i]);
}
*bptr = 0; /* Terminate multibyte string */
mblen = bptr - buf;
/* Scan directory for matching name */
for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
if (mblen > strlen(dp->d_name))
continue;
if (strncmp(dp->d_name, buf, mblen) == 0) {
mbstowcs(dir, &dp->d_name[mblen],
sizeof(dir) / sizeof(*dir));
if (el_winsertstr(el, dir) == -1)
res = CC_ERROR;
else
res = CC_REFRESH;
break;
}
}
closedir(dd);
free(buf);
return res;
}
int
main(int argc, char *argv[])
{
EditLine *el = NULL;
int numc, ncontinuation;
const wchar_t *line;
TokenizerW *tok;
HistoryW *hist;
HistEventW ev;
#ifdef DEBUG
int i;
#endif
setlocale(LC_ALL, "");
(void)signal(SIGINT, sig);
(void)signal(SIGQUIT, sig);
(void)signal(SIGHUP, sig);
(void)signal(SIGTERM, sig);
hist = history_winit(); /* Init built-in history */
history_w(hist, &ev, H_SETSIZE, 100); /* Remember 100 events */
history_w(hist, &ev, H_LOAD, hfile);
tok = tok_winit(NULL); /* Init the tokenizer */
el = el_init(argv[0], stdin, stdout, stderr);
el_wset(el, EL_EDITOR, L"vi"); /* Default editor is vi */
el_wset(el, EL_SIGNAL, 1); /* Handle signals gracefully */
el_wset(el, EL_PROMPT_ESC, prompt, '\1'); /* Set the prompt function */
el_wset(el, EL_HIST, history_w, hist); /* FIXME - history_w? */
/* Add a user-defined function */
el_wset(el, EL_ADDFN, L"ed-complete", L"Complete argument", complete);
/* Bind <tab> to it */
el_wset(el, EL_BIND, L"^I", L"ed-complete", NULL);
/*
* Bind j, k in vi command mode to previous and next line, instead
* of previous and next history.
*/
el_wset(el, EL_BIND, L"-a", L"k", L"ed-prev-line", NULL);
el_wset(el, EL_BIND, L"-a", L"j", L"ed-next-line", NULL);
/* Source the user's defaults file. */
el_source(el, NULL);
while((line = el_wgets(el, &numc)) != NULL && numc != 0) {
int ac, cc, co, rc;
const wchar_t **av;
const LineInfoW *li;
li = el_wline(el);
#ifdef DEBUG
(void)fwprintf(stderr, L"==> got %d %ls", numc, line);
(void)fwprintf(stderr, L" > li `%.*ls_%.*ls'\n",
(li->cursor - li->buffer), li->buffer,
(li->lastchar - 1 - li->cursor),
(li->cursor >= li->lastchar) ? L"" : li->cursor);
#endif
if (gotsig) {
(void)fprintf(stderr, "Got signal %d.\n", (int)gotsig);
gotsig = 0;
el_reset(el);
}
if(!continuation && numc == 1)
continue; /* Only got a linefeed */
ac = cc = co = 0;
ncontinuation = tok_wline(tok, li, &ac, &av, &cc, &co);
if (ncontinuation < 0) {
(void) fprintf(stderr, "Internal error\n");
continuation = 0;
continue;
}
#ifdef DEBUG
(void)fprintf(stderr, " > nc %d ac %d cc %d co %d\n",
ncontinuation, ac, cc, co);
#endif
history_w(hist, &ev, continuation ? H_APPEND : H_ENTER, line);
continuation = ncontinuation;
ncontinuation = 0;
if(continuation)
continue;
#ifdef DEBUG
for (i = 0; i < ac; ++i) {
(void)fwprintf(stderr, L" > arg# %2d ", i);
if (i != cc)
(void)fwprintf(stderr, L"`%ls'\n", av[i]);
else
(void)fwprintf(stderr, L"`%.*ls_%ls'\n",
co, av[i], av[i] + co);
}
#endif
if (wcscmp (av[0], L"history") == 0) {
switch(ac) {
case 1:
for(rc = history_w(hist, &ev, H_LAST);
rc != -1;
rc = history_w(hist, &ev, H_PREV))
(void)fwprintf(stdout, L"%4d %ls",
ev.num, ev.str);
break;
case 2:
if (wcscmp(av[1], L"clear") == 0)
history_w(hist, &ev, H_CLEAR);
else
goto badhist;
break;
case 3:
if (wcscmp(av[1], L"load") == 0)
history_w(hist, &ev, H_LOAD,
my_wcstombs(av[2]));
else if (wcscmp(av[1], L"save") == 0)
history_w(hist, &ev, H_SAVE,
my_wcstombs(av[2]));
else
goto badhist;
break;
badhist:
default:
(void)fprintf(stderr,
"Bad history arguments\n");
break;
}
} else if (el_wparse(el, ac, av) == -1) {
switch (fork()) {
case 0: {
Tokenizer *ntok = tok_init(NULL);
int nargc;
const char **nav;
tok_str(ntok, my_wcstombs(line), &nargc, &nav);
execvp(nav[0],(char **)nav);
perror(nav[0]);
_exit(1);
/* NOTREACHED */
break;
}
case -1:
perror("fork");
break;
default:
if (wait(&rc) == -1)
perror("wait");
(void)fprintf(stderr, "Exit %x\n", rc);
break;
}
}
tok_wreset(tok);
}
el_end(el);
tok_wend(tok);
history_w(hist, &ev, H_SAVE, hfile);
history_wend(hist);
fprintf(stdout, "\n");
return 0;
}

747
contrib/libedit/chared.c Normal file
View file

@ -0,0 +1,747 @@
/* $NetBSD: chared.c,v 1.59 2019/07/23 10:18:52 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.59 2019/07/23 10:18:52 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[num] <= 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_calloc(EL_BUFSIZ,
sizeof(*el->el_line.buffer));
if (el->el_line.buffer == NULL)
return -1;
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_calloc(EL_BUFSIZ,
sizeof(*el->el_chared.c_undo.buf));
if (el->el_chared.c_undo.buf == NULL)
return -1;
el->el_chared.c_undo.len = -1;
el->el_chared.c_undo.cursor = 0;
el->el_chared.c_redo.buf = el_calloc(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_calloc(EL_BUFSIZ,
sizeof(*el->el_chared.c_kill.buf));
if (el->el_chared.c_kill.buf == NULL)
return -1;
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 cursor
*/
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;
}

155
contrib/libedit/chared.h Normal file
View file

@ -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 */

339
contrib/libedit/chartype.c Normal file
View file

@ -0,0 +1,339 @@
/* $NetBSD: chartype.c,v 1.35 2019/07/23 10:18:52 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.35 2019/07/23 10:18:52 christos Exp $");
#endif /* not lint && not SCCSID */
#include <ctype.h>
#include <limits.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_calloc((size_t)(argc + 1), 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;
}
wargv[i] = NULL;
return wargv;
}
libedit_private size_t
ct_enc_width(wchar_t c)
{
mbstate_t mbs;
char buf[MB_LEN_MAX];
size_t size;
memset(&mbs, 0, sizeof(mbs));
if ((size = wcrtomb(buf, c, &mbs)) == (size_t)-1)
return 0;
return size;
}
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;
}

119
contrib/libedit/chartype.h Normal file
View file

@ -0,0 +1,119 @@
/* $NetBSD: chartype.h,v 1.35 2017/05/22 19:16:25 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__) && \
!defined(__DragonFly__)
#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 */

837
contrib/libedit/common.c Normal file
View file

@ -0,0 +1,837 @@
/* $NetBSD: common.c,v 1.48 2018/02/26 17:36:14 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.48 2018/02/26 17:36:14 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
/*ARGSUSED*/
ed_quoted_insert(EditLine *el, wint_t c __attribute__((__unused__)))
{
int num;
wchar_t ch;
tty_quotemode(el);
num = el_wgetc(el, &ch);
tty_noquotemode(el);
if (num == 1)
return ed_insert(el, ch);
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;
}

286
contrib/libedit/config.h Normal file
View file

@ -0,0 +1,286 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if the `closedir' function returns void instead of `int'. */
/* #undef CLOSEDIR_VOID */
/* Define to 1 if you have the <curses.h> header file. */
#define HAVE_CURSES_H 1
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#define HAVE_DIRENT_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the `endpwent' function. */
#define HAVE_ENDPWENT 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `getline' function. */
#define HAVE_GETLINE 1
/* Define to 1 if you have the `fork' function. */
#define HAVE_FORK 1
/* Define to 1 if you have getpwnam_r and getpwuid_r that are draft POSIX.1
versions. */
/* #undef HAVE_GETPW_R_DRAFT */
/* Define to 1 if you have getpwnam_r and getpwuid_r that are POSIX.1
compatible. */
#define HAVE_GETPW_R_POSIX 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `isascii' function. */
#define HAVE_ISASCII 1
/* Define to 1 if you have the `issetugid' function. */
#define HAVE_ISSETUGID 1
/* Define to 1 if you have the `curses' library (-lcurses). */
/* #undef HAVE_LIBCURSES */
/* Define to 1 if you have the `ncurses' library (-lncurses). */
/* #undef HAVE_LIBNCURSES */
/* Define to 1 if you have the `termcap' library (-ltermcap). */
/* #undef HAVE_LIBTERMCAP */
/* Define to 1 if you have the `terminfo' library (-lterminfo). */
#define HAVE_LIBTERMINFO 1
/* Define to 1 if you have the `termlib' library (-ltermlib). */
/* #undef HAVE_LIBTERMLIB */
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <malloc.h> header file. */
#define HAVE_MALLOC_H 1
/* Define to 1 if you have the `memchr' function. */
#define HAVE_MEMCHR 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the <ncurses.h> header file. */
/* #undef HAVE_NCURSES_H */
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
/* #undef HAVE_NDIR_H */
/* Define to 1 if you have the `regcomp' function. */
#define HAVE_REGCOMP 1
/* Define to 1 if you have the `re_comp' function. */
/* #undef HAVE_RE_COMP */
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strcasecmp' function. */
#define HAVE_STRCASECMP 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strcspn' function. */
#define HAVE_STRCSPN 1
/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strlcat' function. */
#define HAVE_STRLCAT 1
/* Define to 1 if you have the `strlcpy' function. */
#define HAVE_STRLCPY 1
/* Define to 1 if you have the `strrchr' function. */
#define HAVE_STRRCHR 1
/* Define to 1 if you have the `strstr' function. */
#define HAVE_STRSTR 1
/* Define to 1 if you have the `strtol' function. */
#define HAVE_STRTOL 1
/* Define to 1 if struct dirent has member d_namlen */
#define HAVE_STRUCT_DIRENT_D_NAMLEN 1
/* Define to 1 if you have the `strunvis' function. */
#define HAVE_STRUNVIS 1
/* Define to 1 if you have the `strvis' function. */
#define HAVE_STRVIS 1
/* Define to 1 if you have the <sys/cdefs.h> header file. */
#define HAVE_SYS_CDEFS_H 1
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_SYS_DIR_H */
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_SYS_NDIR_H */
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define to 1 if you have the <termcap.h> header file. */
#define HAVE_TERMCAP_H 1
/* Define to 1 if you have the <term.h> header file. */
#define HAVE_TERM_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if the system has the type `u_int32_t'. */
#define HAVE_U_INT32_T 1
/* Define to 1 if you have the `vfork' function. */
#define HAVE_VFORK 1
/* Define to 1 if you have the <vfork.h> header file. */
/* #undef HAVE_VFORK_H */
/* Define to 1 if you have the `vis' function. */
#define HAVE_VIS 1
/* Define to 1 if `fork' works. */
#define HAVE_WORKING_FORK 1
/* Define to 1 if `vfork' works. */
#define HAVE_WORKING_VFORK 1
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "libedit-20110729"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME "libedit"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libedit 3.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libedit-20110729"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "3.0"
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
/* Version number of package */
#define VERSION "3.0"
/* Define to 1 if the system provides the SIZE_MAX constant */
#define HAVE_SIZE_MAX 1
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef pid_t */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define as `fork' if `vfork' does not work. */
/* #undef vfork */
#include "sys.h"
/* #undef SCCSID */
/* #undef LIBC_SCCS */
/* #undef lint */

1006
contrib/libedit/editline.3 Normal file

File diff suppressed because it is too large Load diff

935
contrib/libedit/editline.7 Normal file
View file

@ -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 .

325
contrib/libedit/editrc.5 Normal file
View file

@ -0,0 +1,325 @@
.\" $NetBSD: editrc.5,v 1.33 2017/06/27 01:22:58 kre 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 ENVIRONMENT
.Bl -tag -width "~/.editrcXXX"
.It Ev EDITRC
Names the default configuration file for the
.Xr editline 3
library.
.El
.Sh FILES
.Bl -tag -width "~/.editrcXXX"
.It Pa ~/.editrc
Last resort, if no other file is specified,
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 .

645
contrib/libedit/el.c Normal file
View file

@ -0,0 +1,645 @@
/* $NetBSD: el.c,v 1.99 2019/07/23 10:18:52 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.99 2019/07/23 10:18:52 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));
}
libedit_private EditLine *
el_init_internal(const char *prog, FILE *fin, FILE *fout, FILE *ferr,
int fdin, int fdout, int fderr, int flags)
{
EditLine *el = el_calloc(1, sizeof(*el));
if (el == NULL)
return NULL;
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 = flags;
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);
(void) literal_init(el);
if (read_init(el) == -1) {
el_end(el);
return NULL;
}
return el;
}
EditLine *
el_init_fd(const char *prog, FILE *fin, FILE *fout, FILE *ferr,
int fdin, int fdout, int fderr)
{
return el_init_internal(prog, fin, fout, ferr, fdin, fdout, fderr, 0);
}
/* 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, TCSAFLUSH);
ch_end(el);
read_end(el->el_read);
search_end(el);
hist_end(el);
prompt_end(el);
sig_end(el);
literal_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 (MB_CUR_MAX == 1)
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[3];
argv[0] = name;
argv[1] = va_arg(ap, char *);
argv[2] = va_arg(ap, void *);
rv = terminal_gettc(el, 3, 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
if (issetugid())
return -1;
if ((fname = getenv("EDITRC")) == NULL) {
static const char elpath[] = "/.editrc";
size_t plen = sizeof(elpath);
if ((ptr = getenv("HOME")) == NULL)
return -1;
plen += strlen(ptr);
if ((path = el_calloc(plen, sizeof(*path))) == NULL)
return -1;
(void)snprintf(path, plen, "%s%s", ptr,
elpath + (*ptr == '\0'));
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 (fname[0] == '\0')
return -1;
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;
}

158
contrib/libedit/el.h Normal file
View file

@ -0,0 +1,158 @@
/* $NetBSD: el.h,v 1.45 2019/07/23 10:18:52 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 NARROW_HISTORY 0x40
#define NO_RESET 0x80
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_calloc(a,b) calloc(a, b)
#define el_realloc(a,b) realloc(a, b)
#define el_free(a) free(a)
#include "tty.h"
#include "prompt.h"
#include "literal.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 */
wint_t **el_display; /* Real screen image = what is there */
wint_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_literal_t el_literal; /* prompt literal bits */
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 **);
libedit_private EditLine *el_init_internal(const char *, FILE *, FILE *,
FILE *, int, int, int, int);
#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 */

386
contrib/libedit/eln.c Normal file
View file

@ -0,0 +1,386 @@
/* $NetBSD: eln.c,v 1.35 2019/04/26 16:56:57 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.35 2019/04/26 16:56:57 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[3];
static char gettc[] = "gettc";
argv[0] = gettc;
argv[1] = va_arg(ap, char *);
argv[2] = va_arg(ap, void *);
ret = terminal_gettc(el, 3, 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));
}

512
contrib/libedit/emacs.c Normal file
View file

@ -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;
}

View file

@ -0,0 +1,825 @@
/* $NetBSD: filecomplete.c,v 1.58 2019/09/08 05:50:58 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.58 2019/09/08 05:50:58 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_calloc(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_calloc(len, sizeof(*temp));
if (temp == NULL)
return NULL;
(void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt);
return temp;
}
static int
needs_escaping(char c)
{
switch (c) {
case '\'':
case '"':
case '(':
case ')':
case '\\':
case '<':
case '>':
case '$':
case '#':
case ' ':
case '\n':
case '\t':
case '?':
case ';':
case '`':
case '@':
case '=':
case '|':
case '{':
case '}':
case '&':
case '*':
case '[':
return 1;
default:
return 0;
}
}
static int
needs_dquote_escaping(char c)
{
switch (c) {
case '"':
case '\\':
case '`':
case '$':
return 1;
default:
return 0;
}
}
static wchar_t *
unescape_string(const wchar_t *string, size_t length)
{
size_t i;
size_t j = 0;
wchar_t *unescaped = el_calloc(length + 1, sizeof(*string));
if (unescaped == NULL)
return NULL;
for (i = 0; i < length ; i++) {
if (string[i] == '\\')
continue;
unescaped[j++] = string[i];
}
unescaped[j] = 0;
return unescaped;
}
static char *
escape_filename(EditLine * el, const char *filename, int single_match,
const char *(*app_func)(const char *))
{
size_t original_len = 0;
size_t escaped_character_count = 0;
size_t offset = 0;
size_t newlen;
const char *s;
char c;
size_t s_quoted = 0; /* does the input contain a single quote */
size_t d_quoted = 0; /* does the input contain a double quote */
char *escaped_str;
wchar_t *temp = el->el_line.buffer;
const char *append_char = NULL;
if (filename == NULL)
return NULL;
while (temp != el->el_line.cursor) {
/*
* If we see a single quote but have not seen a double quote
* so far set/unset s_quote
*/
if (temp[0] == '\'' && !d_quoted)
s_quoted = !s_quoted;
/*
* vice versa to the above condition
*/
else if (temp[0] == '"' && !s_quoted)
d_quoted = !d_quoted;
temp++;
}
/* Count number of special characters so that we can calculate
* number of extra bytes needed in the new string
*/
for (s = filename; *s; s++, original_len++) {
c = *s;
/* Inside a single quote only single quotes need escaping */
if (s_quoted && c == '\'') {
escaped_character_count += 3;
continue;
}
/* Inside double quotes only ", \, ` and $ need escaping */
if (d_quoted && needs_dquote_escaping(c)) {
escaped_character_count++;
continue;
}
if (!s_quoted && !d_quoted && needs_escaping(c))
escaped_character_count++;
}
newlen = original_len + escaped_character_count + 1;
if (s_quoted || d_quoted)
newlen++;
if (single_match && app_func)
newlen++;
if ((escaped_str = el_malloc(newlen)) == NULL)
return NULL;
for (s = filename; *s; s++) {
c = *s;
if (!needs_escaping(c)) {
/* no escaping is required continue as usual */
escaped_str[offset++] = c;
continue;
}
/* single quotes inside single quotes require special handling */
if (c == '\'' && s_quoted) {
escaped_str[offset++] = '\'';
escaped_str[offset++] = '\\';
escaped_str[offset++] = '\'';
escaped_str[offset++] = '\'';
continue;
}
/* Otherwise no escaping needed inside single quotes */
if (s_quoted) {
escaped_str[offset++] = c;
continue;
}
/* No escaping needed inside a double quoted string either
* unless we see a '$', '\', '`', or '"' (itself)
*/
if (d_quoted && !needs_dquote_escaping(c)) {
escaped_str[offset++] = c;
continue;
}
/* If we reach here that means escaping is actually needed */
escaped_str[offset++] = '\\';
escaped_str[offset++] = c;
}
if (single_match && app_func) {
escaped_str[offset] = 0;
append_char = app_func(escaped_str);
/* we want to append space only if we are not inside quotes */
if (append_char[0] == ' ') {
if (!s_quoted && !d_quoted)
escaped_str[offset++] = append_char[0];
} else
escaped_str[offset++] = append_char[0];
}
/* close the quotes if single match and the match is not a directory */
if (single_match && (append_char && append_char[0] == ' ')) {
if (s_quoted)
escaped_str[offset++] = '\'';
else if (d_quoted)
escaped_str[offset++] = '"';
}
escaped_str[offset] = 0;
return escaped_str;
}
/*
* 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_calloc(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_calloc(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,
const char *(*app_func) (const char *))
{
size_t line, lines, col, cols, thisguy;
int screenwidth = el->el_terminal.t_size.h;
if (app_func == NULL)
app_func = append_char_function;
/* 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 + 2);
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%s",
col == 0 ? "" : " ", matches[thisguy],
(*app_func)(matches[thisguy]));
(void)fprintf(el->el_outfile, "%-*s",
(int) (width - strlen(matches[thisguy])), "");
}
(void)fprintf(el->el_outfile, "\n");
}
}
static wchar_t *
find_word_to_complete(const wchar_t * cursor, const wchar_t * buffer,
const wchar_t * word_break, const wchar_t * special_prefixes, size_t * length)
{
/* We now look backwards for the start of a filename/variable word */
const wchar_t *ctemp = cursor;
size_t len;
/* if the cursor is placed at a slash or a quote, we need to find the
* word before it
*/
if (ctemp > buffer) {
switch (ctemp[-1]) {
case '\\':
case '\'':
case '"':
ctemp--;
break;
default:
break;
}
}
for (;;) {
if (ctemp <= buffer)
break;
if (wcschr(word_break, ctemp[-1])) {
if (ctemp - buffer >= 2 && ctemp[-2] == '\\') {
ctemp -= 2;
continue;
} else if (ctemp - buffer >= 2 &&
(ctemp[-2] == '\'' || ctemp[-2] == '"')) {
ctemp--;
continue;
} else
break;
}
if (special_prefixes && wcschr(special_prefixes, ctemp[-1]))
break;
ctemp--;
}
len = (size_t) (cursor - ctemp);
if (len == 1 && (ctemp[0] == '\'' || ctemp[0] == '"')) {
len = 0;
ctemp++;
}
*length = len;
wchar_t *unescaped_word = unescape_string(ctemp, len);
if (unescaped_word == NULL)
return NULL;
return unescaped_word;
}
/*
* 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;
char *completion;
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;
li = el_wline(el);
temp = find_word_to_complete(li->cursor,
li->buffer, word_break, special_prefixes, &len);
if (temp == NULL)
goto out;
/* 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;
int single_match = matches[2] == NULL &&
(matches[1] == NULL || strcmp(matches[0], matches[1]) == 0);
retval = CC_REFRESH;
if (matches[0][0] != '\0') {
el_deletestr(el, (int)len);
if (!attempted_completion_function)
completion = escape_filename(el, matches[0],
single_match, app_func);
else
completion = strdup(matches[0]);
if (completion == NULL)
goto out;
if (single_match) {
/* We found exact match. Add a space after it,
* unless we do filename completion and the
* object is a directory. Also do necessary
* escape quoting
*/
el_winsertstr(el,
ct_decode_string(completion, &el->el_scratch));
} else {
/* Only replace the completed string with
* common part of possible matches if there is
* possible completion.
*/
el_winsertstr(el,
ct_decode_string(completion, &el->el_scratch));
}
free(completion);
}
if (!single_match && (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, app_func);
}
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;
}
out:
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);
}

View file

@ -0,0 +1,45 @@
/* $NetBSD: filecomplete.h,v 1.11 2017/04/21 05:38:03 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.
*/
#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,
const char *(*)(const char *));
char *fn_tilde_expand(const char *);
char *fn_filename_completion_function(const char *, int);
#endif

252
contrib/libedit/hist.c Normal file
View file

@ -0,0 +1,252 @@
/* $NetBSD: hist.c,v 1.34 2019/07/23 10:19:35 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.34 2019/07/23 10:19:35 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_calloc(EL_BUFSIZ, sizeof(*el->el_history.buf));
if (el->el_history.buf == NULL)
return -1;
el->el_history.sz = EL_BUFSIZ;
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;
size_t blen, hlen;
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)
goto out;
hlen = wcslen(hp) + 1;
blen = (size_t)(el->el_line.limit - el->el_line.buffer);
if (hlen > blen && !ch_enlargebufs(el, hlen))
goto out;
memcpy(el->el_line.buffer, hp, hlen * sizeof(*hp));
el->el_line.lastchar = el->el_line.buffer + hlen - 1;
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;
out:
el->el_history.eventno = h;
return CC_ERROR;
}
/* 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);
}

80
contrib/libedit/hist.h Normal file
View file

@ -0,0 +1,80 @@
/* $NetBSD: hist.h,v 1.23 2017/09/01 10:19:10 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)
#define HIST_NSAVE_FP(el, n, fp) HIST_FUN(el, H_NSAVE_FP, n, 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 */

314
contrib/libedit/histedit.h Normal file
View file

@ -0,0 +1,314 @@
/* $NetBSD: histedit.h,v 1.57 2017/09/01 10:19:10 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 *); */
#define H_NSAVE_FP 27 /* , size_t, 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_ */

1178
contrib/libedit/history.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,3 @@
#include "config.h"
#define NARROWCHAR
#include "history.c"

669
contrib/libedit/keymacro.c Normal file
View file

@ -0,0 +1,669 @@
/* $NetBSD: keymacro.c,v 1.24 2019/07/23 10:18:52 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.24 2019/07/23 10:18:52 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_calloc(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);
}

View file

@ -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 */

136
contrib/libedit/literal.c Normal file
View file

@ -0,0 +1,136 @@
/* $NetBSD: literal.c,v 1.5 2019/07/23 13:10:11 christos Exp $ */
/*-
* Copyright (c) 2017 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 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)
__RCSID("$NetBSD: literal.c,v 1.5 2019/07/23 13:10:11 christos Exp $");
#endif /* not lint && not SCCSID */
/*
* literal.c: Literal sequences handling.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "el.h"
libedit_private void
literal_init(EditLine *el)
{
el_literal_t *l = &el->el_literal;
memset(l, 0, sizeof(*l));
}
libedit_private void
literal_end(EditLine *el)
{
literal_clear(el);
}
libedit_private void
literal_clear(EditLine *el)
{
el_literal_t *l = &el->el_literal;
size_t i;
if (l->l_len == 0)
return;
for (i = 0; i < l->l_idx; i++)
el_free(l->l_buf[i]);
el_free(l->l_buf);
l->l_buf = NULL;
l->l_len = 0;
l->l_idx = 0;
}
libedit_private wint_t
literal_add(EditLine *el, const wchar_t *buf, const wchar_t *end, int *wp)
{
el_literal_t *l = &el->el_literal;
size_t i, len;
ssize_t w, n;
char *b;
w = wcwidth(end[1]); /* column width of the visible char */
*wp = (int)w;
if (w <= 0) /* we require something to be printed */
return 0;
len = (size_t)(end - buf);
for (w = 0, i = 0; i < len; i++)
w += ct_enc_width(buf[i]);
w += ct_enc_width(end[1]);
b = el_malloc((size_t)(w + 1));
if (b == NULL)
return 0;
for (n = 0, i = 0; i < len; i++)
n += ct_encode_char(b + n, (size_t)(w - n), buf[i]);
n += ct_encode_char(b + n, (size_t)(w - n), end[1]);
b[n] = '\0';
/*
* Then save this literal string in the list of such strings,
* and return a "magic character" to put into the terminal buffer.
* When that magic char is 'printed' the saved string (which includes
* the char that belongs in that position) gets sent instead.
*/
if (l->l_idx == l->l_len) {
char **bp;
l->l_len += 4;
bp = el_realloc(l->l_buf, sizeof(*l->l_buf) * l->l_len);
if (bp == NULL) {
free(b);
l->l_len -= 4;
return 0;
}
l->l_buf = bp;
}
l->l_buf[l->l_idx++] = b;
return EL_LITERAL | (wint_t)(l->l_idx - 1);
}
libedit_private const char *
literal_get(EditLine *el, wint_t idx)
{
el_literal_t *l = &el->el_literal;
assert(idx & EL_LITERAL);
idx &= ~EL_LITERAL;
assert(l->l_idx > (size_t)idx);
return l->l_buf[idx];
}

53
contrib/libedit/literal.h Normal file
View file

@ -0,0 +1,53 @@
/* $NetBSD: literal.h,v 1.2 2017/06/30 20:26:52 kre Exp $ */
/*-
* Copyright (c) 2017 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 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.literal.h: Literal character
*/
#ifndef _h_el_literal
#define _h_el_literal
#define EL_LITERAL ((wint_t)0x80000000)
typedef struct el_literal_t {
char **l_buf; /* array of buffers */
size_t l_idx; /* max in use */
size_t l_len; /* max allocated */
} el_literal_t;
libedit_private void literal_init(EditLine *);
libedit_private void literal_end(EditLine *);
libedit_private void literal_clear(EditLine *);
libedit_private wint_t literal_add(EditLine *, const wchar_t *,
const wchar_t *, int *);
libedit_private const char *literal_get(EditLine *, wint_t);
#endif /* _h_el_literal */

174
contrib/libedit/makelist Normal file
View file

@ -0,0 +1,174 @@
#!/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...
AWK=awk
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 '[:lower:]' '[:upper:]' | $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

1427
contrib/libedit/map.c Normal file

File diff suppressed because it is too large Load diff

79
contrib/libedit/map.h Normal file
View file

@ -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 */

289
contrib/libedit/parse.c Normal file
View file

@ -0,0 +1,289 @@
/* $NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 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.42 2019/07/23 10:18:52 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]);
tprog = el_calloc(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;
}

48
contrib/libedit/parse.h Normal file
View file

@ -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 */

202
contrib/libedit/prompt.c Normal file
View file

@ -0,0 +1,202 @@
/* $NetBSD: prompt.c,v 1.27 2017/06/27 23:25:13 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.27 2017/06/27 23:25:13 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;
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) {
wchar_t *litstart = ++p;
while (*p && *p != elp->p_ignore)
p++;
if (!*p || !p[1]) {
// XXX: We lose the last literal
break;
}
re_putliteral(el, litstart, p++);
continue;
}
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;
}

58
contrib/libedit/prompt.h Normal file
View file

@ -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 */

621
contrib/libedit/read.c Normal file
View file

@ -0,0 +1,621 @@
/* $NetBSD: read.c,v 1.106 2019/07/23 10:18:52 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.106 2019/07/23 10:18:52 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_calloc(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_free(el_read);
}
/* 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;
do {
if (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:
if (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;
}

45
contrib/libedit/read.h Normal file
View file

@ -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 */

2445
contrib/libedit/readline.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
# $NetBSD: Makefile,v 1.8 2016/02/17 19:47:49 christos Exp $
NOOBJ= # defined
.include <bsd.own.mk>
.PATH: ${NETBSDSRCDIR}/lib/libedit
INCS= readline.h
INCSDIR= /usr/include/readline
INCSYMLINKS= readline.h ${INCSDIR}/history.h
.include <bsd.prog.mk>

View file

@ -0,0 +1,234 @@
/* $NetBSD: readline.h,v 1.46 2019/06/07 15:19:29 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 char *CPFunction(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);
typedef int rl_hook_func_t(void);
/* 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)
#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 const 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 const char *rl_basic_word_break_characters;
extern char *rl_completer_word_break_characters;
extern const 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 const 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 rl_hook_func_t *rl_event_hook;
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);
int append_history(int, const char *);
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 *);
int rl_reset_terminal(const char *);
void rl_resize_terminal(void);
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 *);
int 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);
void rl_reset_after_signal(void);
void rl_echo_signal_char(int);
/*
* 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_ */

1223
contrib/libedit/refresh.c Normal file

File diff suppressed because it is too large Load diff

59
contrib/libedit/refresh.h Normal file
View file

@ -0,0 +1,59 @@
/* $NetBSD: refresh.h,v 1.11 2017/06/27 23:23:48 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_putliteral(EditLine *, const wchar_t *,
const wchar_t *);
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 */

643
contrib/libedit/search.c Normal file
View file

@ -0,0 +1,643 @@
/* $NetBSD: search.c,v 1.49 2019/07/23 10:18:52 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.49 2019/07/23 10:18:52 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_calloc(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) {
wchar_t c;
if (el_wgetc(el, &c) != 1)
return ed_end_of_file(el, 0);
ch = c;
}
/* 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;
}

64
contrib/libedit/search.h Normal file
View file

@ -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 */

View file

@ -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

205
contrib/libedit/sig.c Normal file
View file

@ -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);
}

70
contrib/libedit/sig.h Normal file
View file

@ -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 */

113
contrib/libedit/sys.h Normal file
View file

@ -0,0 +1,113 @@
/* $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
#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 */
#if defined(__sun)
extern int tgetent(char *, const char *);
extern int tgetflag(char *);
extern int tgetnum(char *);
extern int tputs(const char *, int, int (*)(int));
extern char* tgoto(const char*, int, int);
extern char* tgetstr(char*, char**);
#endif
#endif /* _h_sys */

1656
contrib/libedit/terminal.c Normal file

File diff suppressed because it is too large Load diff

125
contrib/libedit/terminal.h Normal file
View file

@ -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 */

466
contrib/libedit/tokenizer.c Normal file
View file

@ -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);
}

View file

@ -0,0 +1,3 @@
#include "config.h"
#define NARROWCHAR
#include "tokenizer.c"

1373
contrib/libedit/tty.c Normal file

File diff suppressed because it is too large Load diff

482
contrib/libedit/tty.h Normal file
View file

@ -0,0 +1,482 @@
/* $NetBSD: tty.h,v 1.23 2018/12/02 16:58:13 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 *, int);
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);
libedit_private int tty_get_signal_character(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 */

1157
contrib/libedit/vi.c Normal file

File diff suppressed because it is too large Load diff