version 1.99, 2011/08/16 16:25:15 |
version 1.125, 2016/02/17 19:47:49 |
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 "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 77 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; |
VFunction *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; |
Line 99 int rl_attempted_completion_over = 0; |
|
Line 106 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; |
CPPFunction *rl_attempted_completion_function = NULL; |
char *(*rl_completion_word_break_hook)(void) = 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 108 char *rl_terminal_name = NULL; |
|
Line 116 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; |
Line 152 int rl_completion_append_character = ' ' |
|
Line 159 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 */ |
Line 228 static const char * |
|
Line 235 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 252 rl_set_prompt(const char *prompt) |
|
Line 266 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 323 rl_initialize(void) |
|
Line 337 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 346 rl_initialize(void) |
|
Line 360 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 619 get_history_event(const char *cmd, int * |
|
Line 664 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, |
Line 887 history_expand(char *str, char **output) |
|
Line 932 history_expand(char *str, char **output) |
|
*output = NULL; |
*output = NULL; |
if (str[0] == history_subst_char) { |
if (str[0] == history_subst_char) { |
/* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ |
/* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ |
*output = el_malloc((strlen(str) + 4 + 1) * sizeof(*output)); |
*output = el_malloc((strlen(str) + 4 + 1) * sizeof(**output)); |
if (*output == NULL) |
if (*output == NULL) |
return 0; |
return 0; |
(*output)[0] = (*output)[1] = history_expansion_char; |
(*output)[0] = (*output)[1] = history_expansion_char; |
|
|
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) { |
Line 1371 add_history(const char *line) |
|
Line 1417 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(); |
|
|
Line 1464 clear_history(void) |
|
Line 1513 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_length = 0; |
} |
} |
Line 1673 filename_completion_function(const char |
|
Line 1725 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 1756 rl_complete(int ignore __attribute__((__ |
|
Line 1808 rl_complete(int ignore __attribute__((__ |
|
#ifdef WIDECHAR |
#ifdef WIDECHAR |
static ct_buffer_t wbreak_conv, sprefix_conv; |
static ct_buffer_t wbreak_conv, sprefix_conv; |
#endif |
#endif |
|
char *breakchars; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
Line 1768 rl_complete(int ignore __attribute__((__ |
|
Line 1821 rl_complete(int ignore __attribute__((__ |
|
return CC_REFRESH; |
return CC_REFRESH; |
} |
} |
|
|
|
if (rl_completion_word_break_hook != NULL) |
|
breakchars = (*rl_completion_word_break_hook)(); |
|
else |
|
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(rl_special_prefixes, &sprefix_conv), |
ct_decode_string(breakchars, &sprefix_conv), |
_rl_completion_append_character_function, |
_rl_completion_append_character_function, |
(size_t)rl_completion_query_items, |
(size_t)rl_completion_query_items, |
&rl_completion_type, &rl_attempted_completion_over, |
&rl_completion_type, &rl_attempted_completion_over, |
Line 1899 rl_bind_wrapper(EditLine *el __attribute |
|
Line 1959 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 1909 rl_bind_wrapper(EditLine *el __attribute |
|
Line 1969 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 1917 rl_add_defun(const char *name, Function |
|
Line 1977 rl_add_defun(const char *name, Function |
|
map[(unsigned char)c] = fun; |
map[(unsigned char)c] = fun; |
el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); |
el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); |
vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); |
vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); |
el_set(e, EL_BIND, dest, name); |
el_set(e, EL_BIND, dest, name, NULL); |
return 0; |
return 0; |
} |
} |
|
|
void |
void |
rl_callback_read_char() |
rl_callback_read_char(void) |
{ |
{ |
int count = 0, done = 0; |
int count = 0, done = 0; |
const char *buf = el_gets(e, &count); |
const char *buf = el_gets(e, &count); |
Line 1943 rl_callback_read_char() |
|
Line 2003 rl_callback_read_char() |
|
} 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 1956 rl_callback_handler_install(const char * |
|
Line 2016 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); |
el_set(e, EL_UNBUFFERED, 0); |
Line 2025 rl_variable_bind(const char *var, const |
|
Line 2085 rl_variable_bind(const char *var, const |
|
* The proper return value is undocument, but this is what the |
* The proper return value is undocument, but this is what the |
* readline source seems to do. |
* readline source seems to do. |
*/ |
*/ |
return el_set(e, EL_BIND, "", var, value) == -1 ? 1 : 0; |
return el_set(e, EL_BIND, "", var, value, NULL) == -1 ? 1 : 0; |
} |
} |
|
|
void |
void |
|
|
rl_get_screen_size(int *rows, int *cols) |
rl_get_screen_size(int *rows, int *cols) |
{ |
{ |
if (rows) |
if (rows) |
el_get(e, EL_GETTC, "li", rows); |
el_get(e, EL_GETTC, "li", rows, (void *)0); |
if (cols) |
if (cols) |
el_get(e, EL_GETTC, "co", cols); |
el_get(e, EL_GETTC, "co", cols, (void *)0); |
} |
} |
|
|
void |
void |
Line 2104 rl_set_screen_size(int rows, int cols) |
|
Line 2164 rl_set_screen_size(int rows, int cols) |
|
{ |
{ |
char buf[64]; |
char buf[64]; |
(void)snprintf(buf, sizeof(buf), "%d", rows); |
(void)snprintf(buf, sizeof(buf), "%d", rows); |
el_set(e, EL_SETTC, "li", buf); |
el_set(e, EL_SETTC, "li", buf, NULL); |
(void)snprintf(buf, sizeof(buf), "%d", cols); |
(void)snprintf(buf, sizeof(buf), "%d", cols); |
el_set(e, EL_SETTC, "co", buf); |
el_set(e, EL_SETTC, "co", buf, NULL); |
} |
} |
|
|
char ** |
char ** |
Line 2140 rl_completion_matches(const char *str, r |
|
Line 2200 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 2158 rl_completion_matches(const char *str, r |
|
Line 2218 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; |
Line 2257 rl_on_new_line(void) |
|
Line 2317 rl_on_new_line(void) |
|
{ |
{ |
return 0; |
return 0; |
} |
} |
|
|
|
void |
|
rl_free_line_state(void) |
|
{ |
|
} |
|
|
|
int |
|
/*ARGSUSED*/ |
|
rl_set_keyboard_input_timeout(int u __attribute__((__unused__))) |
|
{ |
|
return 0; |
|
} |