From 3150625201d9c293e5c34b19b8a2d48a27da5f07 Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Tue, 10 Sep 2019 13:55:44 +0000 Subject: [PATCH] Update libedit to snapshot 2019-09-10 --- TEST/Makefile | 4 +- TEST/test_filecompletion.c | 553 +++++++++++++++++++++++++++++++++++++ chared.c | 22 +- chartype.c | 26 +- common.c | 12 +- editline.3 | 6 +- el.c | 30 +- el.h | 4 +- eln.c | 14 +- filecomplete.c | 324 +++++++++++++++++++--- hist.c | 8 +- history.c | 16 +- keymacro.c | 6 +- literal.c | 8 +- map.c | 12 +- parse.c | 8 +- read.c | 15 +- readline.c | 98 ++++--- readline/readline.h | 21 +- refresh.c | 18 +- search.c | 10 +- terminal.c | 69 ++--- tty.c | 39 ++- tty.h | 5 +- vi.c | 8 +- 25 files changed, 1083 insertions(+), 253 deletions(-) create mode 100644 TEST/test_filecompletion.c diff --git a/TEST/Makefile b/TEST/Makefile index 1f86d7144174..2e6f8250c3ff 100644 --- a/TEST/Makefile +++ b/TEST/Makefile @@ -1,7 +1,7 @@ -# $NetBSD: Makefile,v 1.7 2016/03/23 22:27:48 christos Exp $ +# $NetBSD: Makefile,v 1.8 2017/10/15 18:59:00 abhinav Exp $ NOMAN=1 -PROG=wtc1 +PROG=wtc1 test_filecompletion CPPFLAGS=-I${.CURDIR}/.. LDADD+=-ledit -ltermlib DPADD+=${LIBEDIT} ${LIBTERMLIB} diff --git a/TEST/test_filecompletion.c b/TEST/test_filecompletion.c new file mode 100644 index 000000000000..11335083df4c --- /dev/null +++ b/TEST/test_filecompletion.c @@ -0,0 +1,553 @@ +/* $NetBSD: test_filecompletion.c,v 1.5 2019/09/08 05:50:58 abhinav Exp $ */ + +/*- + * Copyright (c) 2017 Abhinav Upadhyay + * 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 +#include +#include +#include +#include +#include +#include + +#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", + {"angtest", NULL}, + L"ls ang\\test " + }, + { + /* test angular bracket inside double quotes: ls "dq_ang */ + L"ls \"dq_ang", + "dq_ang", + {"dq_angtest", NULL}, + L"ls \"dq_angtest\"" + }, + { + /* test angular bracket inside singlq quotes: ls "sq_ang */ + L"ls 'sq_ang", + "sq_ang", + {"sq_angtest", NULL}, + L"ls 'sq_angtest'" + }, + { + /* 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 "}, + L"ls bar\\ \\<=;|&{("; + +/* + * 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; + +} diff --git a/chared.c b/chared.c index 9d46ba68feea..a96322aa6883 100644 --- a/chared.c +++ b/chared.c @@ -1,4 +1,4 @@ -/* $NetBSD: chared.c,v 1.56 2016/05/22 19:44:26 christos Exp $ */ +/* $NetBSD: chared.c,v 1.59 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: chared.c,v 1.56 2016/05/22 19:44:26 christos Exp $"); +__RCSID("$NetBSD: chared.c,v 1.59 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -174,7 +174,7 @@ c_delbefore(EditLine *el, int num) wchar_t *cp; for (cp = el->el_line.cursor - num; - cp <= el->el_line.lastchar; + &cp[num] <= el->el_line.lastchar; cp++) *cp = cp[num]; @@ -396,26 +396,22 @@ cv__endword(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t)) libedit_private int ch_init(EditLine *el) { - el->el_line.buffer = el_malloc(EL_BUFSIZ * + el->el_line.buffer = el_calloc(EL_BUFSIZ, sizeof(*el->el_line.buffer)); if (el->el_line.buffer == NULL) return -1; - (void) memset(el->el_line.buffer, 0, EL_BUFSIZ * - sizeof(*el->el_line.buffer)); el->el_line.cursor = el->el_line.buffer; el->el_line.lastchar = el->el_line.buffer; el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE]; - el->el_chared.c_undo.buf = el_malloc(EL_BUFSIZ * + 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; - (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ * - sizeof(*el->el_chared.c_undo.buf)); el->el_chared.c_undo.len = -1; el->el_chared.c_undo.cursor = 0; - el->el_chared.c_redo.buf = el_malloc(EL_BUFSIZ * + 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; @@ -426,12 +422,10 @@ ch_init(EditLine *el) el->el_chared.c_vcmd.action = NOP; el->el_chared.c_vcmd.pos = el->el_line.buffer; - el->el_chared.c_kill.buf = el_malloc(EL_BUFSIZ * + 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; - (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ * - sizeof(*el->el_chared.c_kill.buf)); el->el_chared.c_kill.mark = el->el_line.buffer; el->el_chared.c_kill.last = el->el_chared.c_kill.buf; el->el_chared.c_resizefun = NULL; @@ -591,7 +585,7 @@ ch_end(EditLine *el) /* el_insertstr(): - * Insert string at cursorI + * Insert string at cursor */ int el_winsertstr(EditLine *el, const wchar_t *s) diff --git a/chartype.c b/chartype.c index 9288e6b7db26..3df4af69b51a 100644 --- a/chartype.c +++ b/chartype.c @@ -1,4 +1,4 @@ -/* $NetBSD: chartype.c,v 1.31 2017/01/09 02:54:18 christos Exp $ */ +/* $NetBSD: chartype.c,v 1.35 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -31,10 +31,11 @@ */ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: chartype.c,v 1.31 2017/01/09 02:54:18 christos Exp $"); +__RCSID("$NetBSD: chartype.c,v 1.35 2019/07/23 10:18:52 christos Exp $"); #endif /* not lint && not SCCSID */ #include +#include #include #include @@ -156,7 +157,7 @@ ct_decode_argv(int argc, const char *argv[], ct_buffer_t *conv) if (ct_conv_wbuff_resize(conv, bufspace + CT_BUFSIZ) == -1) return NULL; - wargv = el_malloc((size_t)(argc + 1) * sizeof(*wargv)); + 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 */ @@ -183,17 +184,14 @@ ct_decode_argv(int argc, const char *argv[], ct_buffer_t *conv) libedit_private size_t ct_enc_width(wchar_t c) { - /* UTF-8 encoding specific values */ - if (c < 0x80) - return 1; - else if (c < 0x0800) - return 2; - else if (c < 0x10000) - return 3; - else if (c < 0x110000) - return 4; - else - return 0; /* not a valid codepoint */ + 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 diff --git a/common.c b/common.c index 270860510b80..bc6c057cf51d 100644 --- a/common.c +++ b/common.c @@ -1,4 +1,4 @@ -/* $NetBSD: common.c,v 1.47 2016/05/22 19:44:26 christos Exp $ */ +/* $NetBSD: common.c,v 1.48 2018/02/26 17:36:14 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: common.c,v 1.47 2016/05/22 19:44:26 christos Exp $"); +__RCSID("$NetBSD: common.c,v 1.48 2018/02/26 17:36:14 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -363,15 +363,17 @@ ed_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) * [^V] [^V] */ libedit_private el_action_t -ed_quoted_insert(EditLine *el, wint_t c) +/*ARGSUSED*/ +ed_quoted_insert(EditLine *el, wint_t c __attribute__((__unused__))) { int num; + wchar_t ch; tty_quotemode(el); - num = el_wgetc(el, &c); + num = el_wgetc(el, &ch); tty_noquotemode(el); if (num == 1) - return ed_insert(el, c); + return ed_insert(el, ch); else return ed_end_of_file(el, 0); } diff --git a/editline.3 b/editline.3 index 91788af1d653..feec9a6cac25 100644 --- a/editline.3 +++ b/editline.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: editline.3,v 1.98 2017/09/02 06:48:10 wiz Exp $ +.\" $NetBSD: editline.3,v 1.99 2018/11/18 17:09:39 christos Exp $ .\" .\" Copyright (c) 1997-2014 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -26,7 +26,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd September 1, 2017 +.Dd November 9, 2018 .Dt EDITLINE 3 .Os .Sh NAME @@ -181,8 +181,6 @@ library respects the locale set by the application program and never uses .Xr setlocale 3 to change the locale. -The only locales supported are UTF-8 and the default C or POSIX locale. -If any other locale is set, behaviour is undefined. .Sh LINE EDITING FUNCTIONS The line editing functions use a common data structure, .Fa EditLine , diff --git a/el.c b/el.c index f0cb6941f086..9ae7af3533d3 100644 --- a/el.c +++ b/el.c @@ -1,4 +1,4 @@ -/* $NetBSD: el.c,v 1.95 2017/09/05 18:07:59 christos Exp $ */ +/* $NetBSD: el.c,v 1.99 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; #else -__RCSID("$NetBSD: el.c,v 1.95 2017/09/05 18:07:59 christos Exp $"); +__RCSID("$NetBSD: el.c,v 1.99 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -71,13 +71,11 @@ 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_malloc(sizeof(*el)); + EditLine *el = el_calloc(1, sizeof(*el)); if (el == NULL) return NULL; - memset(el, 0, sizeof(EditLine)); - el->el_infile = fin; el->el_outfile = fout; el->el_errfile = ferr; @@ -96,10 +94,6 @@ el_init_internal(const char *prog, FILE *fin, FILE *fout, FILE *ferr, * Initialize all the modules. Order is important!!! */ el->el_flags = flags; - if (setlocale(LC_CTYPE, NULL) != NULL){ - if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) - el->el_flags |= CHARSET_IS_UTF8; - } if (terminal_init(el) == -1) { el_free(el->el_prog); @@ -146,7 +140,7 @@ el_end(EditLine *el) keymacro_end(el); map_end(el); if (!(el->el_flags & NO_TTY)) - tty_end(el); + tty_end(el, TCSAFLUSH); ch_end(el); read_end(el->el_read); search_end(el); @@ -301,7 +295,7 @@ el_wset(EditLine *el, int op, ...) void *ptr = va_arg(ap, void *); rv = hist_set(el, func, ptr); - if (!(el->el_flags & CHARSET_IS_UTF8)) + if (MB_CUR_MAX == 1) el->el_flags &= ~NARROW_HISTORY; break; } @@ -443,15 +437,11 @@ el_wget(EditLine *el, int op, ...) case EL_GETTC: { static char name[] = "gettc"; - char *argv[20]; - int i; - - for (i = 1; i < (int)__arraycount(argv); i++) - if ((argv[i] = va_arg(ap, char *)) == NULL) - break; - + char *argv[3]; argv[0] = name; - rv = terminal_gettc(el, i, argv); + argv[1] = va_arg(ap, char *); + argv[2] = va_arg(ap, void *); + rv = terminal_gettc(el, 3, argv); break; } @@ -542,7 +532,7 @@ el_source(EditLine *el, const char *fname) if ((ptr = getenv("HOME")) == NULL) return -1; plen += strlen(ptr); - if ((path = el_malloc(plen * sizeof(*path))) == NULL) + if ((path = el_calloc(plen, sizeof(*path))) == NULL) return -1; (void)snprintf(path, plen, "%s%s", ptr, elpath + (*ptr == '\0')); diff --git a/el.h b/el.h index eb95a3ed9e8b..b0d174eb62f6 100644 --- a/el.h +++ b/el.h @@ -1,4 +1,4 @@ -/* $NetBSD: el.h,v 1.43 2017/09/05 18:07:59 christos Exp $ */ +/* $NetBSD: el.h,v 1.45 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -55,7 +55,6 @@ #define NO_TTY 0x02 #define EDIT_DISABLED 0x04 #define UNBUFFERED 0x08 -#define CHARSET_IS_UTF8 0x10 #define NARROW_HISTORY 0x40 #define NO_RESET 0x80 @@ -90,6 +89,7 @@ typedef struct 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) diff --git a/eln.c b/eln.c index aa0a5b565dd7..e980bc5f9d2f 100644 --- a/eln.c +++ b/eln.c @@ -1,4 +1,4 @@ -/* $NetBSD: eln.c,v 1.34 2016/05/09 21:37:34 christos Exp $ */ +/* $NetBSD: eln.c,v 1.35 2019/04/26 16:56:57 christos Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: eln.c,v 1.34 2016/05/09 21:37:34 christos Exp $"); +__RCSID("$NetBSD: eln.c,v 1.35 2019/04/26 16:56:57 christos Exp $"); #endif /* not lint && not SCCSID */ #include @@ -321,14 +321,12 @@ el_get(EditLine *el, int op, ...) break; case EL_GETTC: { - char *argv[20]; + char *argv[3]; static char gettc[] = "gettc"; - int i; - for (i = 1; i < (int)__arraycount(argv); ++i) - if ((argv[i] = va_arg(ap, char *)) == NULL) - break; argv[0] = gettc; - ret = terminal_gettc(el, i, argv); + argv[1] = va_arg(ap, char *); + argv[2] = va_arg(ap, void *); + ret = terminal_gettc(el, 3, argv); break; } diff --git a/filecomplete.c b/filecomplete.c index 6ccc2719b8ab..8dd14c7f2d44 100644 --- a/filecomplete.c +++ b/filecomplete.c @@ -1,4 +1,4 @@ -/* $NetBSD: filecomplete.c,v 1.45 2017/04/21 05:38:03 abhinav Exp $ */ +/* $NetBSD: filecomplete.c,v 1.58 2019/09/08 05:50:58 abhinav Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: filecomplete.c,v 1.45 2017/04/21 05:38:03 abhinav Exp $"); +__RCSID("$NetBSD: filecomplete.c,v 1.58 2019/09/08 05:50:58 abhinav Exp $"); #endif /* not lint && not SCCSID */ #include @@ -83,7 +83,7 @@ fn_tilde_expand(const char *txt) } else { /* text until string after slash */ len = (size_t)(temp - txt + 1); - temp = el_malloc(len * sizeof(*temp)); + temp = el_calloc(len, sizeof(*temp)); if (temp == NULL) return NULL; (void)strncpy(temp, txt + 1, len - 2); @@ -118,7 +118,7 @@ fn_tilde_expand(const char *txt) txt += len; len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1; - temp = el_malloc(len * sizeof(*temp)); + temp = el_calloc(len, sizeof(*temp)); if (temp == NULL) return NULL; (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt); @@ -126,6 +126,192 @@ fn_tilde_expand(const char *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 @@ -242,7 +428,7 @@ fn_filename_completion_function(const char *text, int state) #endif len = strlen(dirname) + len + 1; - temp = el_malloc(len * sizeof(*temp)); + temp = el_calloc(len, sizeof(*temp)); if (temp == NULL) return NULL; (void)snprintf(temp, len, "%s%s", dirname, entry->d_name); @@ -318,7 +504,7 @@ completion_matches(const char *text, char *(*genfunc)(const char *, int)) max_equal = i; } - retstr = el_malloc((max_equal + 1) * sizeof(*retstr)); + retstr = el_calloc(max_equal + 1, sizeof(*retstr)); if (retstr == NULL) { el_free(match_list); return NULL; @@ -370,7 +556,7 @@ fn_display_match_list(EditLine * el, char **matches, size_t num, size_t width, * Find out how many entries can be put on one line; count * with one space between strings the same way it's printed. */ - cols = (size_t)screenwidth / (width + 1); + cols = (size_t)screenwidth / (width + 2); if (cols == 0) cols = 1; @@ -390,7 +576,7 @@ fn_display_match_list(EditLine * el, char **matches, size_t num, size_t width, break; (void)fprintf(el->el_outfile, "%s%s%s", col == 0 ? "" : " ", matches[thisguy], - append_char_function(matches[thisguy])); + (*app_func)(matches[thisguy])); (void)fprintf(el->el_outfile, "%-*s", (int) (width - strlen(matches[thisguy])), ""); } @@ -398,6 +584,60 @@ fn_display_match_list(EditLine * el, char **matches, size_t num, size_t width, } } +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. @@ -420,8 +660,8 @@ fn_complete(EditLine *el, { const LineInfoW *li; wchar_t *temp; - char **matches; - const wchar_t *ctemp; + char **matches; + char *completion; size_t len; int what_to_do = '\t'; int retval = CC_NORM; @@ -438,18 +678,11 @@ fn_complete(EditLine *el, if (!app_func) app_func = append_char_function; - /* We now look backwards for the start of a filename/variable word */ li = el_wline(el); - ctemp = li->cursor; - while (ctemp > li->buffer - && !wcschr(word_break, ctemp[-1]) - && (!special_prefixes || !wcschr(special_prefixes, ctemp[-1]) ) ) - ctemp--; - - len = (size_t)(li->cursor - ctemp); - temp = el_malloc((len + 1) * sizeof(*temp)); - (void)wcsncpy(temp, ctemp, len); - temp[len] = '\0'; + 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)() */ @@ -476,30 +709,41 @@ fn_complete(EditLine *el, 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; - /* - * Only replace the completed string with common part of - * possible matches if there is possible completion. - */ + if (matches[0][0] != '\0') { - el_deletestr(el, (int) len); - el_winsertstr(el, - ct_decode_string(matches[0], &el->el_scratch)); + 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 (matches[2] == NULL && - (matches[1] == NULL || strcmp(matches[0], matches[1]) == 0)) { - /* - * We found exact match. Add a space after - * it, unless we do filename completion and the - * object is a directory. - */ - el_winsertstr(el, - ct_decode_string((*app_func)(matches[0]), - &el->el_scratch)); - } else if (what_to_do == '!' || what_to_do == '?') { + if (!single_match && (what_to_do == '!' || what_to_do == '?')) { /* * More than one match and requested to list possible * matches. @@ -562,6 +806,8 @@ fn_complete(EditLine *el, el_free(matches); matches = NULL; } + +out: el_free(temp); return retval; } diff --git a/hist.c b/hist.c index 3c9db7dcbe71..19ce1c161722 100644 --- a/hist.c +++ b/hist.c @@ -1,4 +1,4 @@ -/* $NetBSD: hist.c,v 1.32 2017/03/05 19:23:58 christos Exp $ */ +/* $NetBSD: hist.c,v 1.34 2019/07/23 10:19:35 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: hist.c,v 1.32 2017/03/05 19:23:58 christos Exp $"); +__RCSID("$NetBSD: hist.c,v 1.34 2019/07/23 10:19:35 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -59,10 +59,10 @@ hist_init(EditLine *el) el->el_history.fun = NULL; el->el_history.ref = NULL; - el->el_history.buf = el_malloc(EL_BUFSIZ * sizeof(*el->el_history.buf)); - el->el_history.sz = EL_BUFSIZ; + 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; } diff --git a/history.c b/history.c index 47cff4d167eb..227f72c4a102 100644 --- a/history.c +++ b/history.c @@ -1,4 +1,4 @@ -/* $NetBSD: history.c,v 1.58 2017/09/01 10:19:10 christos Exp $ */ +/* $NetBSD: history.c,v 1.62 2018/09/13 09:03:40 kre Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: history.c,v 1.58 2017/09/01 10:19:10 christos Exp $"); +__RCSID("$NetBSD: history.c,v 1.62 2018/09/13 09:03:40 kre Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -775,6 +775,7 @@ history_load(TYPE(History) *h, const char *fname) char *ptr; int i = -1; TYPE(HistEvent) ev; + Char *decode_result; #ifndef NARROWCHAR static ct_buffer_t conv; #endif @@ -807,7 +808,10 @@ history_load(TYPE(History) *h, const char *fname) ptr = nptr; } (void) strunvis(ptr, line); - if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) { + decode_result = ct_decode_string(ptr, &conv); + if (decode_result == NULL) + continue; + if (HENTER(h, &ev, decode_result) == -1) { i = -1; goto oomem; } @@ -1082,11 +1086,13 @@ FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...) break; case H_NSAVE_FP: - retval = history_save_fp(h, va_arg(va, size_t), - va_arg(va, FILE *)); + { + size_t sz = va_arg(va, size_t); + retval = history_save_fp(h, sz, va_arg(va, FILE *)); if (retval == -1) he_seterrev(ev, _HE_HIST_WRITE); break; + } case H_PREV_EVENT: retval = history_prev_event(h, ev, va_arg(va, int)); diff --git a/keymacro.c b/keymacro.c index 13d208930e6b..cef24a1752e6 100644 --- a/keymacro.c +++ b/keymacro.c @@ -1,4 +1,4 @@ -/* $NetBSD: keymacro.c,v 1.23 2016/05/24 15:00:45 christos Exp $ */ +/* $NetBSD: keymacro.c,v 1.24 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: keymacro.c,v 1.23 2016/05/24 15:00:45 christos Exp $"); +__RCSID("$NetBSD: keymacro.c,v 1.24 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -105,7 +105,7 @@ libedit_private int keymacro_init(EditLine *el) { - el->el_keymacro.buf = el_malloc(KEY_BUFSIZ * + el->el_keymacro.buf = el_calloc(KEY_BUFSIZ, sizeof(*el->el_keymacro.buf)); if (el->el_keymacro.buf == NULL) return -1; diff --git a/literal.c b/literal.c index 6c2496f2f044..f6eac26937e8 100644 --- a/literal.c +++ b/literal.c @@ -1,4 +1,4 @@ -/* $NetBSD: literal.c,v 1.3 2017/06/30 20:26:52 kre Exp $ */ +/* $NetBSD: literal.c,v 1.5 2019/07/23 13:10:11 christos Exp $ */ /*- * Copyright (c) 2017 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: literal.c,v 1.3 2017/06/30 20:26:52 kre Exp $"); +__RCSID("$NetBSD: literal.c,v 1.5 2019/07/23 13:10:11 christos Exp $"); #endif /* not lint && not SCCSID */ /* @@ -98,8 +98,8 @@ literal_add(EditLine *el, const wchar_t *buf, const wchar_t *end, int *wp) return 0; for (n = 0, i = 0; i < len; i++) - n += ct_encode_char(b + n, w - n, buf[i]); - n += ct_encode_char(b + n, w - n, end[1]); + 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'; /* diff --git a/map.c b/map.c index f72d2724a81e..0c489593335a 100644 --- a/map.c +++ b/map.c @@ -1,4 +1,4 @@ -/* $NetBSD: map.c,v 1.51 2016/05/09 21:46:56 christos Exp $ */ +/* $NetBSD: map.c,v 1.52 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: map.c,v 1.51 2016/05/09 21:46:56 christos Exp $"); +__RCSID("$NetBSD: map.c,v 1.52 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -913,21 +913,21 @@ map_init(EditLine *el) EL_ABORT((el->errfile, "Vi insert map incorrect\n")); #endif - el->el_map.alt = el_malloc(sizeof(*el->el_map.alt) * N_KEYS); + el->el_map.alt = el_calloc(N_KEYS, sizeof(*el->el_map.alt)); if (el->el_map.alt == NULL) return -1; - el->el_map.key = el_malloc(sizeof(*el->el_map.key) * N_KEYS); + el->el_map.key = el_calloc(N_KEYS, sizeof(*el->el_map.key)); if (el->el_map.key == NULL) return -1; el->el_map.emacs = el_map_emacs; el->el_map.vic = el_map_vi_command; el->el_map.vii = el_map_vi_insert; - el->el_map.help = el_malloc(sizeof(*el->el_map.help) * EL_NUM_FCNS); + el->el_map.help = el_calloc(EL_NUM_FCNS, sizeof(*el->el_map.help)); if (el->el_map.help == NULL) return -1; (void) memcpy(el->el_map.help, el_func_help, sizeof(*el->el_map.help) * EL_NUM_FCNS); - el->el_map.func = el_malloc(sizeof(*el->el_map.func) * EL_NUM_FCNS); + el->el_map.func = el_calloc(EL_NUM_FCNS, sizeof(*el->el_map.func)); if (el->el_map.func == NULL) return -1; memcpy(el->el_map.func, el_func, sizeof(*el->el_map.func) diff --git a/parse.c b/parse.c index fdd0d847a79d..2620f41eb1c8 100644 --- a/parse.c +++ b/parse.c @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.40 2016/05/09 21:46:56 christos Exp $ */ +/* $NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: parse.c,v 1.40 2016/05/09 21:46:56 christos Exp $"); +__RCSID("$NetBSD: parse.c,v 1.42 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -111,8 +111,8 @@ el_wparse(EditLine *el, int argc, const wchar_t *argv[]) if (ptr == argv[0]) return 0; - l = (size_t)(ptr - argv[0] - 1); - tprog = el_malloc((l + 1) * sizeof(*tprog)); + l = (size_t)(ptr - argv[0]); + tprog = el_calloc(l + 1, sizeof(*tprog)); if (tprog == NULL) return 0; (void) wcsncpy(tprog, argv[0], l); diff --git a/read.c b/read.c index 04925c387253..d2095a244efa 100644 --- a/read.c +++ b/read.c @@ -1,4 +1,4 @@ -/* $NetBSD: read.c,v 1.103 2017/06/27 23:24:19 christos Exp $ */ +/* $NetBSD: read.c,v 1.106 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: read.c,v 1.103 2017/06/27 23:24:19 christos Exp $"); +__RCSID("$NetBSD: read.c,v 1.106 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -89,8 +89,7 @@ read_init(EditLine *el) return -1; ma = &el->el_read->macros; - if ((ma->macro = el_malloc(EL_MAXMACRO * - sizeof(*ma->macro))) == NULL) { + if ((ma->macro = el_calloc(EL_MAXMACRO, sizeof(*ma->macro))) == NULL) { free(el->el_read); return -1; } @@ -335,13 +334,7 @@ read_char(EditLine *el, wchar_t *cp) goto again; } case (size_t)-2: - /* - * We don't support other multibyte charsets. - * The second condition shouldn't happen - * and is here merely for additional safety. - */ - if ((el->el_flags & CHARSET_IS_UTF8) == 0 || - cbp >= MB_LEN_MAX) { + if (cbp >= MB_LEN_MAX) { errno = EILSEQ; *cp = L'\0'; return -1; diff --git a/readline.c b/readline.c index 80eb8463386a..dc852f5539c1 100644 --- a/readline.c +++ b/readline.c @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.143 2017/09/05 18:07:59 christos Exp $ */ +/* $NetBSD: readline.c,v 1.157 2019/08/21 11:11:48 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: readline.c,v 1.143 2017/09/05 18:07:59 christos Exp $"); +__RCSID("$NetBSD: readline.c,v 1.157 2019/08/21 11:11:48 christos Exp $"); #endif /* not lint && not SCCSID */ #include @@ -72,7 +72,7 @@ static char empty[] = { '\0' }; static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; -char *rl_readline_name = empty; +const char *rl_readline_name = empty; FILE *rl_instream = NULL; FILE *rl_outstream = NULL; int rl_point = 0; @@ -80,7 +80,7 @@ int rl_end = 0; char *rl_line_buffer = NULL; rl_vcpfunc_t *rl_linefunc = NULL; int rl_done = 0; -VFunction *rl_event_hook = NULL; +rl_hook_func_t *rl_event_hook = NULL; KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; @@ -105,9 +105,9 @@ char *history_arg_extract(int start, int end, const char *str); int rl_inhibit_completion = 0; int rl_attempted_completion_over = 0; -char *rl_basic_word_break_characters = break_chars; +const char *rl_basic_word_break_characters = break_chars; char *rl_completer_word_break_characters = NULL; -char *rl_completer_quote_characters = NULL; +const char *rl_completer_quote_characters = NULL; rl_compentry_func_t *rl_completion_entry_function = NULL; char *(*rl_completion_word_break_hook)(void) = NULL; rl_completion_func_t *rl_attempted_completion_function = NULL; @@ -150,7 +150,7 @@ int rl_completion_query_items = 100; * in the parsed text when it is passed to the completion function. * Shell uses this to help determine what kind of completing to do. */ -char *rl_special_prefixes = NULL; +const char *rl_special_prefixes = NULL; /* * This is the character appended to the completed words if at the end of @@ -258,8 +258,14 @@ rl_set_prompt(const char *prompt) if (rl_prompt == NULL) return -1; - while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) - *p = RL_PROMPT_START_IGNORE; + while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) { + /* Remove adjacent end/start markers to avoid double-escapes. */ + if (p[1] == RL_PROMPT_START_IGNORE) { + memmove(p, p + 2, 1 + strlen(p + 2)); + } else { + *p = RL_PROMPT_START_IGNORE; + } + } return 0; } @@ -319,7 +325,7 @@ rl_initialize(void) el_end(e); return -1; } - el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); + el_set(e, EL_PROMPT_ESC, _get_prompt, RL_PROMPT_START_IGNORE); el_set(e, EL_SIGNAL, rl_catch_signals); /* set default mode to "emacs"-style and read setting afterwards */ @@ -388,7 +394,7 @@ rl_initialize(void) _resize_fun(e, &rl_line_buffer); _rl_update_pos(); - tty_end(e); + tty_end(e, TCSADRAIN); return 0; } @@ -429,7 +435,7 @@ readline(const char *p) if (rl_pre_input_hook) (*rl_pre_input_hook)(NULL, 0); - if (rl_event_hook && !(e->el_flags&NO_TTY)) { + if (rl_event_hook && !(e->el_flags & NO_TTY)) { el_set(e, EL_GETCFN, _rl_event_read_char); used_event_hook = 1; } @@ -460,7 +466,7 @@ readline(const char *p) history_length = ev.num; out: - tty_end(e); + tty_end(e, TCSADRAIN); return buf; } @@ -509,7 +515,7 @@ _rl_compat_sub(const char *str, const char *what, const char *with, } else s++; } - r = result = el_malloc((len + 1) * sizeof(*r)); + r = result = el_calloc(len + 1, sizeof(*r)); if (result == NULL) return NULL; s = str; @@ -599,7 +605,7 @@ get_history_event(const char *cmd, int *cindex, int qchar) else if (len == 0) return NULL; else { - if ((pat = el_malloc((len + 1) * sizeof(*pat))) == NULL) + if ((pat = el_calloc(len + 1, sizeof(*pat))) == NULL) return NULL; (void)strncpy(pat, cmd + begin, len); pat[len] = '\0'; @@ -693,7 +699,7 @@ _history_expand_command(const char *command, size_t offs, size_t cmdlen, } else { if (command[offs + 1] == '#') { /* use command so far */ - if ((aptr = el_malloc((offs + 1) * sizeof(*aptr))) + if ((aptr = el_calloc(offs + 1, sizeof(*aptr))) == NULL) return -1; (void)strncpy(aptr, command, offs); @@ -927,7 +933,7 @@ history_expand(char *str, char **output) *output = NULL; if (str[0] == history_subst_char) { /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ - *output = el_malloc((strlen(str) + 4 + 1) * sizeof(**output)); + *output = el_calloc(strlen(str) + 4 + 1, sizeof(**output)); if (*output == NULL) return 0; (*output)[0] = (*output)[1] = history_expansion_char; @@ -1075,7 +1081,7 @@ history_arg_extract(int start, int end, const char *str) for (i = (size_t)start, len = 0; i <= (size_t)end; i++) len += strlen(arr[i]) + 1; len++; - result = el_malloc(len * sizeof(*result)); + result = el_calloc(len, sizeof(*result)); if (result == NULL) goto out; @@ -1137,7 +1143,7 @@ history_tokenize(const char *str) result = nresult; } len = (size_t)i - (size_t)start; - temp = el_malloc((size_t)(len + 1) * sizeof(*temp)); + temp = el_calloc(len + 1, sizeof(*temp)); if (temp == NULL) { for (i = 0; i < idx; i++) el_free(result[i]); @@ -1355,8 +1361,14 @@ read_history(const char *filename) rl_initialize(); if (filename == NULL && (filename = _default_history_file()) == NULL) return errno; - return history(h, &ev, H_LOAD, filename) == -1 ? - (errno ? errno : EINVAL) : 0; + errno = 0; + if (history(h, &ev, H_LOAD, filename) == -1) + return errno ? errno : EINVAL; + if (history(h, &ev, H_GETSIZE) == 0) + history_length = ev.num; + if (history_length < 0) + return EINVAL; + return 0; } @@ -1465,8 +1477,10 @@ add_history(const char *line) (void)history(h, &ev, H_GETSIZE); if (ev.num == history_length) history_base++; - else + else { + history_offset++; history_length = ev.num; + } return 0; } @@ -1584,7 +1598,7 @@ history_list(void) return NULL; if ((nlp = el_realloc(_history_listp, - (size_t)history_length * sizeof(*nlp))) == NULL) + ((size_t)history_length + 1) * sizeof(*nlp))) == NULL) return NULL; _history_listp = nlp; @@ -1601,6 +1615,7 @@ history_list(void) if (i++ == history_length) abort(); } while (history(h, &ev, H_PREV) == 0); + _history_listp[i] = NULL; return _history_listp; } @@ -1878,7 +1893,7 @@ int rl_complete(int ignore __attribute__((__unused__)), int invoking_key) { static ct_buffer_t wbreak_conv, sprefix_conv; - char *breakchars; + const char *breakchars; if (h == NULL || e == NULL) rl_initialize(); @@ -1964,13 +1979,14 @@ rl_read_key(void) * reset the terminal */ /* ARGSUSED */ -void +int rl_reset_terminal(const char *p __attribute__((__unused__))) { if (h == NULL || e == NULL) rl_initialize(); el_reset(e); + return 0; } @@ -2068,8 +2084,8 @@ rl_callback_read_char(void) if (done && rl_linefunc != NULL) { el_set(e, EL_UNBUFFERED, 0); if (done == 2) { - if ((wbuf = strdup(buf)) != NULL) - wbuf[count] = '\0'; + if ((wbuf = strdup(buf)) != NULL) + wbuf[count] = '\0'; } else wbuf = NULL; (*(void (*)(const char *))rl_linefunc)(wbuf); @@ -2159,7 +2175,7 @@ rl_variable_bind(const char *var, const char *value) return el_set(e, EL_BIND, "", var, value, NULL) == -1 ? 1 : 0; } -void +int rl_stuff_char(int c) { char buf[2]; @@ -2167,6 +2183,7 @@ rl_stuff_char(int c) buf[0] = (char)c; buf[1] = '\0'; el_insertstr(e, buf); + return 1; } static int @@ -2222,15 +2239,16 @@ _rl_update_pos(void) rl_point = (int)(li->cursor - li->buffer); rl_end = (int)(li->lastchar - li->buffer); + rl_line_buffer[rl_end] = '\0'; } void rl_get_screen_size(int *rows, int *cols) { if (rows) - el_get(e, EL_GETTC, "li", rows, (void *)0); + el_get(e, EL_GETTC, "li", rows); if (cols) - el_get(e, EL_GETTC, "co", cols, (void *)0); + el_get(e, EL_GETTC, "co", cols); } void @@ -2251,7 +2269,7 @@ rl_completion_matches(const char *str, rl_compentry_func_t *fun) len = 1; max = 10; - if ((list = el_malloc(max * sizeof(*list))) == NULL) + if ((list = el_calloc(max, sizeof(*list))) == NULL) return NULL; while ((match = (*fun)(str, (int)(len - 1))) != NULL) { @@ -2286,7 +2304,7 @@ rl_completion_matches(const char *str, rl_compentry_func_t *fun) if ((list[0] = strdup(str)) == NULL) goto out; } else { - if ((list[0] = el_malloc((min + 1) * sizeof(*list[0]))) == NULL) + if ((list[0] = el_calloc(min + 1, sizeof(*list[0]))) == NULL) goto out; (void)memcpy(list[0], list[1], min); list[0][min] = '\0'; @@ -2409,3 +2427,19 @@ rl_resize_terminal(void) { el_resize(e); } + +void +rl_reset_after_signal(void) +{ + if (rl_prep_term_function) + (*rl_prep_term_function)(); +} + +void +rl_echo_signal_char(int sig) +{ + int c = tty_get_signal_character(e, sig); + if (c == -1) + return; + re_putc(e, c, 0); +} diff --git a/readline/readline.h b/readline/readline.h index a2a6c15f74df..7e53f417bc25 100644 --- a/readline/readline.h +++ b/readline/readline.h @@ -1,4 +1,4 @@ -/* $NetBSD: readline.h,v 1.42 2017/09/01 10:19:10 christos Exp $ */ +/* $NetBSD: readline.h,v 1.46 2019/06/07 15:19:29 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -38,11 +38,13 @@ /* 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 { @@ -97,23 +99,23 @@ extern "C" { #endif extern const char *rl_library_version; extern int rl_readline_version; -extern char *rl_readline_name; +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 char *rl_basic_word_break_characters; +extern const char *rl_basic_word_break_characters; extern char *rl_completer_word_break_characters; -extern char *rl_completer_quote_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 char *rl_special_prefixes; +extern const char *rl_special_prefixes; extern int rl_completion_append_character; extern int rl_inhibit_completion; extern Function *rl_pre_input_hook; @@ -137,6 +139,7 @@ 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; @@ -177,12 +180,12 @@ 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 *); +char **completion_matches(/* const */ char *, rl_compentry_func_t *); void rl_display_match_list(char **, int, int); int rl_insert(int, int); int rl_insert_text(const char *); -void rl_reset_terminal(const char *); +int rl_reset_terminal(const char *); void rl_resize_terminal(void); int rl_bind_key(int, rl_command_func_t *); int rl_newline(int, int); @@ -196,7 +199,7 @@ void rl_deprep_terminal(void); int rl_read_init_file(const char *); int rl_parse_and_bind(const char *); int rl_variable_bind(const char *, const char *); -void rl_stuff_char(int); +int rl_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 *); @@ -208,6 +211,8 @@ 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 diff --git a/refresh.c b/refresh.c index fe5187c5f066..584eec624976 100644 --- a/refresh.c +++ b/refresh.c @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.c,v 1.54 2017/06/30 20:26:52 kre Exp $ */ +/* $NetBSD: refresh.c,v 1.56 2019/01/04 03:03:44 uwe Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: refresh.c,v 1.54 2017/06/30 20:26:52 kre Exp $"); +__RCSID("$NetBSD: refresh.c,v 1.56 2019/01/04 03:03:44 uwe Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -1090,7 +1090,10 @@ re_refresh_cursor(EditLine *el) static void re_fastputc(EditLine *el, wint_t c) { - int w = wcwidth(c); + wchar_t *lastline; + int w; + + w = wcwidth(c); while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h) re_fastputc(el, ' '); @@ -1112,17 +1115,18 @@ re_fastputc(EditLine *el, wint_t c) */ if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) { int i, lins = el->el_terminal.t_size.v; - wchar_t *firstline = el->el_display[0]; + lastline = el->el_display[0]; for(i = 1; i < lins; i++) el->el_display[i - 1] = el->el_display[i]; - re__copy_and_pad(firstline, L"", (size_t)0); - el->el_display[i - 1] = firstline; + el->el_display[i - 1] = lastline; } else { el->el_cursor.v++; - el->el_refresh.r_oldcv++; + lastline = el->el_display[++el->el_refresh.r_oldcv]; } + re__copy_and_pad(lastline, L"", (size_t)el->el_terminal.t_size.h); + if (EL_HAS_AUTO_MARGINS) { if (EL_HAS_MAGIC_MARGINS) { terminal__putc(el, ' '); diff --git a/search.c b/search.c index 5226cf5fa6a3..78e15d720cb8 100644 --- a/search.c +++ b/search.c @@ -1,4 +1,4 @@ -/* $NetBSD: search.c,v 1.47 2016/05/09 21:46:56 christos Exp $ */ +/* $NetBSD: search.c,v 1.49 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: search.c,v 1.47 2016/05/09 21:46:56 christos Exp $"); +__RCSID("$NetBSD: search.c,v 1.49 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -70,7 +70,7 @@ libedit_private int search_init(EditLine *el) { - el->el_search.patbuf = el_malloc(EL_BUFSIZ * + el->el_search.patbuf = el_calloc(EL_BUFSIZ, sizeof(*el->el_search.patbuf)); if (el->el_search.patbuf == NULL) return -1; @@ -603,8 +603,10 @@ cv_csearch(EditLine *el, int direction, wint_t ch, int count, int tflag) return CC_ERROR; if (ch == (wint_t)-1) { - if (el_wgetc(el, &ch) != 1) + wchar_t c; + if (el_wgetc(el, &c) != 1) return ed_end_of_file(el, 0); + ch = c; } /* Save for ';' and ',' commands */ diff --git a/terminal.c b/terminal.c index 9c74fcdbfb66..c0b9bda67c55 100644 --- a/terminal.c +++ b/terminal.c @@ -1,4 +1,4 @@ -/* $NetBSD: terminal.c,v 1.33 2017/06/27 23:23:09 christos Exp $ */ +/* $NetBSD: terminal.c,v 1.39 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; #else -__RCSID("$NetBSD: terminal.c,v 1.33 2017/06/27 23:23:09 christos Exp $"); +__RCSID("$NetBSD: terminal.c,v 1.39 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -269,31 +269,27 @@ libedit_private int terminal_init(EditLine *el) { - el->el_terminal.t_buf = el_malloc(TC_BUFSIZE * + el->el_terminal.t_buf = el_calloc(TC_BUFSIZE, sizeof(*el->el_terminal.t_buf)); if (el->el_terminal.t_buf == NULL) goto fail1; - el->el_terminal.t_cap = el_malloc(TC_BUFSIZE * + el->el_terminal.t_cap = el_calloc(TC_BUFSIZE, sizeof(*el->el_terminal.t_cap)); if (el->el_terminal.t_cap == NULL) goto fail2; - el->el_terminal.t_fkey = el_malloc(A_K_NKEYS * + el->el_terminal.t_fkey = el_calloc(A_K_NKEYS, sizeof(*el->el_terminal.t_fkey)); if (el->el_terminal.t_fkey == NULL) goto fail3; el->el_terminal.t_loc = 0; - el->el_terminal.t_str = el_malloc(T_str * + el->el_terminal.t_str = el_calloc(T_str, sizeof(*el->el_terminal.t_str)); if (el->el_terminal.t_str == NULL) goto fail4; - (void) memset(el->el_terminal.t_str, 0, T_str * - sizeof(*el->el_terminal.t_str)); - el->el_terminal.t_val = el_malloc(T_val * + el->el_terminal.t_val = el_calloc(T_val, sizeof(*el->el_terminal.t_val)); if (el->el_terminal.t_val == NULL) goto fail5; - (void) memset(el->el_terminal.t_val, 0, T_val * - sizeof(*el->el_terminal.t_val)); (void) terminal_set(el, NULL); terminal_init_arrow(el); return 0; @@ -419,18 +415,18 @@ terminal_rebuffer_display(EditLine *el) return 0; } -static wchar_t ** +static wint_t ** terminal_alloc_buffer(EditLine *el) { wint_t **b; coord_t *c = &el->el_terminal.t_size; int i; - b = el_malloc(sizeof(*b) * (size_t)(c->v + 1)); + b = el_calloc((size_t)(c->v + 1), sizeof(*b)); if (b == NULL) return NULL; for (i = 0; i < c->v; i++) { - b[i] = el_malloc(sizeof(**b) * (size_t)(c->h + 1)); + b[i] = el_calloc((size_t)(c->h + 1), sizeof(**b)); if (b[i] == NULL) { while (--i >= 0) el_free(b[i]); @@ -509,37 +505,14 @@ terminal_move_to_line(EditLine *el, int where) return; } if ((del = where - el->el_cursor.v) > 0) { - while (del > 0) { - if (EL_HAS_AUTO_MARGINS && - el->el_display[el->el_cursor.v][0] != '\0') { - size_t h = (size_t) - (el->el_terminal.t_size.h - 1); - for (; h > 0 && - el->el_display[el->el_cursor.v][h] == - MB_FILL_CHAR; - h--) - continue; - /* move without newline */ - terminal_move_to_char(el, (int)h); - terminal_overwrite(el, &el->el_display - [el->el_cursor.v][el->el_cursor.h], - (size_t)(el->el_terminal.t_size.h - - el->el_cursor.h)); - /* updates Cursor */ - del--; - } else { - if ((del > 1) && GoodStr(T_DO)) { - terminal_tputs(el, tgoto(Str(T_DO), del, - del), del); - del = 0; - } else { - for (; del > 0; del--) - terminal__putc(el, '\n'); - /* because the \n will become \r\n */ - el->el_cursor.h = 0; - } - } - } + /* + * We don't use DO here because some terminals are buggy + * if the destination is beyond bottom of the screen. + */ + for (; del > 0; del--) + terminal__putc(el, '\n'); + /* because the \n will become \r\n */ + el->el_cursor.h = 0; } else { /* del < 0 */ if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) terminal_tputs(el, tgoto(Str(T_UP), -del, -del), -del); @@ -988,9 +961,10 @@ terminal_get_size(EditLine *el, int *lins, int *cols) libedit_private int terminal_change_size(EditLine *el, int lins, int cols) { + coord_t cur = el->el_cursor; /* - * Just in case - */ + * Just in case + */ Val(T_co) = (cols < 2) ? 80 : cols; Val(T_li) = (lins < 1) ? 24 : lins; @@ -998,6 +972,7 @@ terminal_change_size(EditLine *el, int lins, int cols) if (terminal_rebuffer_display(el) == -1) return -1; re_clear_display(el); + el->el_cursor = cur; return 0; } diff --git a/tty.c b/tty.c index 2ca785808fe4..743075e08b3f 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $NetBSD: tty.c,v 1.66 2017/09/05 18:07:59 christos Exp $ */ +/* $NetBSD: tty.c,v 1.68 2018/12/02 16:58:13 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: tty.c,v 1.66 2017/09/05 18:07:59 christos Exp $"); +__RCSID("$NetBSD: tty.c,v 1.68 2018/12/02 16:58:13 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -586,7 +586,7 @@ tty_init(EditLine *el) */ libedit_private void /*ARGSUSED*/ -tty_end(EditLine *el) +tty_end(EditLine *el, int how) { if (el->el_flags & EDIT_DISABLED) return; @@ -594,7 +594,8 @@ tty_end(EditLine *el) if (!el->el_tty.t_initialized) return; - if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) { + if (tty_setty(el, how, &el->el_tty.t_or) == -1) + { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, strerror(errno)); @@ -1340,3 +1341,33 @@ tty_setup_flags(EditLine *el, struct termios *tios, int mode) *f = tty_update_flag(el, *f, mode, kind); } } + +libedit_private int +tty_get_signal_character(EditLine *el, int sig) +{ +#ifdef ECHOCTL + tcflag_t *ed = tty__get_flag(&el->el_tty.t_ed, MD_INP); + if ((*ed & ECHOCTL) == 0) + return -1; +#endif + switch (sig) { +#ifdef SIGINT + case SIGINT: + return el->el_tty.t_c[ED_IO][VINTR]; +#endif +#ifdef SIGQUIT + case SIGQUIT: + return el->el_tty.t_c[ED_IO][VQUIT]; +#endif +#ifdef SIGINFO + case SIGINFO: + return el->el_tty.t_c[ED_IO][VSTATUS]; +#endif +#ifdef SIGTSTP + case SIGTSTP: + return el->el_tty.t_c[ED_IO][VSUSP]; +#endif + default: + return -1; + } +} diff --git a/tty.h b/tty.h index 2603e1ad2d6d..643091961976 100644 --- a/tty.h +++ b/tty.h @@ -1,4 +1,4 @@ -/* $NetBSD: tty.h,v 1.21 2016/05/09 21:46:56 christos Exp $ */ +/* $NetBSD: tty.h,v 1.23 2018/12/02 16:58:13 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -457,13 +457,14 @@ typedef struct { typedef unsigned char ttychar_t[NN_IO][C_NCC]; libedit_private int tty_init(EditLine *); -libedit_private void tty_end(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; diff --git a/vi.c b/vi.c index 0c37bfb9b2ec..010616cdf1dc 100644 --- a/vi.c +++ b/vi.c @@ -1,4 +1,4 @@ -/* $NetBSD: vi.c,v 1.62 2016/05/09 21:46:56 christos Exp $ */ +/* $NetBSD: vi.c,v 1.63 2019/07/23 10:18:52 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: vi.c,v 1.62 2016/05/09 21:46:56 christos Exp $"); +__RCSID("$NetBSD: vi.c,v 1.63 2019/07/23 10:18:52 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -1019,10 +1019,10 @@ vi_histedit(EditLine *el, wint_t c __attribute__((__unused__))) return CC_ERROR; len = (size_t)(el->el_line.lastchar - el->el_line.buffer); #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) - cp = el_malloc(TMP_BUFSIZ * sizeof(*cp)); + cp = el_calloc(TMP_BUFSIZ, sizeof(*cp)); if (cp == NULL) goto error; - line = el_malloc(len * sizeof(*line) + 1); + line = el_calloc(len + 1, sizeof(*line)); if (line == NULL) goto error; wcsncpy(line, el->el_line.buffer, len);