version 1.41, 2003/11/01 23:39:22 |
version 1.60, 2006/02/13 14:12:04 |
Line 61 __RCSID("$NetBSD$"); |
|
Line 61 __RCSID("$NetBSD$"); |
|
#ifdef HAVE_ALLOCA_H |
#ifdef HAVE_ALLOCA_H |
#include <alloca.h> |
#include <alloca.h> |
#endif |
#endif |
#include "histedit.h" |
|
#include "readline/readline.h" |
|
#include "el.h" |
#include "el.h" |
#include "tokenizer.h" |
|
#include "fcns.h" /* for EL_NUM_FCNS */ |
#include "fcns.h" /* for EL_NUM_FCNS */ |
|
#include "histedit.h" |
|
#include "readline/readline.h" |
|
#include "filecomplete.h" |
|
|
/* for rl_complete() */ |
/* for rl_complete() */ |
#define TAB '\r' |
#define TAB '\r' |
Line 86 FILE *rl_outstream = NULL; |
|
Line 86 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; |
VFunction *rl_linefunc = NULL; |
VCPFunction *rl_linefunc = NULL; |
int rl_done = 0; |
int rl_done = 0; |
VFunction *rl_event_hook = NULL; |
VFunction *rl_event_hook = NULL; |
|
|
Line 142 int rl_completion_query_items = 100; |
|
Line 142 int rl_completion_query_items = 100; |
|
* in the parsed text when it is passed to the completion function. |
* in the parsed text when it is passed to the completion function. |
* Shell uses this to help determine what kind of completing to do. |
* Shell uses this to help determine what kind of completing to do. |
*/ |
*/ |
char *rl_special_prefixes = (char *)NULL; |
char *rl_special_prefixes = NULL; |
|
|
/* |
/* |
* This is the character appended to the completed words if at the end of |
* This is the character appended to the completed words if at the end of |
Line 152 int rl_completion_append_character = ' ' |
|
Line 152 int rl_completion_append_character = ' ' |
|
|
|
/* stuff below is used internally by libedit for readline emulation */ |
/* stuff below is used internally by libedit for readline emulation */ |
|
|
/* if not zero, non-unique completions always show list of possible matches */ |
|
static int _rl_complete_show_all = 0; |
|
|
|
static History *h = NULL; |
static History *h = NULL; |
static EditLine *e = NULL; |
static EditLine *e = NULL; |
static Function *map[256]; |
static Function *map[256]; |
static int el_rl_complete_cmdnum = 0; |
|
|
|
/* 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 char *_get_prompt(EditLine *); |
static char *_get_prompt(EditLine *); |
|
static int _getc_function(EditLine *, char *); |
static HIST_ENTRY *_move_history(int); |
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_complete_internal(int); |
|
static int _rl_qsort_string_compare(const void *, const void *); |
|
static int _rl_event_read_char(EditLine *, char *); |
static int _rl_event_read_char(EditLine *, char *); |
|
static void _rl_update_pos(void); |
|
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
Line 202 _move_history(int op) |
|
Line 199 _move_history(int op) |
|
|
|
|
|
/* |
/* |
|
* read one key from user defined input function |
|
*/ |
|
static int |
|
_getc_function(EditLine *el, char *c) |
|
{ |
|
int i; |
|
|
|
i = (*rl_getc_function)(NULL, 0); |
|
if (i == -1) |
|
return 0; |
|
*c = i; |
|
return 1; |
|
} |
|
|
|
|
|
/* |
* READLINE compatibility stuff |
* READLINE compatibility stuff |
*/ |
*/ |
|
|
Line 213 rl_initialize(void) |
|
Line 226 rl_initialize(void) |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
const LineInfo *li; |
const LineInfo *li; |
int i; |
|
int editmode = 1; |
int editmode = 1; |
struct termios t; |
struct termios t; |
|
|
Line 247 rl_initialize(void) |
|
Line 259 rl_initialize(void) |
|
max_input_history = INT_MAX; |
max_input_history = INT_MAX; |
el_set(e, EL_HIST, history, h); |
el_set(e, EL_HIST, history, h); |
|
|
|
/* setup getc function if valid */ |
|
if (rl_getc_function) |
|
el_set(e, EL_GETCFN, _getc_function); |
|
|
/* for proper prompt printing in readline() */ |
/* for proper prompt printing in readline() */ |
rl_prompt = strdup(""); |
rl_prompt = strdup(""); |
if (rl_prompt == NULL) { |
if (rl_prompt == NULL) { |
Line 273 rl_initialize(void) |
|
Line 289 rl_initialize(void) |
|
"ReadLine compatible completion function", |
"ReadLine compatible completion function", |
_el_rl_complete); |
_el_rl_complete); |
el_set(e, EL_BIND, "^I", "rl_complete", NULL); |
el_set(e, EL_BIND, "^I", "rl_complete", NULL); |
|
|
/* |
/* |
* Find out where the rl_complete function was added; this is |
* Send TSTP when ^Z is pressed. |
* used later to detect that lastcmd was also rl_complete. |
|
*/ |
*/ |
for(i=EL_NUM_FCNS; i < e->el_map.nfunc; i++) { |
el_set(e, EL_ADDFN, "rl_tstp", |
if (e->el_map.func[i] == _el_rl_complete) { |
"ReadLine compatible suspend function", |
el_rl_complete_cmdnum = i; |
_el_rl_tstp); |
break; |
el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); |
} |
|
} |
|
|
|
/* read settings from configuration file */ |
/* read settings from configuration file */ |
el_source(e, NULL); |
el_source(e, NULL); |
Line 294 rl_initialize(void) |
|
Line 308 rl_initialize(void) |
|
li = el_line(e); |
li = el_line(e); |
/* a cheesy way to get rid of const cast. */ |
/* a cheesy way to get rid of const cast. */ |
rl_line_buffer = memchr(li->buffer, *li->buffer, 1); |
rl_line_buffer = memchr(li->buffer, *li->buffer, 1); |
rl_point = rl_end = 0; |
_rl_update_pos(); |
|
|
if (rl_startup_hook) |
if (rl_startup_hook) |
(*rl_startup_hook)(NULL, 0); |
(*rl_startup_hook)(NULL, 0); |
Line 1090 read_history(const char *filename) |
|
Line 1104 read_history(const char *filename) |
|
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
return (history(h, &ev, H_LOAD, filename)); |
return (history(h, &ev, H_LOAD, filename) == -1); |
} |
} |
|
|
|
|
Line 1104 write_history(const char *filename) |
|
Line 1118 write_history(const char *filename) |
|
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
return (history(h, &ev, H_SAVE, filename)); |
return (history(h, &ev, H_SAVE, filename) == -1); |
} |
} |
|
|
|
|
Line 1166 add_history(const char *line) |
|
Line 1180 add_history(const char *line) |
|
|
|
|
|
/* |
/* |
|
* remove the specified entry from the history list and return it. |
|
*/ |
|
HIST_ENTRY * |
|
remove_history(int num) |
|
{ |
|
static HIST_ENTRY she; |
|
HistEvent ev; |
|
|
|
if (h == NULL || e == NULL) |
|
rl_initialize(); |
|
|
|
if (history(h, &ev, H_DEL, num) != 0) |
|
return NULL; |
|
|
|
she.line = ev.str; |
|
she.data = NULL; |
|
|
|
return &she; |
|
} |
|
|
|
|
|
/* |
* clear the history list - delete all entries |
* clear the history list - delete all entries |
*/ |
*/ |
void |
void |
Line 1358 history_search_pos(const char *str, |
|
Line 1394 history_search_pos(const char *str, |
|
/********************************/ |
/********************************/ |
/* completion functions */ |
/* completion functions */ |
|
|
/* |
|
* does tilde expansion of strings of type ``~user/foo'' |
|
* if ``user'' isn't valid user name or ``txt'' doesn't start |
|
* w/ '~', returns pointer to strdup()ed copy of ``txt'' |
|
* |
|
* it's callers's responsibility to free() returned string |
|
*/ |
|
char * |
char * |
tilde_expand(char *txt) |
tilde_expand(char *name) |
{ |
{ |
struct passwd *pass; |
return fn_tilde_expand(name); |
char *temp; |
|
size_t len = 0; |
|
|
|
if (txt[0] != '~') |
|
return (strdup(txt)); |
|
|
|
temp = strchr(txt + 1, '/'); |
|
if (temp == NULL) { |
|
temp = strdup(txt + 1); |
|
if (temp == NULL) |
|
return NULL; |
|
} else { |
|
len = temp - txt + 1; /* text until string after slash */ |
|
temp = malloc(len); |
|
if (temp == NULL) |
|
return NULL; |
|
(void)strncpy(temp, txt + 1, len - 2); |
|
temp[len - 2] = '\0'; |
|
} |
|
pass = getpwnam(temp); |
|
free(temp); /* value no more needed */ |
|
if (pass == NULL) |
|
return (strdup(txt)); |
|
|
|
/* update pointer txt to point at string immedially following */ |
|
/* first slash */ |
|
txt += len; |
|
|
|
temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); |
|
if (temp == NULL) |
|
return NULL; |
|
(void)sprintf(temp, "%s/%s", pass->pw_dir, txt); |
|
|
|
return (temp); |
|
} |
} |
|
|
|
|
/* |
|
* return first found file name starting by the ``text'' or NULL if no |
|
* such file can be found |
|
* value of ``state'' is ignored |
|
* |
|
* it's caller's responsibility to free returned string |
|
*/ |
|
char * |
char * |
filename_completion_function(const char *text, int state) |
filename_completion_function(const char *name, int state) |
{ |
{ |
static DIR *dir = NULL; |
return fn_filename_completion_function(name, state); |
static char *filename = NULL, *dirname = NULL; |
|
static size_t filename_len = 0; |
|
struct dirent *entry; |
|
char *temp; |
|
size_t len; |
|
|
|
if (state == 0 || dir == NULL) { |
|
temp = strrchr(text, '/'); |
|
if (temp) { |
|
char *nptr; |
|
temp++; |
|
nptr = realloc(filename, strlen(temp) + 1); |
|
if (nptr == NULL) { |
|
free(filename); |
|
return NULL; |
|
} |
|
filename = nptr; |
|
(void)strcpy(filename, temp); |
|
len = temp - text; /* including last slash */ |
|
nptr = realloc(dirname, len + 1); |
|
if (nptr == NULL) { |
|
free(filename); |
|
return NULL; |
|
} |
|
dirname = nptr; |
|
(void)strncpy(dirname, text, len); |
|
dirname[len] = '\0'; |
|
} else { |
|
filename = strdup(text); |
|
if (filename == NULL) |
|
return NULL; |
|
dirname = NULL; |
|
} |
|
|
|
/* support for ``~user'' syntax */ |
|
if (dirname && *dirname == '~') { |
|
char *nptr; |
|
temp = tilde_expand(dirname); |
|
if (temp == NULL) |
|
return NULL; |
|
nptr = realloc(dirname, strlen(temp) + 1); |
|
if (nptr == NULL) { |
|
free(dirname); |
|
return NULL; |
|
} |
|
dirname = nptr; |
|
(void)strcpy(dirname, temp); /* safe */ |
|
free(temp); /* no longer needed */ |
|
} |
|
/* will be used in cycle */ |
|
filename_len = strlen(filename); |
|
if (filename_len == 0) |
|
return (NULL); /* no expansion possible */ |
|
|
|
if (dir != NULL) { |
|
(void)closedir(dir); |
|
dir = NULL; |
|
} |
|
dir = opendir(dirname ? dirname : "."); |
|
if (!dir) |
|
return (NULL); /* cannot open the directory */ |
|
} |
|
/* find the match */ |
|
while ((entry = readdir(dir)) != NULL) { |
|
/* otherwise, get first entry where first */ |
|
/* filename_len characters are equal */ |
|
if (entry->d_name[0] == filename[0] |
|
#if defined(__SVR4) || defined(__linux__) |
|
&& strlen(entry->d_name) >= filename_len |
|
#else |
|
&& entry->d_namlen >= filename_len |
|
#endif |
|
&& strncmp(entry->d_name, filename, |
|
filename_len) == 0) |
|
break; |
|
} |
|
|
|
if (entry) { /* match found */ |
|
|
|
struct stat stbuf; |
|
#if defined(__SVR4) || defined(__linux__) |
|
len = strlen(entry->d_name) + |
|
#else |
|
len = entry->d_namlen + |
|
#endif |
|
((dirname) ? strlen(dirname) : 0) + 1 + 1; |
|
temp = malloc(len); |
|
if (temp == NULL) |
|
return NULL; |
|
(void)sprintf(temp, "%s%s", |
|
dirname ? dirname : "", entry->d_name); /* safe */ |
|
|
|
/* test, if it's directory */ |
|
if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) |
|
strcat(temp, "/"); /* safe */ |
|
} else { |
|
(void)closedir(dir); |
|
dir = NULL; |
|
temp = NULL; |
|
} |
|
|
|
return (temp); |
|
} |
} |
|
|
|
|
/* |
/* |
* a completion generator for usernames; returns _first_ username |
* a completion generator for usernames; returns _first_ username |
* which starts with supplied text |
* which starts with supplied text |
Line 1532 filename_completion_function(const char |
|
Line 1416 filename_completion_function(const char |
|
char * |
char * |
username_completion_function(const char *text, int state) |
username_completion_function(const char *text, int state) |
{ |
{ |
struct passwd *pwd; |
struct passwd *pwd, pwres; |
|
char pwbuf[1024]; |
|
|
if (text[0] == '\0') |
if (text[0] == '\0') |
return (NULL); |
return (NULL); |
Line 1543 username_completion_function(const char |
|
Line 1428 username_completion_function(const char |
|
if (state == 0) |
if (state == 0) |
setpwent(); |
setpwent(); |
|
|
while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] |
while (getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pwd) == 0 |
|
&& pwd != NULL && text[0] == pwd->pw_name[0] |
&& strcmp(text, pwd->pw_name) == 0); |
&& strcmp(text, pwd->pw_name) == 0); |
|
|
if (pwd == NULL) { |
if (pwd == NULL) { |
Line 1555 username_completion_function(const char |
|
Line 1441 username_completion_function(const char |
|
|
|
|
|
/* |
/* |
* el-compatible wrapper around rl_complete; needed for key binding |
* el-compatible wrapper to send TSTP on ^Z |
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
static unsigned char |
static unsigned char |
_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) |
_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) |
{ |
|
return (unsigned char) rl_complete(0, ch); |
|
} |
|
|
|
|
|
/* |
|
* returns list of completions for text given |
|
*/ |
|
char ** |
|
completion_matches(const char *text, CPFunction *genfunc) |
|
{ |
{ |
char **match_list = NULL, *retstr, *prevstr; |
(void)kill(0, SIGTSTP); |
size_t match_list_len, max_equal, which, i; |
return CC_NORM; |
size_t matches; |
|
|
|
if (h == NULL || e == NULL) |
|
rl_initialize(); |
|
|
|
matches = 0; |
|
match_list_len = 1; |
|
while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { |
|
/* allow for list terminator here */ |
|
if (matches + 3 >= match_list_len) { |
|
char **nmatch_list; |
|
while (matches + 3 >= match_list_len) |
|
match_list_len <<= 1; |
|
nmatch_list = realloc(match_list, |
|
match_list_len * sizeof(char *)); |
|
if (nmatch_list == NULL) { |
|
free(match_list); |
|
return NULL; |
|
} |
|
match_list = nmatch_list; |
|
|
|
} |
|
match_list[++matches] = retstr; |
|
} |
|
|
|
if (!match_list) |
|
return NULL; /* nothing found */ |
|
|
|
/* find least denominator and insert it to match_list[0] */ |
|
which = 2; |
|
prevstr = match_list[1]; |
|
max_equal = strlen(prevstr); |
|
for (; which <= matches; which++) { |
|
for (i = 0; i < max_equal && |
|
prevstr[i] == match_list[which][i]; i++) |
|
continue; |
|
max_equal = i; |
|
} |
|
|
|
retstr = malloc(max_equal + 1); |
|
if (retstr == NULL) { |
|
free(match_list); |
|
return NULL; |
|
} |
|
(void)strncpy(retstr, match_list[1], max_equal); |
|
retstr[max_equal] = '\0'; |
|
match_list[0] = retstr; |
|
|
|
/* add NULL as last pointer to the array */ |
|
match_list[matches + 1] = (char *) NULL; |
|
|
|
return (match_list); |
|
} |
|
|
|
/* |
|
* Sort function for qsort(). Just wrapper around strcasecmp(). |
|
*/ |
|
static int |
|
_rl_qsort_string_compare(i1, i2) |
|
const void *i1, *i2; |
|
{ |
|
const char *s1 = ((const char * const *)i1)[0]; |
|
const char *s2 = ((const char * const *)i2)[0]; |
|
|
|
return strcasecmp(s1, s2); |
|
} |
} |
|
|
/* |
/* |
Line 1646 _rl_qsort_string_compare(i1, i2) |
|
Line 1457 _rl_qsort_string_compare(i1, i2) |
|
* 'max' is maximum length of string in 'matches'. |
* 'max' is maximum length of string in 'matches'. |
*/ |
*/ |
void |
void |
rl_display_match_list (matches, len, max) |
rl_display_match_list(char **matches, int len, int max) |
char **matches; |
|
int len, max; |
|
{ |
{ |
int i, idx, limit, count; |
|
int screenwidth = e->el_term.t_size.h; |
|
|
|
/* |
fn_display_match_list(e, matches, len, max); |
* Find out how many entries can be put on one line, count |
|
* with two spaces between strings. |
|
*/ |
|
limit = screenwidth / (max + 2); |
|
if (limit == 0) |
|
limit = 1; |
|
|
|
/* how many lines of output */ |
|
count = len / limit; |
|
if (count * limit < len) |
|
count++; |
|
|
|
/* Sort the items if they are not already sorted. */ |
|
qsort(&matches[1], (size_t)(len - 1), sizeof(char *), |
|
_rl_qsort_string_compare); |
|
|
|
idx = 1; |
|
for(; count > 0; count--) { |
|
for(i = 0; i < limit && matches[idx]; i++, idx++) |
|
(void)fprintf(e->el_outfile, "%-*s ", max, |
|
matches[idx]); |
|
(void)fprintf(e->el_outfile, "\n"); |
|
} |
|
} |
} |
|
|
/* |
static const char * |
* Complete the word at or before point, called by rl_complete() |
/*ARGSUSED*/ |
* 'what_to_do' says what to do with the completion. |
_rl_completion_append_character_function(const char *dummy |
* `?' means list the possible completions. |
__attribute__((__unused__))) |
* TAB means do standard completion. |
|
* `*' means insert all of the possible completions. |
|
* `!' means to do standard completion, and list all possible completions if |
|
* there is more than one. |
|
* |
|
* Note: '*' support is not implemented |
|
*/ |
|
static int |
|
rl_complete_internal(int what_to_do) |
|
{ |
{ |
Function *complet_func; |
static char buf[2]; |
const LineInfo *li; |
buf[1] = rl_completion_append_character; |
char *temp, **matches; |
return buf; |
const char *ctemp; |
|
size_t len; |
|
|
|
rl_completion_type = what_to_do; |
|
|
|
if (h == NULL || e == NULL) |
|
rl_initialize(); |
|
|
|
complet_func = rl_completion_entry_function; |
|
if (!complet_func) |
|
complet_func = (Function *)(void *)filename_completion_function; |
|
|
|
/* We now look backwards for the start of a filename/variable word */ |
|
li = el_line(e); |
|
ctemp = (const char *) li->cursor; |
|
while (ctemp > li->buffer |
|
&& !strchr(rl_basic_word_break_characters, ctemp[-1]) |
|
&& (!rl_special_prefixes |
|
|| !strchr(rl_special_prefixes, ctemp[-1]) ) ) |
|
ctemp--; |
|
|
|
len = li->cursor - ctemp; |
|
temp = alloca(len + 1); |
|
(void)strncpy(temp, ctemp, len); |
|
temp[len] = '\0'; |
|
|
|
/* these can be used by function called in completion_matches() */ |
|
/* or (*rl_attempted_completion_function)() */ |
|
rl_point = li->cursor - li->buffer; |
|
rl_end = li->lastchar - li->buffer; |
|
|
|
if (!rl_attempted_completion_function) |
|
matches = completion_matches(temp, (CPFunction *)complet_func); |
|
else { |
|
int end = li->cursor - li->buffer; |
|
matches = (*rl_attempted_completion_function) (temp, (int) |
|
(end - len), end); |
|
} |
|
|
|
if (matches) { |
|
int i, retval = CC_REFRESH; |
|
int matches_num, maxlen, match_len, match_display=1; |
|
|
|
/* |
|
* Only replace the completed string with common part of |
|
* possible matches if there is possible completion. |
|
*/ |
|
if (matches[0][0] != '\0') { |
|
el_deletestr(e, (int) len); |
|
el_insertstr(e, matches[0]); |
|
} |
|
|
|
if (what_to_do == '?') |
|
goto display_matches; |
|
|
|
if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { |
|
/* |
|
* We found exact match. Add a space after |
|
* it, unless we do filename completion and the |
|
* object is a directory. |
|
*/ |
|
size_t alen = strlen(matches[0]); |
|
if ((complet_func != |
|
(Function *)filename_completion_function |
|
|| (alen > 0 && (matches[0])[alen - 1] != '/')) |
|
&& rl_completion_append_character) { |
|
char buf[2]; |
|
buf[0] = rl_completion_append_character; |
|
buf[1] = '\0'; |
|
el_insertstr(e, buf); |
|
} |
|
} else if (what_to_do == '!') { |
|
display_matches: |
|
/* |
|
* More than one match and requested to list possible |
|
* matches. |
|
*/ |
|
|
|
for(i=1, maxlen=0; matches[i]; i++) { |
|
match_len = strlen(matches[i]); |
|
if (match_len > maxlen) |
|
maxlen = match_len; |
|
} |
|
matches_num = i - 1; |
|
|
|
/* newline to get on next line from command line */ |
|
(void)fprintf(e->el_outfile, "\n"); |
|
|
|
/* |
|
* If there are too many items, ask user for display |
|
* confirmation. |
|
*/ |
|
if (matches_num > rl_completion_query_items) { |
|
(void)fprintf(e->el_outfile, |
|
"Display all %d possibilities? (y or n) ", |
|
matches_num); |
|
(void)fflush(e->el_outfile); |
|
if (getc(stdin) != 'y') |
|
match_display = 0; |
|
(void)fprintf(e->el_outfile, "\n"); |
|
} |
|
|
|
if (match_display) |
|
rl_display_match_list(matches, matches_num, |
|
maxlen); |
|
retval = CC_REDISPLAY; |
|
} else if (matches[0][0]) { |
|
/* |
|
* There was some common match, but the name was |
|
* not complete enough. Next tab will print possible |
|
* completions. |
|
*/ |
|
el_beep(e); |
|
} else { |
|
/* lcd is not a valid object - further specification */ |
|
/* is needed */ |
|
el_beep(e); |
|
retval = CC_NORM; |
|
} |
|
|
|
/* free elements of array and the array itself */ |
|
for (i = 0; matches[i]; i++) |
|
free(matches[i]); |
|
free(matches), matches = NULL; |
|
|
|
return (retval); |
|
} |
|
return (CC_NORM); |
|
} |
} |
|
|
|
|
/* |
/* |
* complete word at current point |
* complete word at current point |
*/ |
*/ |
|
/* ARGSUSED */ |
int |
int |
rl_complete(int ignore, int invoking_key) |
rl_complete(int ignore __attribute__((__unused__)), int invoking_key) |
{ |
{ |
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
if (rl_inhibit_completion) { |
if (rl_inhibit_completion) { |
rl_insert(ignore, invoking_key); |
char arr[2]; |
|
arr[0] = (char)invoking_key; |
|
arr[1] = '\0'; |
|
el_insertstr(e, arr); |
return (CC_REFRESH); |
return (CC_REFRESH); |
} else if (e->el_state.lastcmd == el_rl_complete_cmdnum) |
} |
return rl_complete_internal('?'); |
|
else if (_rl_complete_show_all) |
/* Just look at how many global variables modify this operation! */ |
return rl_complete_internal('!'); |
return fn_complete(e, |
else |
(CPFunction *)rl_completion_entry_function, |
return (rl_complete_internal(TAB)); |
rl_attempted_completion_function, |
|
rl_basic_word_break_characters, rl_special_prefixes, |
|
_rl_completion_append_character_function, rl_completion_query_items, |
|
&rl_completion_type, &rl_attempted_completion_over, |
|
&rl_point, &rl_end); |
} |
} |
|
|
|
|
|
/* ARGSUSED */ |
|
static unsigned char |
|
_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) |
|
{ |
|
return (unsigned char)rl_complete(0, ch); |
|
} |
|
|
/* |
/* |
* misc other functions |
* misc other functions |
*/ |
*/ |
Line 1939 rl_bind_wrapper(EditLine *el, unsigned c |
|
Line 1601 rl_bind_wrapper(EditLine *el, unsigned c |
|
{ |
{ |
if (map[c] == NULL) |
if (map[c] == NULL) |
return CC_ERROR; |
return CC_ERROR; |
|
|
|
_rl_update_pos(); |
|
|
(*map[c])(NULL, c); |
(*map[c])(NULL, 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 */ |
Line 1983 rl_callback_read_char() |
|
Line 1648 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); |
} |
} |
} |
} |
|
|
void |
void |
rl_callback_handler_install (const char *prompt, VFunction *linefunc) |
rl_callback_handler_install (const char *prompt, VCPFunction *linefunc) |
{ |
{ |
if (e == NULL) { |
if (e == NULL) { |
rl_initialize(); |
rl_initialize(); |
Line 2052 rl_parse_and_bind(const char *line) |
|
Line 1718 rl_parse_and_bind(const char *line) |
|
Tokenizer *tok; |
Tokenizer *tok; |
|
|
tok = tok_init(NULL); |
tok = tok_init(NULL); |
tok_line(tok, line, &argc, &argv); |
tok_str(tok, line, &argc, &argv); |
argc = el_parse(e, argc, argv); |
argc = el_parse(e, argc, argv); |
tok_end(tok); |
tok_end(tok); |
return (argc ? 1 : 0); |
return (argc ? 1 : 0); |
} |
} |
|
|
|
int |
|
rl_variable_bind(const char *var, const char *value) |
|
{ |
|
/* |
|
* The proper return value is undocument, but this is what the |
|
* readline source seems to do. |
|
*/ |
|
return ((el_set(e, EL_BIND, "", var, value) == -1) ? 1 : 0); |
|
} |
|
|
void |
void |
rl_stuff_char(int c) |
rl_stuff_char(int c) |
{ |
{ |
Line 2071 rl_stuff_char(int c) |
|
Line 1747 rl_stuff_char(int c) |
|
static int |
static int |
_rl_event_read_char(EditLine *el, char *cp) |
_rl_event_read_char(EditLine *el, char *cp) |
{ |
{ |
int n, num_read; |
int n, num_read = 0; |
|
|
*cp = 0; |
*cp = 0; |
while (rl_event_hook) { |
while (rl_event_hook) { |
Line 2109 _rl_event_read_char(EditLine *el, char * |
|
Line 1785 _rl_event_read_char(EditLine *el, char * |
|
el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); |
el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); |
return(num_read); |
return(num_read); |
} |
} |
|
|
|
static void |
|
_rl_update_pos(void) |
|
{ |
|
const LineInfo *li = el_line(e); |
|
|
|
rl_point = li->cursor - li->buffer; |
|
rl_end = li->lastchar - li->buffer; |
|
} |