summaryrefslogtreecommitdiffstats
path: root/linenoise
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-09-04 22:09:43 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-09-04 22:09:43 -0700
commitedbb612c40e3541a170aeaaf41ad8703c8b70cf9 (patch)
treedec1033f820f12de39ffea15f095e40aff706333 /linenoise
parent875c3401a17f9264b83f5dd9c673cac1ca837e1a (diff)
downloadtxr-edbb612c40e3541a170aeaaf41ad8703c8b70cf9.tar.gz
txr-edbb612c40e3541a170aeaaf41ad8703c8b70cf9.tar.bz2
txr-edbb612c40e3541a170aeaaf41ad8703c8b70cf9.zip
linenoise: get rid of globals; everything in struct.
* linenoise/linenoise.c (completion_callback, orig_termios, rawmode, mlmode, history_max_len, history_len, history): Global variables removed; moved into struct lino_state. (struct lino_state): New members next, prev. New members completion_callback, orig_termios, rawmode, mlmode, history_max_len, history_len, history. (lino_list): New static variable: dummy node for circular list of struct lino_state structures. (lino_set_multiline): Operate on structure rather than global variable. (enable_raw_mode, disable_raw_mode): Operate on structure. Use file descriptors from structures rather than inconsistent hard-coded use of STDIN_FILENO and the argument fd, which is gone. (lino_clear_screen): Obtain file descriptor from structure, rather than global. (complete_line): Operate on structure rather than globals. Pass context to completion callback. (lino_set_completion_cb): Store callback in structure rather than global. Store new context argument also. (reresh_line): Take mode from structure rather than global. (edit_insert, edit_move_end): Operate on struture rather than globals. (edit): Do not accept file descriptor arguments. Do not update ifd and ofd members of structure; just rely on these values to already be there, since the lino_make constructor puts them there. (lino_print_keycodes, go_raw): Operate on structure. (lino_make, lino_free): New functions. (lino_cleanup): New static function. (linenoise, free_hist): Operate on structure. (atexit_handler): Loop over all structures in global list, and clean up each one. (lino_hist_add, lino_list_set_max_len, lino_hist_save, lino_hist_load): Operate on structure. * linenoise/linenoise.h (lino_t): New typedef. (lino_compl_cb_t): Function type takes new context argument. (lino_set_completion_cb, linenoise, lino_hist_add, lino_hist_set_max, lino_his_save, lino_hist_load, lino_clear_screen, lino_set_multiline, lino_print_keycodes): Declarations updated. * linenoise/example.c (completion): Take new context argument, and ignore it. (main): Create linenoise context with lino_make, giving it the input and output file descriptor, and pass it to all functions.
Diffstat (limited to 'linenoise')
-rw-r--r--linenoise/example.c20
-rw-r--r--linenoise/linenoise.c371
-rw-r--r--linenoise/linenoise.h25
3 files changed, 234 insertions, 182 deletions
diff --git a/linenoise/example.c b/linenoise/example.c
index a5046fa3..f884c962 100644
--- a/linenoise/example.c
+++ b/linenoise/example.c
@@ -15,7 +15,8 @@ mem_t *chk_realloc(mem_t *old, size_t size)
return realloc(old, size);
}
-void completion(const char *buf, lino_completions_t *lc) {
+void completion(const char *buf, lino_completions_t *lc, void *ctx) {
+ (void) ctx;
if (buf[0] == 'h') {
lino_add_completion(lc, "hello");
lino_add_completion(lc, "hello there");
@@ -25,16 +26,17 @@ void completion(const char *buf, lino_completions_t *lc) {
int main(int argc, char **argv) {
char *line;
char *prgname = argv[0];
+ lino_t *ls = lino_make(0, 1);
/* Parse options, with --multiline we enable multi line editing. */
while(argc > 1) {
argc--;
argv++;
if (!strcmp(*argv,"--multiline")) {
- lino_set_multiline(1);
+ lino_set_multiline(ls, 1);
printf("Multi-line mode enabled.\n");
} else if (!strcmp(*argv,"--keycodes")) {
- lino_print_keycodes();
+ lino_print_keycodes(ls);
exit(0);
} else {
fprintf(stderr, "Usage: %s [--multiline] [--keycodes]\n", prgname);
@@ -44,11 +46,11 @@ int main(int argc, char **argv) {
/* Set the completion callback. This will be called every time the
* user uses the <tab> key. */
- lino_set_completion_cb(completion);
+ lino_set_completion_cb(ls, completion, 0);
/* Load history from file. The history file is just a plain text file
* where entries are separated by newlines. */
- lino_hist_load("history.txt"); /* Load the history at startup */
+ lino_hist_load(ls, "history.txt"); /* Load the history at startup */
/* Now this is the main loop of the typical linenoise-based application.
* The call to linenoise() will block as long as the user types something
@@ -56,16 +58,16 @@ int main(int argc, char **argv) {
*
* The typed string is returned as a malloc() allocated string by
* linenoise, so the user needs to free() it. */
- while((line = linenoise("hello> ")) != NULL) {
+ while((line = linenoise(ls, "hello> ")) != NULL) {
/* Do something with the string. */
if ((1 || line[0] != '\0') && line[0] != '/') {
printf("echo: '%s'\n", line);
- lino_hist_add(line); /* Add to the history. */
- lino_hist_save("history.txt"); /* Save the history on disk. */
+ lino_hist_add(ls, line); /* Add to the history. */
+ lino_hist_save(ls, "history.txt"); /* Save the history on disk. */
} else if (!strncmp(line,"/historylen",11)) {
/* The "/historylen" command will change the history len. */
int len = atoi(line+11);
- lino_hist_set_max_len(len);
+ lino_hist_set_max_len(ls, len);
} else if (line[0] == '/') {
printf("Unreconized command: %s\n", line);
}
diff --git a/linenoise/linenoise.c b/linenoise/linenoise.c
index 3d596bd9..53a308d6 100644
--- a/linenoise/linenoise.c
+++ b/linenoise/linenoise.c
@@ -118,29 +118,25 @@
#include <unistd.h>
#include "linenoise.h"
-typedef unsigned char mem_t;
-mem_t *chk_malloc(size_t n);
-mem_t *chk_realloc(mem_t *old, size_t size);
-
-#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
-#define LINENOISE_MAX_LINE 4096
-static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
-static lino_compl_cb_t *completion_callback = NULL;
-
-static struct termios orig_termios; /* In order to restore at exit.*/
-static int rawmode = 0; /* For atexit() function to check if restore is needed*/
-static int mlmode = 0; /* Multi line mode. Default is single line. */
-static int atexit_registered = 0; /* Register atexit just 1 time. */
-static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
-static int history_len = 0;
-static char **history = NULL;
-
/* The lino_state structure represents the state during line editing.
* We pass this state to functions implementing specific editing
* functionalities. */
struct lino_state {
+ lino_t *next, *prev; /* Links for global list: must be first */
+
+ /* Lifetime enduring state */
+ lino_compl_cb_t *completion_callback;
+ void *cb_ctx; /* User context for callback */
+ struct termios orig_termios; /* In order to restore at exit.*/
+ int rawmode; /* For atexit() function to check if restore is needed*/
+ int mlmode; /* Multi line mode. Default is single line. */
+ int history_max_len;
+ int history_len;
+ char **history;
int ifd; /* Terminal stdin file descriptor. */
int ofd; /* Terminal stdout file descriptor. */
+
+ /* Volatile state pertaining to just one linenoise call */
char *buf; /* Edited line buffer. */
size_t buflen; /* Edited line buffer size. */
const char *prompt; /* Prompt to display. */
@@ -175,8 +171,16 @@ enum key_action {
BACKSPACE = 127 /* Backspace */
};
-static void atexit_handler(void);
-static void refresh_line(struct lino_state *l);
+
+typedef unsigned char mem_t;
+mem_t *chk_malloc(size_t n);
+mem_t *chk_realloc(mem_t *old, size_t size);
+
+#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
+#define LINENOISE_MAX_LINE 4096
+static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
+static lino_t lino_list = { &lino_list, &lino_list };
+static int atexit_registered = 0; /* Register atexit just 1 time. */
/* Debugging macro. */
#if 0
@@ -200,8 +204,8 @@ FILE *lndebug_fp = NULL;
/* ======================= Low level terminal handling ====================== */
/* Set if to use or not the multi line mode. */
-void lino_set_multiline(int ml) {
- mlmode = ml;
+void lino_set_multiline(lino_t *ls, int ml) {
+ ls->mlmode = ml;
}
/* Return true if the terminal name is in the list of terminals we know are
@@ -216,18 +220,22 @@ static int is_unsupported_term(void) {
return 0;
}
+static void atexit_handler(void);
+
/* Raw mode: 1960 magic shit. */
-static int enable_raw_mode(int fd) {
+static int enable_raw_mode(lino_t *ls) {
struct termios raw;
- if (!isatty(STDIN_FILENO)) goto fatal;
+ if (!isatty(ls->ifd)) goto fatal;
+
if (!atexit_registered) {
atexit(atexit_handler);
atexit_registered = 1;
}
- if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
- raw = orig_termios; /* modify the original mode */
+ if (tcgetattr(ls->ifd,&ls->orig_termios) == -1) goto fatal;
+
+ 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);
@@ -243,8 +251,8 @@ static int enable_raw_mode(int fd) {
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
/* put terminal in raw mode after flushing */
- if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
- rawmode = 1;
+ if (tcsetattr(ls->ifd,TCSAFLUSH,&raw) < 0) goto fatal;
+ ls->rawmode = 1;
return 0;
fatal:
@@ -252,10 +260,10 @@ fatal:
return -1;
}
-static void disable_raw_mode(int fd) {
+static void disable_raw_mode(lino_t *ls) {
/* Don't even check the return value as it's too late. */
- if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
- rawmode = 0;
+ if (ls->rawmode && tcsetattr(ls->ifd,TCSAFLUSH,&ls->orig_termios) != -1)
+ ls->rawmode = 0;
}
/* Use the ESC [6n escape sequence to query the horizontal cursor position
@@ -319,10 +327,8 @@ failed:
}
/* Clear the screen. Used to handle ctrl+l */
-void lino_clear_screen(void) {
- if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
- /* nothing to do, just to avoid warning. */
- }
+int lino_clear_screen(lino_t *ls) {
+ return (write(ls->ofd,"\x1b[H\x1b[2J",7) > 0);
}
/* Beep, used for completion when there is nothing to complete or when all
@@ -343,6 +349,8 @@ static void free_completions(lino_completions_t *lc) {
free(lc->cvec);
}
+static void refresh_line(struct lino_state *l);
+
/* This is an helper function for edit() and is called when the
* user types the <tab> key in order to complete the string currently in the
* input.
@@ -354,7 +362,7 @@ static int complete_line(struct lino_state *ls) {
int nread, nwritten;
char c = 0;
- completion_callback(ls->buf,&lc);
+ ls->completion_callback(ls->buf, &lc, ls->cb_ctx);
if (lc.len == 0) {
generate_beep();
} else {
@@ -408,8 +416,9 @@ static int complete_line(struct lino_state *ls) {
}
/* Register a callback function to be called for tab-completion. */
-void lino_set_completion_cb(lino_compl_cb_t *fn) {
- completion_callback = fn;
+void lino_set_completion_cb(lino_t *ls, lino_compl_cb_t *fn, void *ctx) {
+ ls->completion_callback = fn;
+ ls->cb_ctx = ctx;
}
/* This function is used by the callback function registered by the user
@@ -587,11 +596,11 @@ static void refresh_multiline(struct lino_state *l) {
/* Calls the two low level functions refresh_singleline() or
* refresh_multiline() according to the selected mode. */
-static void refresh_line(struct lino_state *l) {
- if (mlmode)
- refresh_multiline(l);
+static void refresh_line(struct lino_state *ls) {
+ if (ls->mlmode)
+ refresh_multiline(ls);
else
- refresh_singleline(l);
+ refresh_singleline(ls);
}
/* Insert the character 'c' at cursor current position.
@@ -604,7 +613,7 @@ static int edit_insert(struct lino_state *l, char c) {
l->pos++;
l->len++;
l->buf[l->len] = '\0';
- if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) {
+ if ((!l->mlmode && l->plen+l->len < l->cols) /* || mlmode */) {
/* Avoid a full update of the line in the
* trivial case. */
if (write(l->ofd,&c,1) == -1) return -1;
@@ -660,21 +669,21 @@ static void edit_move_end(struct lino_state *l) {
#define LINENOISE_HISTORY_NEXT 0
#define LINENOISE_HISTORY_PREV 1
static void edit_history_next(struct lino_state *l, int dir) {
- if (history_len > 1) {
+ if (l->history_len > 1) {
/* Update the current history entry before to
* overwrite it with the next one. */
- free(history[history_len - 1 - l->history_index]);
- history[history_len - 1 - l->history_index] = strdup(l->buf);
+ free(l->history[l->history_len - 1 - l->history_index]);
+ l->history[l->history_len - 1 - l->history_index] = strdup(l->buf);
/* Show the new entry */
l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
if (l->history_index < 0) {
l->history_index = 0;
return;
- } else if (l->history_index >= history_len) {
- l->history_index = history_len-1;
+ } else if (l->history_index >= l->history_len) {
+ l->history_index = l->history_len-1;
return;
}
- strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
+ strncpy(l->buf,l->history[l->history_len - 1 - l->history_index],l->buflen);
l->buf[l->buflen-1] = '\0';
l->len = l->pos = strlen(l->buf);
refresh_line(l);
@@ -727,141 +736,137 @@ static void edit_delete_prev_word(struct lino_state *l) {
* when ctrl+d is typed.
*
* The function returns the length of the current buffer. */
-static int edit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
+static int edit(lino_t *l, char *buf, size_t buflen, const char *prompt)
{
- struct lino_state l;
-
/* Populate the linenoise state that we pass to functions implementing
* specific editing functionalities. */
- l.ifd = stdin_fd;
- l.ofd = stdout_fd;
- l.buf = buf;
- l.buflen = buflen;
- l.prompt = prompt;
- l.plen = strlen(prompt);
- l.oldpos = l.pos = 0;
- l.len = 0;
- l.cols = get_columns(stdin_fd, stdout_fd);
- l.maxrows = 0;
- l.history_index = 0;
+ l->buf = buf;
+ l->buflen = buflen;
+ l->prompt = prompt;
+ l->plen = strlen(prompt);
+ l->oldpos = l->pos = 0;
+ l->len = 0;
+ l->cols = get_columns(l->ifd, l->ofd);
+ l->maxrows = 0;
+ l->history_index = 0;
/* Buffer starts empty. */
- l.buf[0] = '\0';
- l.buflen--; /* Make sure there is always space for the nulterm */
+ l->buf[0] = '\0';
+ l->buflen--; /* Make sure there is always space for the nulterm */
/* The latest history entry is always our current buffer, that
* initially is just an empty string. */
- lino_hist_add("");
+ lino_hist_add(l, "");
- if (write(l.ofd,prompt,l.plen) == -1) return -1;
+ if (write(l->ofd,prompt,l->plen) == -1) return -1;
while(1) {
char c;
int nread;
char seq[3];
- nread = read(l.ifd,&c,1);
+ nread = read(l->ifd,&c,1);
if (nread <= 0)
- return l.len ? l.len : -1;
+ return l->len ? (int) l->len : -1;
/* Only autocomplete when the callback is set. It returns < 0 when
* there was an error reading from fd. Otherwise it will return the
* character that should be handled next. */
- if (c == 9 && completion_callback != NULL) {
- c = complete_line(&l);
+ if (c == 9 && l->completion_callback != NULL) {
+ c = complete_line(l);
/* Return on errors */
- if (c < 0) return l.len;
+ if (c < 0) return l->len;
/* Read next character when 0 */
if (c == 0) continue;
}
switch(c) {
case ENTER: /* enter */
- if (history_len > 0) {
- history_len--;
- free(history[history_len]);
- history[history_len] = 0;
+ if (l->history_len > 0) {
+ l->history_len--;
+ free(l->history[l->history_len]);
+ l->history[l->history_len] = 0;
}
- if (mlmode) edit_move_end(&l);
- return (int)l.len;
+ if (l->mlmode) edit_move_end(l);
+ return (int)l->len;
case CTRL_C: /* ctrl-c */
errno = EAGAIN;
return -1;
case BACKSPACE: /* backspace */
case 8: /* ctrl-h */
- edit_backspace(&l);
+ edit_backspace(l);
break;
case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
line is empty, act as end-of-file. */
- if (l.len > 0) {
- edit_delete(&l);
+ if (l->len > 0) {
+ edit_delete(l);
} else {
- if (history_len > 0) {
- history_len--;
- free(history[history_len]);
- history[history_len] = 0;
+ if (l->history_len > 0) {
+ l->history_len--;
+ free(l->history[l->history_len]);
+ l->history[l->history_len] = 0;
}
return -1;
}
break;
case CTRL_T: /* ctrl-t, swaps current character with previous. */
- if (l.pos > 0 && l.pos < l.len) {
- int aux = buf[l.pos-1];
- buf[l.pos-1] = buf[l.pos];
- buf[l.pos] = aux;
- if (l.pos != l.len-1) l.pos++;
- refresh_line(&l);
+ if (l->pos > 0 && l->pos < l->len) {
+ int aux = buf[l->pos-1];
+ buf[l->pos-1] = buf[l->pos];
+ buf[l->pos] = aux;
+ if (l->pos != l->len-1) l->pos++;
+ refresh_line(l);
}
break;
case CTRL_B: /* ctrl-b */
- edit_move_left(&l);
+ edit_move_left(l);
break;
case CTRL_F: /* ctrl-f */
- edit_move_right(&l);
+ edit_move_right(l);
break;
case CTRL_P: /* ctrl-p */
- edit_history_next(&l, LINENOISE_HISTORY_PREV);
+ edit_history_next(l, LINENOISE_HISTORY_PREV);
break;
case CTRL_N: /* ctrl-n */
- edit_history_next(&l, LINENOISE_HISTORY_NEXT);
+ edit_history_next(l, LINENOISE_HISTORY_NEXT);
break;
case ESC: /* escape sequence */
/* Read the next two bytes representing the escape sequence.
* Use two calls to handle slow terminals returning the two
* chars at different times. */
- if (read(l.ifd,seq,1) == -1) break;
- if (read(l.ifd,seq+1,1) == -1) break;
+ if (read(l->ifd,seq,1) == -1) break;
+ if (read(l->ifd,seq+1,1) == -1) break;
/* ESC [ sequences. */
if (seq[0] == '[') {
if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */
- if (read(l.ifd,seq+2,1) == -1) break;
+ if (read(l->ifd,seq+2,1) == -1) break;
if (seq[2] == '~') {
switch(seq[1]) {
case '3': /* Delete key. */
- edit_delete(&l);
+ edit_delete(l);
break;
}
}
} else {
switch(seq[1]) {
case 'A': /* Up */
- edit_history_next(&l, LINENOISE_HISTORY_PREV);
+ edit_history_next(l, LINENOISE_HISTORY_PREV);
break;
case 'B': /* Down */
- edit_history_next(&l, LINENOISE_HISTORY_NEXT);
+ edit_history_next(l, LINENOISE_HISTORY_NEXT);
break;
case 'C': /* Right */
- edit_move_right(&l);
+ edit_move_right(l);
break;
case 'D': /* Left */
- edit_move_left(&l);
+ edit_move_left(l);
break;
case 'H': /* Home */
- edit_move_home(&l);
+ edit_move_home(l);
break;
case 'F': /* End*/
- edit_move_end(&l);
+ edit_move_end(l);
break;
}
}
@@ -871,49 +876,49 @@ static int edit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const cha
else if (seq[0] == 'O') {
switch(seq[1]) {
case 'H': /* Home */
- edit_move_home(&l);
+ edit_move_home(l);
break;
case 'F': /* End*/
- edit_move_end(&l);
+ edit_move_end(l);
break;
}
}
break;
default:
- if (edit_insert(&l,c)) return -1;
+ if (edit_insert(l,c)) return -1;
break;
case CTRL_U: /* Ctrl+u, delete the whole line. */
buf[0] = '\0';
- l.pos = l.len = 0;
- refresh_line(&l);
+ l->pos = l->len = 0;
+ refresh_line(l);
break;
case CTRL_K: /* Ctrl+k, delete from current to end of line. */
- buf[l.pos] = '\0';
- l.len = l.pos;
- refresh_line(&l);
+ buf[l->pos] = '\0';
+ l->len = l->pos;
+ refresh_line(l);
break;
case CTRL_A: /* Ctrl+a, go to the start of the line */
- edit_move_home(&l);
+ edit_move_home(l);
break;
case CTRL_E: /* ctrl+e, go to the end of the line */
- edit_move_end(&l);
+ edit_move_end(l);
break;
case CTRL_L: /* ctrl+l, clear screen */
- lino_clear_screen();
- refresh_line(&l);
+ lino_clear_screen(l);
+ refresh_line(l);
break;
case CTRL_W: /* ctrl+w, delete previous word */
- edit_delete_prev_word(&l);
+ edit_delete_prev_word(l);
break;
}
}
- return l.len;
+ return l->len;
}
/* This special mode is used by linenoise in order to print scan codes
* on screen for debugging / development purposes. It is implemented
* by the linenoise_example program using the --keycodes option. */
-void lino_print_keycodes(void) {
+void lino_print_keycodes(lino_t *l) {
char quit[4];
printf("Linenoise key codes debugging mode.\n"
@@ -935,12 +940,12 @@ void lino_print_keycodes(void) {
printf("\r"); /* Go left edge manually, we are in raw mode. */
fflush(stdout);
}
- disable_raw_mode(STDIN_FILENO);
+ disable_raw_mode(l);
}
/* This function calls the line editing function edit() using
- * the STDIN file descriptor set in raw mode. */
-static int go_raw(char *buf, size_t buflen, const char *prompt) {
+ * the object's file descriptor set in raw mode. */
+static int go_raw(lino_t *ls, char *buf, size_t buflen, const char *prompt) {
int count;
if (buflen == 0) {
@@ -957,20 +962,57 @@ static int go_raw(char *buf, size_t buflen, const char *prompt) {
}
} else {
/* Interactive editing. */
- if (enable_raw_mode(STDIN_FILENO) == -1) return -1;
- count = edit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
- disable_raw_mode(STDIN_FILENO);
+ if (enable_raw_mode(ls) == -1) return -1;
+ count = edit(ls, buf, buflen, prompt);
+ disable_raw_mode(ls);
printf("\n");
}
return count;
}
+lino_t *lino_make(int ifd, int ofd)
+{
+ lino_t *ls = (lino_t *) chk_malloc(sizeof *ls);
+
+ if (ls) {
+ memset(ls, 0, sizeof *ls);
+ ls->history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
+ ls->ifd = ifd;
+ ls->ofd = ofd;
+
+ ls->prev = &lino_list;
+ ls->next = lino_list.next;
+ lino_list.next->prev = ls;
+ lino_list.next = ls;
+ }
+
+ return ls;
+}
+
+static void free_hist(lino_t *ls);
+
+static void lino_cleanup(lino_t *ls)
+{
+ disable_raw_mode(ls);
+ free_hist(ls);
+}
+
+void lino_free(lino_t *ls)
+{
+ ls->prev->next = ls->next;
+ ls->next->prev = ls->prev;
+ ls->next = ls->prev = 0;
+ lino_cleanup(ls);
+ free(ls);
+}
+
+
/* The high level function that is the main API of the linenoise library.
* This function checks if the terminal has basic capabilities, just checking
* for a blacklist of stupid terminals, and later either calls the line
* editing function or uses dummy fgets() so that you will be able to type
* something even in the most desperate of the conditions. */
-char *linenoise(const char *prompt) {
+char *linenoise(lino_t *ls, const char *prompt) {
char buf[LINENOISE_MAX_LINE];
int count;
@@ -987,7 +1029,7 @@ char *linenoise(const char *prompt) {
}
return strdup(buf);
} else {
- count = go_raw(buf,LINENOISE_MAX_LINE,prompt);
+ count = go_raw(ls, buf,LINENOISE_MAX_LINE,prompt);
if (count == -1) return NULL;
return strdup(buf);
}
@@ -997,23 +1039,25 @@ char *linenoise(const char *prompt) {
/* Free the history, but does not reset it. Only used when we have to
* exit() to avoid memory leaks are reported by valgrind & co. */
-static void free_hist(void) {
- if (history) {
+static void free_hist(lino_t *ls) {
+ if (ls->history) {
int j;
- for (j = 0; j < history_len; j++) {
- free(history[j]);
- history[j] = 0;
+ for (j = 0; j < ls->history_len; j++) {
+ free(ls->history[j]);
+ ls->history[j] = 0;
}
- free(history);
- history = 0;
+ free(ls->history);
+ ls->history = 0;
}
}
/* At exit we'll try to fix the terminal to the initial conditions. */
static void atexit_handler(void) {
- disable_raw_mode(STDIN_FILENO);
- free_hist();
+ lino_t *ls;
+
+ for (ls = lino_list.next; ls != &lino_list; ls = ls->next)
+ lino_cleanup(ls);
}
/* This is the API call to add a new entry in the linenoise history.
@@ -1023,32 +1067,33 @@ static void atexit_handler(void) {
* histories, but will work well for a few hundred of entries.
*
* Using a circular buffer is smarter, but a bit more complex to handle. */
-int lino_hist_add(const char *line) {
+int lino_hist_add(lino_t *ls, const char *line) {
char *linecopy;
- if (history_max_len == 0) return 0;
+ if (ls->history_max_len == 0) return 0;
/* Initialization on first call. */
- if (history == NULL) {
- history = (char **) chk_malloc(history_max_len * sizeof *history);
- if (history == NULL) return 0;
- memset(history,0,(sizeof(char*)*history_max_len));
+ if (ls->history == NULL) {
+ size_t size = ls->history_max_len * sizeof *ls->history;
+ ls->history = (char **) chk_malloc(size);
+ if (ls->history == NULL) return 0;
+ memset(ls->history, 0, size);
}
/* Don't add duplicated lines. */
- if (history_len && !strcmp(history[history_len-1], line)) return 0;
+ if (ls->history_len && !strcmp(ls->history[ls->history_len-1], line)) return 0;
/* Add an heap allocated copy of the line in the history.
* If we reached the max length, remove the older line. */
linecopy = strdup(line);
if (!linecopy) return 0;
- if (history_len == history_max_len) {
- free(history[0]);
- memmove(history,history+1,sizeof(char*)*(history_max_len-1));
- history_len--;
+ if (ls->history_len == ls->history_max_len) {
+ free(ls->history[0]);
+ memmove(ls->history,ls->history+1,(ls->history_max_len-1)*sizeof *ls->history);
+ ls->history_len--;
}
- history[history_len] = linecopy;
- history_len++;
+ ls->history[ls->history_len] = linecopy;
+ ls->history_len++;
return 1;
}
@@ -1056,12 +1101,12 @@ int lino_hist_add(const char *line) {
* if there is already some history, the function will make sure to retain
* just the latest 'len' elements if the new history length value is smaller
* than the amount of items already inside the history. */
-int lino_hist_set_max_len(int len) {
+int lino_hist_set_max_len(lino_t *ls, int len) {
char **nsv;
if (len < 1) return 0;
- if (history) {
- int tocopy = history_len;
+ if (ls->history) {
+ int tocopy = ls->history_len;
nsv = (char **) chk_malloc(len * sizeof *nsv);
if (nsv == NULL) return 0;
@@ -1070,28 +1115,28 @@ int lino_hist_set_max_len(int len) {
if (len < tocopy) {
int j;
- for (j = 0; j < tocopy-len; j++) free(history[j]);
+ for (j = 0; j < tocopy-len; j++) free(ls->history[j]);
tocopy = len;
}
memset(nsv,0,sizeof(char*)*len);
- memcpy(nsv,history+(history_len-tocopy), sizeof(char*)*tocopy);
- free(history);
- history = nsv;
- history_len = tocopy;
+ memcpy(nsv,ls->history+(ls->history_len-tocopy), sizeof *ls->history * tocopy);
+ free(ls->history);
+ ls->history = nsv;
+ ls->history_len = tocopy;
}
- history_max_len = len;
+ ls->history_max_len = len;
return 1;
}
/* Save the history in the specified file. On success 0 is returned
* otherwise -1 is returned. */
-int lino_hist_save(const char *filename) {
+int lino_hist_save(lino_t *ls, const char *filename) {
FILE *fp = fopen(filename,"w");
int j;
if (fp == NULL) return -1;
- for (j = 0; j < history_len; j++)
- fprintf(fp,"%s\n",history[j]);
+ for (j = 0; j < ls->history_len; j++)
+ fprintf(fp,"%s\n",ls->history[j]);
fclose(fp);
return 0;
}
@@ -1101,7 +1146,7 @@ int lino_hist_save(const char *filename) {
*
* If the file exists and the operation succeeded 0 is returned, otherwise
* on error -1 is returned. */
-int lino_hist_load(const char *filename) {
+int lino_hist_load(lino_t *ls, const char *filename) {
FILE *fp = fopen(filename,"r");
char buf[LINENOISE_MAX_LINE];
@@ -1113,7 +1158,7 @@ int lino_hist_load(const char *filename) {
p = strchr(buf,'\r');
if (!p) p = strchr(buf,'\n');
if (p) *p = '\0';
- lino_hist_add(buf);
+ lino_hist_add(ls, buf);
}
fclose(fp);
return 0;
diff --git a/linenoise/linenoise.h b/linenoise/linenoise.h
index 5eb92c4f..acf9ffe2 100644
--- a/linenoise/linenoise.h
+++ b/linenoise/linenoise.h
@@ -36,20 +36,25 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+typedef struct lino_state lino_t;
+
typedef struct lino_completions {
size_t len;
char **cvec;
} lino_completions_t;
-typedef void (lino_compl_cb_t)(const char *, lino_completions_t *);
-void lino_set_completion_cb(lino_compl_cb_t *);
+typedef void lino_compl_cb_t(const char *, 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 char *);
-char *linenoise(const char *prompt);
-int lino_hist_add(const char *line);
-int lino_hist_set_max_len(int len);
-int lino_hist_save(const char *filename);
-int lino_hist_load(const char *filename);
-void lino_clear_screen(void);
-void lino_set_multiline(int ml);
-void lino_print_keycodes(void);
+lino_t *lino_make(int ifd, int ofd);
+void lino_free(lino_t *);
+
+char *linenoise(lino_t *, const char *prompt);
+int lino_hist_add(lino_t *, const char *line);
+int lino_hist_set_max_len(lino_t *, int len);
+int lino_hist_save(lino_t *, const char *filename);
+int lino_hist_load(lino_t *, const char *filename);
+int lino_clear_screen(lino_t *);
+void lino_set_multiline(lino_t *, int ml);
+void lino_print_keycodes(lino_t *);