version 1.99.2.4, 2013/01/23 00:05:24 |
version 1.146.2.1, 2018/06/25 07:25:35 |
Line 36 __RCSID("$NetBSD$"); |
|
Line 36 __RCSID("$NetBSD$"); |
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <stdio.h> |
|
#include <dirent.h> |
|
#include <string.h> |
|
#include <pwd.h> |
|
#include <ctype.h> |
#include <ctype.h> |
#include <stdlib.h> |
#include <dirent.h> |
#include <unistd.h> |
|
#include <limits.h> |
|
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
|
#include <limits.h> |
|
#include <pwd.h> |
#include <setjmp.h> |
#include <setjmp.h> |
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <unistd.h> |
#include <vis.h> |
#include <vis.h> |
|
|
#include "readline/readline.h" |
#include "readline/readline.h" |
#include "el.h" |
#include "el.h" |
#include "fcns.h" /* for EL_NUM_FCNS */ |
#include "fcns.h" |
#include "histedit.h" |
|
#include "filecomplete.h" |
#include "filecomplete.h" |
|
|
void rl_prep_terminal(int); |
void rl_prep_terminal(int); |
Line 78 FILE *rl_outstream = NULL; |
|
Line 78 FILE *rl_outstream = NULL; |
|
int rl_point = 0; |
int rl_point = 0; |
int rl_end = 0; |
int rl_end = 0; |
char *rl_line_buffer = NULL; |
char *rl_line_buffer = NULL; |
VCPFunction *rl_linefunc = NULL; |
rl_vcpfunc_t *rl_linefunc = NULL; |
int rl_done = 0; |
int rl_done = 0; |
VFunction *rl_event_hook = NULL; |
rl_hook_func_t *rl_event_hook = NULL; |
KEYMAP_ENTRY_ARRAY emacs_standard_keymap, |
KEYMAP_ENTRY_ARRAY emacs_standard_keymap, |
emacs_meta_keymap, |
emacs_meta_keymap, |
emacs_ctlx_keymap; |
emacs_ctlx_keymap; |
|
/* |
|
* The following is not implemented; we always catch signals in the |
|
* libedit fashion: set handlers on entry to el_gets() and clear them |
|
* on the way out. This simplistic approach works for most cases; if |
|
* it does not work for your application, please let us know. |
|
*/ |
|
int rl_catch_signals = 1; |
|
int rl_catch_sigwinch = 1; |
|
|
int history_base = 1; /* probably never subject to change */ |
int history_base = 1; /* probably never subject to change */ |
int history_length = 0; |
int history_length = 0; |
|
int history_offset = 0; |
int max_input_history = 0; |
int max_input_history = 0; |
char history_expansion_char = '!'; |
char history_expansion_char = '!'; |
char history_subst_char = '^'; |
char history_subst_char = '^'; |
Line 99 int rl_attempted_completion_over = 0; |
|
Line 108 int rl_attempted_completion_over = 0; |
|
char *rl_basic_word_break_characters = break_chars; |
char *rl_basic_word_break_characters = break_chars; |
char *rl_completer_word_break_characters = NULL; |
char *rl_completer_word_break_characters = NULL; |
char *rl_completer_quote_characters = NULL; |
char *rl_completer_quote_characters = NULL; |
Function *rl_completion_entry_function = NULL; |
rl_compentry_func_t *rl_completion_entry_function = NULL; |
char *(*rl_completion_word_break_hook)(void) = NULL; |
char *(*rl_completion_word_break_hook)(void) = NULL; |
CPPFunction *rl_attempted_completion_function = NULL; |
rl_completion_func_t *rl_attempted_completion_function = NULL; |
Function *rl_pre_input_hook = NULL; |
Function *rl_pre_input_hook = NULL; |
Function *rl_startup1_hook = NULL; |
Function *rl_startup1_hook = NULL; |
int (*rl_getc_function)(FILE *) = NULL; |
int (*rl_getc_function)(FILE *) = NULL; |
Line 109 char *rl_terminal_name = NULL; |
|
Line 118 char *rl_terminal_name = NULL; |
|
int rl_already_prompted = 0; |
int rl_already_prompted = 0; |
int rl_filename_completion_desired = 0; |
int rl_filename_completion_desired = 0; |
int rl_ignore_completion_duplicates = 0; |
int rl_ignore_completion_duplicates = 0; |
int rl_catch_signals = 1; |
|
int readline_echoing_p = 1; |
int readline_echoing_p = 1; |
int _rl_print_completions_horizontally = 0; |
int _rl_print_completions_horizontally = 0; |
VFunction *rl_redisplay_function = NULL; |
VFunction *rl_redisplay_function = NULL; |
Function *rl_startup_hook = NULL; |
Function *rl_startup_hook = NULL; |
|
int rl_did_startup_hook = 0; |
VFunction *rl_completion_display_matches_hook = NULL; |
VFunction *rl_completion_display_matches_hook = NULL; |
VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; |
VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; |
VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; |
VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; |
Line 153 int rl_completion_append_character = ' ' |
|
Line 162 int rl_completion_append_character = ' ' |
|
|
|
static History *h = NULL; |
static History *h = NULL; |
static EditLine *e = NULL; |
static EditLine *e = NULL; |
static Function *map[256]; |
static rl_command_func_t *map[256]; |
static jmp_buf topbuf; |
static jmp_buf topbuf; |
|
|
/* internal functions */ |
/* internal functions */ |
static unsigned char _el_rl_complete(EditLine *, int); |
static unsigned char _el_rl_complete(EditLine *, int); |
static unsigned char _el_rl_tstp(EditLine *, int); |
static unsigned char _el_rl_tstp(EditLine *, int); |
static char *_get_prompt(EditLine *); |
static char *_get_prompt(EditLine *); |
static int _getc_function(EditLine *, char *); |
static int _getc_function(EditLine *, wchar_t *); |
static HIST_ENTRY *_move_history(int); |
|
static int _history_expand_command(const char *, size_t, size_t, |
static int _history_expand_command(const char *, size_t, size_t, |
char **); |
char **); |
static char *_rl_compat_sub(const char *, const char *, |
static char *_rl_compat_sub(const char *, const char *, |
const char *, int); |
const char *, int); |
static int _rl_event_read_char(EditLine *, char *); |
static int _rl_event_read_char(EditLine *, wchar_t *); |
static void _rl_update_pos(void); |
static void _rl_update_pos(void); |
|
|
|
static HIST_ENTRY rl_he; |
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static char * |
static char * |
Line 180 _get_prompt(EditLine *el __attribute__(( |
|
Line 189 _get_prompt(EditLine *el __attribute__(( |
|
|
|
|
|
/* |
/* |
* generic function for moving around history |
|
*/ |
|
static HIST_ENTRY * |
|
_move_history(int op) |
|
{ |
|
HistEvent ev; |
|
static HIST_ENTRY rl_he; |
|
|
|
if (history(h, &ev, op) != 0) |
|
return NULL; |
|
|
|
rl_he.line = ev.str; |
|
rl_he.data = NULL; |
|
|
|
return &rl_he; |
|
} |
|
|
|
|
|
/* |
|
* read one key from user defined input function |
* read one key from user defined input function |
*/ |
*/ |
static int |
static int |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
_getc_function(EditLine *el __attribute__((__unused__)), char *c) |
_getc_function(EditLine *el __attribute__((__unused__)), wchar_t *c) |
{ |
{ |
int i; |
int i; |
|
|
i = (*rl_getc_function)(NULL); |
i = (*rl_getc_function)(rl_instream); |
if (i == -1) |
if (i == -1) |
return 0; |
return 0; |
*c = (char)i; |
*c = (wchar_t)i; |
return 1; |
return 1; |
} |
} |
|
|
Line 229 static const char * |
|
Line 219 static const char * |
|
_default_history_file(void) |
_default_history_file(void) |
{ |
{ |
struct passwd *p; |
struct passwd *p; |
static char path[PATH_MAX]; |
static char *path; |
|
size_t len; |
|
|
if (*path) |
if (path) |
return path; |
return path; |
|
|
if ((p = getpwuid(getuid())) == NULL) |
if ((p = getpwuid(getuid())) == NULL) |
return NULL; |
return NULL; |
(void)snprintf(path, sizeof(path), "%s/.history", p->pw_dir); |
|
|
len = strlen(p->pw_dir) + sizeof("/.history"); |
|
if ((path = malloc(len)) == NULL) |
|
return NULL; |
|
|
|
(void)snprintf(path, len, "%s/.history", p->pw_dir); |
return path; |
return path; |
} |
} |
|
|
Line 253 rl_set_prompt(const char *prompt) |
|
Line 250 rl_set_prompt(const char *prompt) |
|
|
|
if (!prompt) |
if (!prompt) |
prompt = ""; |
prompt = ""; |
if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) |
if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) |
return 0; |
return 0; |
if (rl_prompt) |
if (rl_prompt) |
el_free(rl_prompt); |
el_free(rl_prompt); |
Line 293 rl_initialize(void) |
|
Line 290 rl_initialize(void) |
|
if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) |
if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) |
editmode = 0; |
editmode = 0; |
|
|
e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); |
e = el_init_internal(rl_readline_name, rl_instream, rl_outstream, |
|
stderr, fileno(rl_instream), fileno(rl_outstream), fileno(stderr), |
|
NO_RESET); |
|
|
if (!editmode) |
if (!editmode) |
el_set(e, EL_EDITMODE, 0); |
el_set(e, EL_EDITMODE, 0); |
Line 324 rl_initialize(void) |
|
Line 323 rl_initialize(void) |
|
el_set(e, EL_SIGNAL, rl_catch_signals); |
el_set(e, EL_SIGNAL, rl_catch_signals); |
|
|
/* set default mode to "emacs"-style and read setting afterwards */ |
/* set default mode to "emacs"-style and read setting afterwards */ |
/* so this can be overriden */ |
/* so this can be overridden */ |
el_set(e, EL_EDITOR, "emacs"); |
el_set(e, EL_EDITOR, "emacs"); |
if (rl_terminal_name != NULL) |
if (rl_terminal_name != NULL) |
el_set(e, EL_TERMINAL, rl_terminal_name); |
el_set(e, EL_TERMINAL, rl_terminal_name); |
Line 347 rl_initialize(void) |
|
Line 346 rl_initialize(void) |
|
"ReadLine compatible suspend function", |
"ReadLine compatible suspend function", |
_el_rl_tstp); |
_el_rl_tstp); |
el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); |
el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); |
|
|
|
/* |
|
* Set some readline compatible key-bindings. |
|
*/ |
|
el_set(e, EL_BIND, "^R", "em-inc-search-prev", NULL); |
|
|
|
/* |
|
* Allow the use of Home/End keys. |
|
*/ |
|
el_set(e, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL); |
|
el_set(e, EL_BIND, "\\e[4~", "ed-move-to-end", NULL); |
|
el_set(e, EL_BIND, "\\e[7~", "ed-move-to-beg", NULL); |
|
el_set(e, EL_BIND, "\\e[8~", "ed-move-to-end", NULL); |
|
el_set(e, EL_BIND, "\\e[H", "ed-move-to-beg", NULL); |
|
el_set(e, EL_BIND, "\\e[F", "ed-move-to-end", NULL); |
|
|
|
/* |
|
* Allow the use of the Delete/Insert keys. |
|
*/ |
|
el_set(e, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL); |
|
el_set(e, EL_BIND, "\\e[2~", "ed-quoted-insert", NULL); |
|
|
|
/* |
|
* Ctrl-left-arrow and Ctrl-right-arrow for word moving. |
|
*/ |
|
el_set(e, EL_BIND, "\\e[1;5C", "em-next-word", NULL); |
|
el_set(e, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); |
|
el_set(e, EL_BIND, "\\e[5C", "em-next-word", NULL); |
|
el_set(e, EL_BIND, "\\e[5D", "ed-prev-word", NULL); |
|
el_set(e, EL_BIND, "\\e\\e[C", "em-next-word", NULL); |
|
el_set(e, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); |
|
|
/* read settings from configuration file */ |
/* read settings from configuration file */ |
el_source(e, NULL); |
el_source(e, NULL); |
|
|
Line 358 rl_initialize(void) |
|
Line 388 rl_initialize(void) |
|
_resize_fun(e, &rl_line_buffer); |
_resize_fun(e, &rl_line_buffer); |
_rl_update_pos(); |
_rl_update_pos(); |
|
|
if (rl_startup_hook) |
tty_end(e, TCSADRAIN); |
(*rl_startup_hook)(NULL, 0); |
|
|
|
return 0; |
return 0; |
} |
} |
Line 381 readline(const char *p) |
|
Line 410 readline(const char *p) |
|
|
|
if (e == NULL || h == NULL) |
if (e == NULL || h == NULL) |
rl_initialize(); |
rl_initialize(); |
|
if (rl_did_startup_hook == 0 && rl_startup_hook) { |
|
rl_did_startup_hook = 1; |
|
(*rl_startup_hook)(NULL, 0); |
|
} |
|
tty_init(e); |
|
|
|
|
rl_done = 0; |
rl_done = 0; |
|
|
(void)setjmp(topbuf); |
(void)setjmp(topbuf); |
|
buf = NULL; |
|
|
/* update prompt accordingly to what has been passed */ |
/* update prompt accordingly to what has been passed */ |
if (rl_set_prompt(prompt) == -1) |
if (rl_set_prompt(prompt) == -1) |
return NULL; |
goto out; |
|
|
if (rl_pre_input_hook) |
if (rl_pre_input_hook) |
(*rl_pre_input_hook)(NULL, 0); |
(*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); |
el_set(e, EL_GETCFN, _rl_event_read_char); |
used_event_hook = 1; |
used_event_hook = 1; |
} |
} |
Line 413 readline(const char *p) |
|
Line 449 readline(const char *p) |
|
|
|
buf = strdup(ret); |
buf = strdup(ret); |
if (buf == NULL) |
if (buf == NULL) |
return NULL; |
goto out; |
lastidx = count - 1; |
lastidx = count - 1; |
if (buf[lastidx] == '\n') |
if (buf[lastidx] == '\n') |
buf[lastidx] = '\0'; |
buf[lastidx] = '\0'; |
Line 423 readline(const char *p) |
|
Line 459 readline(const char *p) |
|
history(h, &ev, H_GETSIZE); |
history(h, &ev, H_GETSIZE); |
history_length = ev.num; |
history_length = ev.num; |
|
|
|
out: |
|
tty_end(e, TCSADRAIN); |
return buf; |
return buf; |
} |
} |
|
|
Line 439 using_history(void) |
|
Line 477 using_history(void) |
|
{ |
{ |
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
history_offset = history_length; |
} |
} |
|
|
|
|
Line 520 get_history_event(const char *cmd, int * |
|
Line 559 get_history_event(const char *cmd, int * |
|
} |
} |
|
|
if ('0' <= cmd[idx] && cmd[idx] <= '9') { |
if ('0' <= cmd[idx] && cmd[idx] <= '9') { |
HIST_ENTRY *rl_he; |
HIST_ENTRY *he; |
|
|
num = 0; |
num = 0; |
while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { |
while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { |
Line 528 get_history_event(const char *cmd, int * |
|
Line 567 get_history_event(const char *cmd, int * |
|
idx++; |
idx++; |
} |
} |
if (sign) |
if (sign) |
num = history_length - num + 1; |
num = history_length - num + history_base; |
|
|
if (!(rl_he = history_get(num))) |
if (!(he = history_get(num))) |
return NULL; |
return NULL; |
|
|
*cindex = idx; |
*cindex = idx; |
return rl_he->line; |
return he->line; |
} |
} |
sub = 0; |
sub = 0; |
if (cmd[idx] == '?') { |
if (cmd[idx] == '?') { |
Line 620 get_history_event(const char *cmd, int * |
|
Line 659 get_history_event(const char *cmd, int * |
|
* returns 0 if data was not modified, 1 if it was and 2 if the string |
* returns 0 if data was not modified, 1 if it was and 2 if the string |
* should be only printed and not executed; in case of error, |
* should be only printed and not executed; in case of error, |
* returns -1 and *result points to NULL |
* returns -1 and *result points to NULL |
* it's callers responsibility to free() string returned in *result |
* it's the caller's responsibility to free() the string returned in *result |
*/ |
*/ |
static int |
static int |
_history_expand_command(const char *command, size_t offs, size_t cmdlen, |
_history_expand_command(const char *command, size_t offs, size_t cmdlen, |
|
|
for (; str[j]; j++) { |
for (; str[j]; j++) { |
if (str[j] == '\\' && |
if (str[j] == '\\' && |
str[j + 1] == history_expansion_char) { |
str[j + 1] == history_expansion_char) { |
(void)strcpy(&str[j], &str[j + 1]); |
len = strlen(&str[j + 1]) + 1; |
|
memmove(&str[j], &str[j + 1], len); |
continue; |
continue; |
} |
} |
if (!loop_again) { |
if (!loop_again) { |
|
|
stifle_history(int max) |
stifle_history(int max) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
HIST_ENTRY *he; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
if (history(h, &ev, H_SETSIZE, max) == 0) |
if (history(h, &ev, H_SETSIZE, max) == 0) { |
max_input_history = max; |
max_input_history = max; |
|
if (history_length > max) |
|
history_base = history_length - max; |
|
while (history_length > max) { |
|
he = remove_history(0); |
|
el_free(he->data); |
|
el_free((void *)(unsigned long)he->line); |
|
el_free(he); |
|
} |
|
} |
} |
} |
|
|
|
|
Line 1305 read_history(const char *filename) |
|
Line 1355 read_history(const char *filename) |
|
rl_initialize(); |
rl_initialize(); |
if (filename == NULL && (filename = _default_history_file()) == NULL) |
if (filename == NULL && (filename = _default_history_file()) == NULL) |
return errno; |
return errno; |
return history(h, &ev, H_LOAD, filename) == -1 ? |
errno = 0; |
(errno ? errno : EINVAL) : 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; |
} |
} |
|
|
|
|
Line 1326 write_history(const char *filename) |
|
Line 1382 write_history(const char *filename) |
|
(errno ? errno : EINVAL) : 0; |
(errno ? errno : EINVAL) : 0; |
} |
} |
|
|
|
int |
|
append_history(int n, const char *filename) |
|
{ |
|
HistEvent ev; |
|
FILE *fp; |
|
|
|
if (h == NULL || e == NULL) |
|
rl_initialize(); |
|
if (filename == NULL && (filename = _default_history_file()) == NULL) |
|
return errno; |
|
|
|
if ((fp = fopen(filename, "a")) == NULL) |
|
return errno; |
|
|
|
if (history(h, &ev, H_NSAVE_FP, (size_t)n, fp) == -1) { |
|
int serrno = errno ? errno : EINVAL; |
|
fclose(fp); |
|
return serrno; |
|
} |
|
fclose(fp); |
|
return 0; |
|
} |
|
|
/* |
/* |
* returns history ``num''th event |
* returns history ``num''th event |
Line 1342 history_get(int num) |
|
Line 1420 history_get(int num) |
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
|
if (num < history_base) |
|
return NULL; |
|
|
/* save current position */ |
/* save current position */ |
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_CURR) != 0) |
return NULL; |
return NULL; |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
/* start from the oldest */ |
/* |
if (history(h, &ev, H_LAST) != 0) |
* use H_DELDATA to set to nth history (without delete) by passing |
return NULL; /* error */ |
* (void **)-1 -- as in history_set_pos |
|
*/ |
/* look forwards for event matching specified offset */ |
if (history(h, &ev, H_DELDATA, num - history_base, (void **)-1) != 0) |
if (history(h, &ev, H_NEXT_EVDATA, num, &she.data)) |
goto out; |
return NULL; |
|
|
|
|
/* get current entry */ |
|
if (history(h, &ev, H_CURR) != 0) |
|
goto out; |
|
if (history(h, &ev, H_NEXT_EVDATA, ev.num, &she.data) != 0) |
|
goto out; |
she.line = ev.str; |
she.line = ev.str; |
|
|
/* restore pointer to where it was */ |
/* restore pointer to where it was */ |
(void)history(h, &ev, H_SET, curr_num); |
(void)history(h, &ev, H_SET, curr_num); |
|
|
return &she; |
return &she; |
|
|
|
out: |
|
/* restore pointer to where it was */ |
|
(void)history(h, &ev, H_SET, curr_num); |
|
return NULL; |
} |
} |
|
|
|
|
Line 1372 add_history(const char *line) |
|
Line 1462 add_history(const char *line) |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
|
if (line == NULL) |
|
return 0; |
|
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
(void)history(h, &ev, H_ENTER, line); |
if (history(h, &ev, H_ENTER, line) == -1) |
if (history(h, &ev, H_GETSIZE) == 0) |
return 0; |
history_length = ev.num; |
|
|
|
return !(history_length > 0); /* return 0 if all is okay */ |
(void)history(h, &ev, H_GETSIZE); |
|
if (ev.num == history_length) |
|
history_base++; |
|
else |
|
history_length = ev.num; |
|
return 0; |
} |
} |
|
|
|
|
Line 1468 clear_history(void) |
|
Line 1559 clear_history(void) |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
|
|
if (h == NULL || e == NULL) |
|
rl_initialize(); |
|
|
(void)history(h, &ev, H_CLEAR); |
(void)history(h, &ev, H_CLEAR); |
history_length = 0; |
history_offset = history_length = 0; |
} |
} |
|
|
|
|
Line 1479 clear_history(void) |
|
Line 1573 clear_history(void) |
|
int |
int |
where_history(void) |
where_history(void) |
{ |
{ |
|
return history_offset; |
|
} |
|
|
|
static HIST_ENTRY **_history_listp; |
|
static HIST_ENTRY *_history_list; |
|
|
|
HIST_ENTRY ** |
|
history_list(void) |
|
{ |
HistEvent ev; |
HistEvent ev; |
int curr_num, off; |
HIST_ENTRY **nlp, *nl; |
|
int i; |
|
|
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_LAST) != 0) |
return 0; |
return NULL; |
curr_num = ev.num; |
|
|
|
(void)history(h, &ev, H_FIRST); |
if ((nlp = el_realloc(_history_listp, |
off = 1; |
(size_t)history_length * sizeof(*nlp))) == NULL) |
while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) |
return NULL; |
off++; |
_history_listp = nlp; |
|
|
return off; |
if ((nl = el_realloc(_history_list, |
} |
(size_t)history_length * sizeof(*nl))) == NULL) |
|
return NULL; |
|
_history_list = nl; |
|
|
|
i = 0; |
|
do { |
|
_history_listp[i] = &_history_list[i]; |
|
_history_list[i].line = ev.str; |
|
_history_list[i].data = NULL; |
|
if (i++ == history_length) |
|
abort(); |
|
} while (history(h, &ev, H_PREV) == 0); |
|
return _history_listp; |
|
} |
|
|
/* |
/* |
* returns current history event or NULL if there is no such event |
* returns current history event or NULL if there is no such event |
Line 1501 where_history(void) |
|
Line 1616 where_history(void) |
|
HIST_ENTRY * |
HIST_ENTRY * |
current_history(void) |
current_history(void) |
{ |
{ |
|
HistEvent ev; |
|
|
|
if (history(h, &ev, H_PREV_EVENT, history_offset + 1) != 0) |
|
return NULL; |
|
|
return _move_history(H_CURR); |
rl_he.line = ev.str; |
|
rl_he.data = NULL; |
|
return &rl_he; |
} |
} |
|
|
|
|
Line 1539 history_total_bytes(void) |
|
Line 1660 history_total_bytes(void) |
|
int |
int |
history_set_pos(int pos) |
history_set_pos(int pos) |
{ |
{ |
HistEvent ev; |
|
int curr_num; |
|
|
|
if (pos >= history_length || pos < 0) |
if (pos >= history_length || pos < 0) |
return -1; |
return 0; |
|
|
(void)history(h, &ev, H_CURR); |
|
curr_num = ev.num; |
|
|
|
/* |
history_offset = pos; |
* use H_DELDATA to set to nth history (without delete) by passing |
return 1; |
* (void **)-1 |
|
*/ |
|
if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { |
|
(void)history(h, &ev, H_SET, curr_num); |
|
return -1; |
|
} |
|
return 0; |
|
} |
} |
|
|
|
|
/* |
/* |
* returns previous event in history and shifts pointer accordingly |
* returns previous event in history and shifts pointer accordingly |
|
* Note that readline and editline define directions in opposite ways. |
*/ |
*/ |
HIST_ENTRY * |
HIST_ENTRY * |
previous_history(void) |
previous_history(void) |
{ |
{ |
|
HistEvent ev; |
|
|
return _move_history(H_PREV); |
if (history_offset == 0) |
|
return NULL; |
|
|
|
if (history(h, &ev, H_LAST) != 0) |
|
return NULL; |
|
|
|
history_offset--; |
|
return current_history(); |
} |
} |
|
|
|
|
Line 1577 previous_history(void) |
|
Line 1694 previous_history(void) |
|
HIST_ENTRY * |
HIST_ENTRY * |
next_history(void) |
next_history(void) |
{ |
{ |
|
HistEvent ev; |
|
|
return _move_history(H_NEXT); |
if (history_offset >= history_length) |
|
return NULL; |
|
|
|
if (history(h, &ev, H_LAST) != 0) |
|
return NULL; |
|
|
|
history_offset++; |
|
return current_history(); |
} |
} |
|
|
|
|
Line 1639 history_search_pos(const char *str, |
|
Line 1764 history_search_pos(const char *str, |
|
return -1; |
return -1; |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) |
if (!history_set_pos(off) || history(h, &ev, H_CURR) != 0) |
return -1; |
return -1; |
|
|
for (;;) { |
for (;;) { |
Line 1677 filename_completion_function(const char |
|
Line 1802 filename_completion_function(const char |
|
* which starts with supplied text |
* which starts with supplied text |
* text contains a partial username preceded by random character |
* text contains a partial username preceded by random character |
* (usually '~'); state resets search from start (??? should we do that anyway) |
* (usually '~'); state resets search from start (??? should we do that anyway) |
* it's callers responsibility to free returned value |
* it's the caller's responsibility to free the returned value |
*/ |
*/ |
char * |
char * |
username_completion_function(const char *text, int state) |
username_completion_function(const char *text, int state) |
Line 1726 _el_rl_tstp(EditLine *el __attribute__(( |
|
Line 1851 _el_rl_tstp(EditLine *el __attribute__(( |
|
return CC_NORM; |
return CC_NORM; |
} |
} |
|
|
/* |
|
* Display list of strings in columnar format on readline's output stream. |
|
* 'matches' is list of strings, 'len' is number of strings in 'matches', |
|
* 'max' is maximum length of string in 'matches'. |
|
*/ |
|
void |
|
rl_display_match_list(char **matches, int len, int max) |
|
{ |
|
|
|
fn_display_match_list(e, matches, (size_t)len, (size_t)max); |
|
} |
|
|
|
static const char * |
static const char * |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
_rl_completion_append_character_function(const char *dummy |
_rl_completion_append_character_function(const char *dummy |
Line 1751 _rl_completion_append_character_function |
|
Line 1864 _rl_completion_append_character_function |
|
|
|
|
|
/* |
/* |
|
* Display list of strings in columnar format on readline's output stream. |
|
* 'matches' is list of strings, 'len' is number of strings in 'matches', |
|
* 'max' is maximum length of string in 'matches'. |
|
*/ |
|
void |
|
rl_display_match_list(char **matches, int len, int max) |
|
{ |
|
|
|
fn_display_match_list(e, matches, (size_t)len, (size_t)max, |
|
_rl_completion_append_character_function); |
|
} |
|
|
|
/* |
* complete word at current point |
* complete word at current point |
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
int |
int |
rl_complete(int ignore __attribute__((__unused__)), int invoking_key) |
rl_complete(int ignore __attribute__((__unused__)), int invoking_key) |
{ |
{ |
#ifdef WIDECHAR |
|
static ct_buffer_t wbreak_conv, sprefix_conv; |
static ct_buffer_t wbreak_conv, sprefix_conv; |
#endif |
|
char *breakchars; |
char *breakchars; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
Line 1778 rl_complete(int ignore __attribute__((__ |
|
Line 1902 rl_complete(int ignore __attribute__((__ |
|
else |
else |
breakchars = rl_basic_word_break_characters; |
breakchars = rl_basic_word_break_characters; |
|
|
|
_rl_update_pos(); |
|
|
/* Just look at how many global variables modify this operation! */ |
/* Just look at how many global variables modify this operation! */ |
return fn_complete(e, |
return fn_complete(e, |
(CPFunction *)rl_completion_entry_function, |
(rl_compentry_func_t *)rl_completion_entry_function, |
rl_attempted_completion_function, |
rl_attempted_completion_function, |
ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), |
ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), |
ct_decode_string(breakchars, &sprefix_conv), |
ct_decode_string(breakchars, &sprefix_conv), |
Line 1909 rl_bind_wrapper(EditLine *el __attribute |
|
Line 2035 rl_bind_wrapper(EditLine *el __attribute |
|
|
|
_rl_update_pos(); |
_rl_update_pos(); |
|
|
(*map[c])(NULL, c); |
(*map[c])(1, c); |
|
|
/* If rl_done was set by the above call, deal with it here */ |
/* If rl_done was set by the above call, deal with it here */ |
if (rl_done) |
if (rl_done) |
Line 1919 rl_bind_wrapper(EditLine *el __attribute |
|
Line 2045 rl_bind_wrapper(EditLine *el __attribute |
|
} |
} |
|
|
int |
int |
rl_add_defun(const char *name, Function *fun, int c) |
rl_add_defun(const char *name, rl_command_func_t *fun, int c) |
{ |
{ |
char dest[8]; |
char dest[8]; |
if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) |
if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) |
Line 1948 rl_callback_read_char(void) |
|
Line 2074 rl_callback_read_char(void) |
|
if (done && rl_linefunc != NULL) { |
if (done && rl_linefunc != NULL) { |
el_set(e, EL_UNBUFFERED, 0); |
el_set(e, EL_UNBUFFERED, 0); |
if (done == 2) { |
if (done == 2) { |
if ((wbuf = strdup(buf)) != NULL) |
if ((wbuf = strdup(buf)) != NULL) |
wbuf[count] = '\0'; |
wbuf[count] = '\0'; |
} else |
} else |
wbuf = NULL; |
wbuf = NULL; |
(*(void (*)(const char *))rl_linefunc)(wbuf); |
(*(void (*)(const char *))rl_linefunc)(wbuf); |
//el_set(e, EL_UNBUFFERED, 1); |
el_set(e, EL_UNBUFFERED, 1); |
} |
} |
} |
} |
|
|
void |
void |
rl_callback_handler_install(const char *prompt, VCPFunction *linefunc) |
rl_callback_handler_install(const char *prompt, rl_vcpfunc_t *linefunc) |
{ |
{ |
if (e == NULL) { |
if (e == NULL) { |
rl_initialize(); |
rl_initialize(); |
Line 1966 rl_callback_handler_install(const char * |
|
Line 2092 rl_callback_handler_install(const char * |
|
(void)rl_set_prompt(prompt); |
(void)rl_set_prompt(prompt); |
rl_linefunc = linefunc; |
rl_linefunc = linefunc; |
el_set(e, EL_UNBUFFERED, 1); |
el_set(e, EL_UNBUFFERED, 1); |
} |
} |
|
|
void |
void |
rl_callback_handler_remove(void) |
rl_callback_handler_remove(void) |
{ |
{ |
el_set(e, EL_UNBUFFERED, 0); |
|
rl_linefunc = NULL; |
rl_linefunc = NULL; |
|
el_end(e); |
|
e = NULL; |
} |
} |
|
|
void |
void |
Line 2049 rl_stuff_char(int c) |
|
Line 2176 rl_stuff_char(int c) |
|
} |
} |
|
|
static int |
static int |
_rl_event_read_char(EditLine *el, char *cp) |
_rl_event_read_char(EditLine *el, wchar_t *wc) |
{ |
{ |
|
char ch; |
int n; |
int n; |
ssize_t num_read = 0; |
ssize_t num_read = 0; |
|
|
*cp = '\0'; |
ch = '\0'; |
|
*wc = L'\0'; |
while (rl_event_hook) { |
while (rl_event_hook) { |
|
|
(*rl_event_hook)(); |
(*rl_event_hook)(); |
Line 2063 _rl_event_read_char(EditLine *el, char * |
|
Line 2192 _rl_event_read_char(EditLine *el, char * |
|
if (ioctl(el->el_infd, FIONREAD, &n) < 0) |
if (ioctl(el->el_infd, FIONREAD, &n) < 0) |
return -1; |
return -1; |
if (n) |
if (n) |
num_read = read(el->el_infd, cp, (size_t)1); |
num_read = read(el->el_infd, &ch, (size_t)1); |
else |
else |
num_read = 0; |
num_read = 0; |
#elif defined(F_SETFL) && defined(O_NDELAY) |
#elif defined(F_SETFL) && defined(O_NDELAY) |
Line 2071 _rl_event_read_char(EditLine *el, char * |
|
Line 2200 _rl_event_read_char(EditLine *el, char * |
|
return -1; |
return -1; |
if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) |
if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) |
return -1; |
return -1; |
num_read = read(el->el_infd, cp, 1); |
num_read = read(el->el_infd, &ch, 1); |
if (fcntl(el->el_infd, F_SETFL, n)) |
if (fcntl(el->el_infd, F_SETFL, n)) |
return -1; |
return -1; |
#else |
#else |
/* not non-blocking, but what you gonna do? */ |
/* not non-blocking, but what you gonna do? */ |
num_read = read(el->el_infd, cp, 1); |
num_read = read(el->el_infd, &ch, 1); |
return -1; |
return -1; |
#endif |
#endif |
|
|
Line 2088 _rl_event_read_char(EditLine *el, char * |
|
Line 2217 _rl_event_read_char(EditLine *el, char * |
|
} |
} |
if (!rl_event_hook) |
if (!rl_event_hook) |
el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); |
el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); |
|
*wc = (wchar_t)ch; |
return (int)num_read; |
return (int)num_read; |
} |
} |
|
|
Line 2150 rl_completion_matches(const char *str, r |
|
Line 2280 rl_completion_matches(const char *str, r |
|
} |
} |
qsort(&list[1], len - 1, sizeof(*list), |
qsort(&list[1], len - 1, sizeof(*list), |
(int (*)(const void *, const void *)) strcmp); |
(int (*)(const void *, const void *)) strcmp); |
min = SIZE_T_MAX; |
min = SIZE_MAX; |
for (i = 1, a = list[i]; i < len - 1; i++, a = b) { |
for (i = 1, a = list[i]; i < len - 1; i++, a = b) { |
b = list[i + 1]; |
b = list[i + 1]; |
for (j = 0; a[j] && a[j] == b[j]; j++) |
for (j = 0; a[j] && a[j] == b[j]; j++) |
Line 2168 rl_completion_matches(const char *str, r |
|
Line 2298 rl_completion_matches(const char *str, r |
|
list[0][min] = '\0'; |
list[0][min] = '\0'; |
} |
} |
return list; |
return list; |
|
|
out: |
out: |
el_free(list); |
el_free(list); |
return NULL; |
return NULL; |
|
|
rl_free_line_state(void) |
rl_free_line_state(void) |
{ |
{ |
} |
} |
|
|
|
int |
|
/*ARGSUSED*/ |
|
rl_set_keyboard_input_timeout(int u __attribute__((__unused__))) |
|
{ |
|
return 0; |
|
} |
|
|
|
void |
|
rl_resize_terminal(void) |
|
{ |
|
el_resize(e); |
|
} |