summaryrefslogtreecommitdiffstats
path: root/linenoise
diff options
context:
space:
mode:
Diffstat (limited to 'linenoise')
-rw-r--r--linenoise/linenoise.c198
-rw-r--r--linenoise/linenoise.h11
2 files changed, 170 insertions, 39 deletions
diff --git a/linenoise/linenoise.c b/linenoise/linenoise.c
index e61ba49d..ca75c39c 100644
--- a/linenoise/linenoise.c
+++ b/linenoise/linenoise.c
@@ -14,7 +14,7 @@
*
* Copyright (c) 2010-2015, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
- * Copyright (c) 2015-2020, Kaz Kylheku <kaz at kylheku dot com>
+ * Copyright (c) 2015-2024, Kaz Kylheku <kaz at kylheku dot com>
*
* All rights reserved.
*
@@ -42,8 +42,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <termios.h>
-#include <unistd.h>
#include <stddef.h>
#include <wchar.h>
#include <stdlib.h>
@@ -52,13 +50,16 @@
#include <string.h>
#include <ctype.h>
#include <wctype.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
#include <signal.h>
#include <limits.h>
#include <assert.h>
#include <stdarg.h>
+#include <unistd.h>
#include "config.h"
+#if CONFIG_FULL_REPL
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
#if HAVE_POLL
#include <poll.h>
#endif
@@ -67,6 +68,7 @@
#include <sys/fcntl.h>
#include <io.h>
#endif
+#endif
#include "linenoise.h"
#ifdef __cplusplus
@@ -92,33 +94,46 @@ struct lino_state {
lino_t *next, *prev; /* Links for global list: must be first */
/* Lifetime enduring state */
+#if CONFIG_FULL_REPL
lino_compl_cb_t *completion_callback;
+#endif
void *cb_ctx; /* User context for completion callback */
+#if CONFIG_FULL_REPL
lino_atom_cb_t *atom_callback;
void *ca_ctx; /* User context for atom callback */
+#endif
lino_enter_cb_t *enter_callback;
void *ce_ctx; /* User context for enter callback */
+#if CONFIG_FULL_REPL
struct termios orig_termios; /* In order to restore at exit.*/
+#endif
#ifdef __CYGWIN__
int orig_imode, orig_omode;
#endif
+#if CONFIG_FULL_REPL
int rawmode; /* For atexit() function to check if restore is needed*/
int mlmode; /* Multi line mode. Default is single line. */
+#endif
int history_max_len;
int history_len;
int loaded_lines; /* How many lines come from load. */
wchar_t **history;
+#if CONFIG_FULL_REPL
wchar_t *clip; /* Selection */
wchar_t *result; /* Previous command result. */
+#endif
mem_t *tty_ifs; /* Terminal input file stream. */
mem_t *tty_ofs; /* Terminal output file stream. */
int save_hist_idx; /* Jump to history position on entry into edit */
/* Volatile state pertaining to just one linenoise call */
- wchar_t buf[LINENOISE_MAX_DISP]; /* Displayed line bufer. */
+#if CONFIG_FULL_REPL
+ wchar_t buf[LINENOISE_MAX_DISP]; /* Displayed line buffer. */
+#endif
wchar_t data[LINENOISE_MAX_LINE]; /* True data corresponding to display */
const wchar_t *prompt; /* Prompt to display. */
const char *suffix; /* Suffix when creating temp file. */
+#if CONFIG_FULL_REPL
int plen; /* Prompt length. */
int pos; /* Current cursor position. */
int sel; /* Selection start in terms of display. */
@@ -137,7 +152,11 @@ struct lino_state {
int selmode; /* Visual selection being made. */
int selinclusive; /* Selections include character right of endpoint. */
int noninteractive; /* No character editing, even if input is tty. */
+#endif
+ int show_prompt; /* Show prompting in non-interactive mode. */
+#if CONFIG_FULL_REPL
struct lino_undo *undo_stack;
+#endif
lino_error_t error; /* Most recent error. */
};
@@ -159,12 +178,16 @@ enum key_action {
};
static lino_os_t lino_os;
-static lino_t lino_list = { &lino_list, &lino_list };
+static lino_t lino_list;
volatile sig_atomic_t lino_list_busy;
+#if CONFIG_FULL_REPL
static int atexit_registered = 0; /* Register atexit just 1 time. */
+#endif
#define nelem(array) (sizeof (array) / sizeof (array)[0])
+#if CONFIG_FULL_REPL
+
static int wcsnprintf(wchar_t *s, size_t nchar, const wchar_t *fmt, ...)
{
int ret;
@@ -177,8 +200,11 @@ static int wcsnprintf(wchar_t *s, size_t nchar, const wchar_t *fmt, ...)
return wcslen(s);
}
+#endif
+
/* ======================= Low level terminal handling ====================== */
+#if CONFIG_FULL_REPL
/* Set if to use or not the multi line mode. */
void lino_set_multiline(lino_t *ls, int ml) {
ls->mlmode = ml;
@@ -197,6 +223,7 @@ int lino_get_selinculsive(lino_t *ls)
return ls->selinclusive;
}
+
void lino_set_noninteractive(lino_t *ls, int ni)
{
ls->noninteractive = ni;
@@ -207,18 +234,31 @@ int lino_get_noninteractive(lino_t *ls)
return ls->noninteractive;
}
+#endif
+
+void lino_enable_noninteractive_prompt(lino_t *ls, int enable)
+{
+ ls->show_prompt = enable;
+}
+
+#if CONFIG_FULL_REPL
+
void lino_set_atom_cb(lino_t *l, lino_atom_cb_t *cb, void *ctx)
{
l->atom_callback = cb;
l->ca_ctx = ctx;
}
+#endif
+
void lino_set_enter_cb(lino_t *l, lino_enter_cb_t *cb, void *ctx)
{
l->enter_callback = cb;
l->ce_ctx = ctx;
}
+#if CONFIG_FULL_REPL
+
static void atexit_handler(void);
/* Raw mode: 1960 magic shit. */
@@ -243,13 +283,13 @@ static int enable_raw_mode(lino_t *ls) {
raw = ls->orig_termios; /* modify the original mode */
/* input modes: no break, no CR to NL, no parity check, no strip char,
* no start/stop output control. */
- raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ raw.c_iflag &= convert(tcflag_t, ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON));
/* we don't change any output modes (c_oflag) */
/* control modes - set 8 bit chars */
raw.c_cflag |= (CS8);
/* local modes - choing off, canonical off, no extended functions,
* no signal chars (^Z,^C) */
- raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ raw.c_lflag &= convert(tcflag_t, ~(ECHO | ICANON | IEXTEN | ISIG));
/* control chars - set return condition: min number of bytes and timer.
* We want read to return every single byte, without timeout. */
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
@@ -406,8 +446,10 @@ static void free_undo_stack(lino_t *l)
static void record_undo(lino_t *l)
{
- struct lino_undo *rec = (struct lino_undo *) lino_os.alloc_fn(sizeof *rec), *iter;
- wchar_t *data = (wchar_t *) lino_os.wstrdup_fn(l->data);
+ struct lino_undo *rec = coerce(struct lino_undo *,
+ lino_os.alloc_fn(sizeof *rec));
+ struct lino_undo *iter;
+ wchar_t *data = lino_os.wstrdup_fn(l->data);
int count;
if (rec == 0 || data == 0) {
@@ -721,6 +763,8 @@ static int history_search(lino_t *l)
verbatim:
if (hl >= convert(int, nelem(hpat)))
break;
+ if (c == CTL('J'))
+ c = '\r';
hpat[hl++] = c;
/* fallthrough */
if (0) {
@@ -784,7 +828,7 @@ static int history_search(lino_t *l)
break;
case CTL('Z'):
disable_raw_mode(l);
- raise(SIGTSTP);
+ kill(0, SIGTSTP);
enable_raw_mode(l);
}
}
@@ -840,14 +884,14 @@ static void show_help(lino_t *l)
break;
continue;
case ESC:
- if ((seq[0] = lino_os.getch_fn(l->tty_ifs)) < 0)
+ if ((seq[0] = lino_os.getch_fn(l->tty_ifs)) == WEOF)
break;
- if ((seq[1] = lino_os.getch_fn(l->tty_ifs)) < 0)
+ if ((seq[1] = lino_os.getch_fn(l->tty_ifs)) == WEOF)
break;
if (seq[0] == '[') {
if (seq[1] >= '0' && seq[1] <= '9') {
- if ((seq[2] = lino_os.getch_fn(l->tty_ifs)) < 0)
+ if ((seq[2] = lino_os.getch_fn(l->tty_ifs)) == WEOF)
break;
if (seq[2] == '~') {
switch(seq[1]) {
@@ -886,7 +930,7 @@ static void show_help(lino_t *l)
continue;
case CTL('Z'):
disable_raw_mode(l);
- raise(SIGTSTP);
+ kill(0, SIGTSTP);
enable_raw_mode(l);
i -= 1;
continue;
@@ -965,7 +1009,7 @@ static void sync_data_to_buf(lino_t *l)
l->sel = pos;
if (l->dend == dpos)
l->end = pos;
- if (l->dsel == dpos - 1 && rev && l->selinclusive && ch && ch != '\r')
+ if (l->dsel == dpos - 1 && rev && l->selinclusive)
l->sel = pos;
if (ch) {
@@ -1303,7 +1347,7 @@ static void move_cursor(lino_t *l, int npos)
static int scan_match_rev(const wchar_t *s, int i, wchar_t mch)
{
while (i > 0) {
- int ch = s[--i];
+ wchar_t ch = s[--i];
if (ch == mch)
return i;
@@ -1348,7 +1392,7 @@ static int scan_rev(const wchar_t *s, int i)
static int scan_match_fwd(const wchar_t *s, int i, wchar_t mch)
{
while (s[++i]) {
- int ch = s[i];
+ wchar_t ch = s[i];
if (ch == mch)
return i;
@@ -1483,7 +1527,7 @@ static void flash(lino_t *l, int ch)
wchar_t on[2] = { ch };
const wchar_t *off = L"\b \b";
- if (l->dlen >= (int) nelem (l->data) - 1)
+ if (l->dlen >= convert(int, nelem (l->data)) - 1)
return;
for (i = 0; i < 2 && !cancel; i++) {
@@ -1572,7 +1616,7 @@ static void delete_sel(lino_t *l)
*
* On error writing to the terminal -1 is returned, otherwise 0. */
static int edit_insert(lino_t *l, wchar_t c) {
- if (l->dlen < (int) nelem(l->data) - 1) {
+ if (l->dlen < convert(int, nelem(l->data)) - 1) {
record_triv_undo(l);
delete_sel(l);
if (l->dpos == l->dlen) {
@@ -1631,7 +1675,7 @@ static int edit_insert(lino_t *l, wchar_t c) {
static int edit_insert_str(lino_t *l, const wchar_t *s, int nchar)
{
- if (l->dlen < (int) nelem (l->data) - nchar) {
+ if (l->dlen < convert(int, nelem (l->data)) - nchar) {
record_undo(l);
delete_sel(l);
@@ -1940,7 +1984,7 @@ static void edit_in_editor(lino_t *l) {
char *ed = getenv("EDITOR");
char path[128];
- if (ed) {
+ if (ed && ed[0] != '\0') {
const char *ho = get_home();
int fd;
#if HAVE_MKSTEMPS
@@ -1968,8 +2012,9 @@ static void edit_in_editor(lino_t *l) {
if (fo) {
char cmd[256];
- snprintf(cmd, sizeof cmd, "%s %s", ed, path);
int preserve = 0;
+
+ snprintf(cmd, sizeof cmd, "%s %s", ed, path);
tr(l->data, '\r', '\n');
if (lino_os.puts_file_fn(fo, l->data) && lino_os.puts_file_fn(fo, L"\n"))
@@ -2086,6 +2131,8 @@ static int edit(lino_t *l, const wchar_t *prompt)
if (verbatim ||
(paste && c != ESC && c != BACKSPACE && c != CTL('H')))
{
+ if (verbatim && c == CTL('J'))
+ c = '\r';
if (edit_insert(l,c)) {
l->error = lino_ioerr;
goto out;
@@ -2212,12 +2259,14 @@ static int edit(lino_t *l, const wchar_t *prompt)
}
break;
}
+ l->save_hist_idx = l->history_index;
+ /* fallthrough */
+ case CTL('F'):
+ ret = l->len;
if (l->mlmode)
edit_move_end(l);
if (l->need_refresh)
refresh_line(l);
- ret = l->len;
- l->save_hist_idx = l->history_index;
goto out;
case '?':
extended = 0;
@@ -2259,7 +2308,7 @@ static int edit(lino_t *l, const wchar_t *prompt)
break;
}
- if (c < 0)
+ if (c == WEOF)
goto out;
if (c == 0)
continue;
@@ -2477,7 +2526,7 @@ static int edit(lino_t *l, const wchar_t *prompt)
if (l->need_refresh)
refresh_line(l);
disable_raw_mode(l);
- raise(SIGTSTP);
+ kill(0, SIGTSTP);
enable_raw_mode(l);
l->maxrows = 0;
l->dpos = dpos;
@@ -2505,6 +2554,8 @@ static void sigwinch_handler(int sig)
{
lino_t *li;
+ (void) sig;
+
if (lino_list_busy)
return;
@@ -2513,6 +2564,8 @@ static void sigwinch_handler(int sig)
}
#endif
+#endif
+
/* The main function of the linenoise library
* handles a non-TTY input file descriptor by opening
* a standard I/O stream on it and reading lines
@@ -2520,23 +2573,74 @@ static void sigwinch_handler(int sig)
* the edit function. */
wchar_t *linenoise(lino_t *ls, const wchar_t *prompt)
{
- int count;
int ifd = lino_os.fileno_fn(ls->tty_ifs);
- if ( ls->noninteractive || !isatty(ifd)) {
- /* Not a tty: read from file / pipe. */
- if (lino_os.getl_fn(ls->tty_ifs, ls->data, nelem(ls->data)) == 0) {
- ls->error = (lino_os.eof_fn(ls->tty_ifs) ? lino_eof : lino_ioerr);
- return 0;
+#if CONFIG_FULL_REPL
+ int noninteractive = ls->noninteractive;
+ int plain = noninteractive || !isatty(ifd);
+#else
+ int noninteractive = 1;
+ int plain = 1;
+#endif
+
+ if (plain) {
+ wchar_t *ret = 0;
+ size_t len = 0;
+ const wchar_t *condensed_prompt = prompt + wcslen(prompt);
+ int show_prompt = ls->show_prompt || (noninteractive && isatty(ifd));
+
+ if (show_prompt) {
+ while (condensed_prompt > prompt &&
+ (*condensed_prompt == 0 || *condensed_prompt == ' '))
+ {
+ condensed_prompt--;
+ }
}
- count = wcslen(ls->data);
+ for (;;) {
+ size_t nlen;
+
+ if (show_prompt)
+ lino_os.puts_fn(ls->tty_ofs, ret ? condensed_prompt : prompt);
+
+ /* Not a tty: read from file / pipe. */
+ if (lino_os.getl_fn(ls->tty_ifs, ls->data, nelem(ls->data)) == 0) {
+ ls->error = (lino_os.eof_fn(ls->tty_ifs) ? lino_eof : lino_ioerr);
+ if (!lino_os.puts_fn(ls->tty_ofs, L"\n"))
+ ls->error = lino_ioerr;
+ break;
+ }
+
+ nlen = wcslen(ls->data);
- if (count && ls->data[count-1] == '\n')
- ls->data[count-1] = '\0';
- return lino_os.wstrdup_fn(ls->data);
+ {
+ wchar_t *nret = lino_os.wrealloc_fn(ret, len + nlen + 1);
+ if (nret == 0) {
+ lino_os.free_fn(ret);
+ return 0;
+ }
+ wmemcpy(nret + len, ls->data, nlen + 1);
+ ret = nret;
+ len = len + nlen;
+
+ if (len && ret[len-1] == '\n')
+ ret[len-1] = '\r';
+ }
+
+ if (!ls->enter_callback || ls->enter_callback(ret, ls->ce_ctx))
+ break;
+ }
+
+ if (ret != 0) {
+ if (len && ret[len - 1] == '\n')
+ ret[len-1] = '\0';
+ }
+
+ return ret;
} else {
wchar_t *ret = 0;
+#if CONFIG_FULL_REPL
+ int count;
#ifdef SIGWINCH
static struct sigaction blank;
struct sigaction sa = blank, oa;
@@ -2562,6 +2666,7 @@ wchar_t *linenoise(lino_t *ls, const wchar_t *prompt)
#ifdef SIGWINCH
sigaction(SIGWINCH, &oa, 0);
#endif
+#endif
return ret;
}
}
@@ -2609,10 +2714,12 @@ lino_t *lino_copy(lino_t *le)
*ls = *le;
ls->history_len = 0;
ls->history = 0;
+#if CONFIG_FULL_REPL
ls->rawmode = 0;
ls->clip = 0;
ls->result = 0;
ls->undo_stack = 0;
+#endif
link_into_list(&lino_list, ls);
}
@@ -2625,13 +2732,17 @@ static void free_hist(lino_t *ls);
static void lino_cleanup(lino_t *ls)
{
+#if CONFIG_FULL_REPL
disable_raw_mode(ls);
+#endif
free_hist(ls);
+#if CONFIG_FULL_REPL
free_undo_stack(ls);
lino_os.free_fn(ls->clip);
ls->clip = 0;
lino_os.free_fn(ls->result);
ls->result = 0;
+#endif
}
void lino_free(lino_t *ls)
@@ -2677,6 +2788,8 @@ static void free_hist(lino_t *ls) {
}
}
+#if CONFIG_FULL_REPL
+
/* At exit we'll try to fix the terminal to the initial conditions. */
static void atexit_handler(void) {
lino_t *ls;
@@ -2685,6 +2798,8 @@ static void atexit_handler(void) {
lino_cleanup(ls);
}
+#endif
+
/* This is the API call to add a new entry in the linenoise history.
* It uses a fixed array of char pointers that are shifted (memmoved)
* when the history max length is reached in order to remove the older
@@ -2724,7 +2839,9 @@ int lino_hist_add(lino_t *ls, const wchar_t *line) {
}
ls->history[ls->history_len] = linecopy;
ls->history_len++;
+#if CONFIG_FULL_REPL
undo_renumber_hist_idx(ls, 1);
+#endif
return 1;
}
@@ -2825,6 +2942,8 @@ int lino_have_new_lines(lino_t *ls)
return ls->history_len > ls->loaded_lines;
}
+#if CONFIG_FULL_REPL
+
void lino_set_result(lino_t *ls, wchar_t *res)
{
lino_os.free_fn(ls->result);
@@ -2833,7 +2952,10 @@ void lino_set_result(lino_t *ls, wchar_t *res)
*res = '\r';
}
+#endif
+
void lino_init(lino_os_t *os)
{
lino_os = *os;
+ lino_list.next = lino_list.prev = &lino_list;
}
diff --git a/linenoise/linenoise.h b/linenoise/linenoise.h
index da6e93de..34d0a993 100644
--- a/linenoise/linenoise.h
+++ b/linenoise/linenoise.h
@@ -9,7 +9,7 @@
*
* Copyright (c) 2010-2015, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
- * Copyright (c) 2015-2020, Kaz Kylheku <kaz at kylheku dot com>
+ * Copyright (c) 2015-2024, Kaz Kylheku <kaz at kylheku dot com>
*
* All rights reserved.
*
@@ -92,6 +92,8 @@ typedef struct lino_os {
wide_disp \
}
+#if CONFIG_FULL_REPL
+
typedef struct lino_completions {
size_t len;
wchar_t **cvec;
@@ -102,6 +104,8 @@ typedef void lino_compl_cb_t(const wchar_t *, lino_completions_t *, void *ctx);
void lino_set_completion_cb(lino_t *, lino_compl_cb_t *, void *ctx);
void lino_add_completion(lino_completions_t *, const wchar_t *);
+#endif
+
void lino_init(lino_os_t *);
lino_t *lino_make(mem_t *istream, mem_t *ostream);
lino_t *lino_copy(lino_t *);
@@ -116,6 +120,7 @@ int lino_hist_set_max_len(lino_t *, int len);
int lino_hist_save(lino_t *, const wchar_t *filename, int new_only);
int lino_hist_load(lino_t *, const wchar_t *filename);
int lino_have_new_lines(lino_t *);
+#if HAVE_TERMIOS
void lino_set_result(lino_t *, wchar_t *); /* takes ownership of malloced mem; modifies it */
int lino_clear_screen(lino_t *);
void lino_set_multiline(lino_t *, int ml);
@@ -124,9 +129,13 @@ void lino_set_selinclusive(lino_t *, int si);
int lino_get_selinculsive(lino_t *);
void lino_set_noninteractive(lino_t *, int ni);
int lino_get_noninteractive(lino_t *);
+#endif
+void lino_enable_noninteractive_prompt(lino_t *, int enable);
+#if HAVE_TERMIOS
typedef wchar_t *lino_atom_cb_t(lino_t *, const wchar_t *line, int n, void *ctx);
void lino_set_atom_cb(lino_t *, lino_atom_cb_t *, void *ctx);
+#endif
typedef int lino_enter_cb_t(const wchar_t *line, void *ctx);
void lino_set_enter_cb(lino_t *, lino_enter_cb_t *, void *ctx);