version 1.52, 2005/04/19 03:29:18 |
version 1.85, 2009/09/07 21:24:33 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by the NetBSD |
|
* Foundation, Inc. and its contributors. |
|
* 4. Neither the name of The NetBSD Foundation nor the names of its |
|
* contributors may be used to endorse or promote products derived |
|
* from this software without specific prior written permission. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
Line 53 __RCSID("$NetBSD$"); |
|
Line 46 __RCSID("$NetBSD$"); |
|
#include <limits.h> |
#include <limits.h> |
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
|
#include <setjmp.h> |
#ifdef HAVE_VIS_H |
#ifdef HAVE_VIS_H |
#include <vis.h> |
#include <vis.h> |
#else |
#else |
#include "np/vis.h" |
#include "np/vis.h" |
#endif |
#endif |
#ifdef HAVE_ALLOCA_H |
#include "readline/readline.h" |
#include <alloca.h> |
|
#endif |
|
#include "el.h" |
#include "el.h" |
#include "fcns.h" /* for EL_NUM_FCNS */ |
#include "fcns.h" /* for EL_NUM_FCNS */ |
#include "histedit.h" |
#include "histedit.h" |
#include "readline/readline.h" |
#include "filecomplete.h" |
|
|
|
void rl_prep_terminal(int); |
|
void rl_deprep_terminal(void); |
|
|
/* for rl_complete() */ |
/* for rl_complete() */ |
#define TAB '\r' |
#define TAB '\r' |
Line 75 __RCSID("$NetBSD$"); |
|
Line 70 __RCSID("$NetBSD$"); |
|
/* readline compatibility stuff - look at readline sources/documentation */ |
/* readline compatibility stuff - look at readline sources/documentation */ |
/* to see what these variables mean */ |
/* to see what these variables mean */ |
const char *rl_library_version = "EditLine wrapper"; |
const char *rl_library_version = "EditLine wrapper"; |
|
int rl_readline_version = RL_READLINE_VERSION; |
static char empty[] = { '\0' }; |
static char empty[] = { '\0' }; |
static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; |
static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; |
static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', |
static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', |
Line 85 FILE *rl_outstream = NULL; |
|
Line 81 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; |
|
KEYMAP_ENTRY_ARRAY emacs_standard_keymap, |
|
emacs_meta_keymap, |
|
emacs_ctlx_keymap; |
|
|
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 107 Function *rl_completion_entry_function = |
|
Line 106 Function *rl_completion_entry_function = |
|
CPPFunction *rl_attempted_completion_function = NULL; |
CPPFunction *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; |
Function *rl_getc_function = NULL; |
int (*rl_getc_function)(FILE *) = NULL; |
char *rl_terminal_name = NULL; |
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 rl_catch_signals = 1; |
|
int readline_echoing_p = 1; |
|
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; |
VFunction *rl_completion_display_matches_hook = NULL; |
VFunction *rl_completion_display_matches_hook = NULL; |
VFunction *rl_prep_term_function = NULL; |
VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; |
VFunction *rl_deprep_term_function = NULL; |
VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; |
|
KEYMAP_ENTRY_ARRAY emacs_meta_keymap; |
|
|
/* |
/* |
* The current prompt string. |
* The current prompt string. |
Line 141 int rl_completion_query_items = 100; |
|
Line 143 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 151 int rl_completion_append_character = ' ' |
|
Line 153 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; |
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 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); |
static void _rl_update_pos(void); |
|
|
Line 203 _move_history(int op) |
|
Line 201 _move_history(int op) |
|
|
|
|
|
/* |
/* |
|
* read one key from user defined input function |
|
*/ |
|
static int |
|
/*ARGSUSED*/ |
|
_getc_function(EditLine *el, char *c) |
|
{ |
|
int i; |
|
|
|
i = (*rl_getc_function)(NULL); |
|
if (i == -1) |
|
return 0; |
|
*c = i; |
|
return 1; |
|
} |
|
|
|
static const char _dothistory[] = "/.history"; |
|
|
|
static const char * |
|
_default_history_file(void) |
|
{ |
|
struct passwd *p; |
|
static char path[PATH_MAX]; |
|
|
|
if (*path) |
|
return path; |
|
if ((p = getpwuid(getuid())) == NULL) |
|
return NULL; |
|
strlcpy(path, p->pw_dir, PATH_MAX); |
|
strlcat(path, _dothistory, PATH_MAX); |
|
return path; |
|
} |
|
|
|
/* |
* READLINE compatibility stuff |
* READLINE compatibility stuff |
*/ |
*/ |
|
|
/* |
/* |
|
* Set the prompt |
|
*/ |
|
int |
|
rl_set_prompt(const char *prompt) |
|
{ |
|
char *p; |
|
|
|
if (!prompt) |
|
prompt = ""; |
|
if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) |
|
return 0; |
|
if (rl_prompt) |
|
free(rl_prompt); |
|
rl_prompt = strdup(prompt); |
|
if (rl_prompt == NULL) |
|
return -1; |
|
|
|
while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) |
|
*p = RL_PROMPT_START_IGNORE; |
|
|
|
return 0; |
|
} |
|
|
|
/* |
* initialize rl compat stuff |
* initialize rl compat stuff |
*/ |
*/ |
int |
int |
Line 214 rl_initialize(void) |
|
Line 269 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 248 rl_initialize(void) |
|
Line 302 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(""); |
if (rl_set_prompt("") == -1) { |
if (rl_prompt == NULL) { |
|
history_end(h); |
history_end(h); |
el_end(e); |
el_end(e); |
return -1; |
return -1; |
} |
} |
el_set(e, EL_PROMPT, _get_prompt); |
el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); |
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 */ |
Line 282 rl_initialize(void) |
|
Line 339 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); |
|
|
/* |
|
* Find out where the rl_complete function was added; this is |
|
* used later to detect that lastcmd was also rl_complete. |
|
*/ |
|
for(i=EL_NUM_FCNS; i < e->el_map.nfunc; i++) { |
|
if (e->el_map.func[i] == _el_rl_complete) { |
|
el_rl_complete_cmdnum = i; |
|
break; |
|
} |
|
} |
|
|
|
/* read settings from configuration file */ |
/* read settings from configuration file */ |
el_source(e, NULL); |
el_source(e, NULL); |
Line 318 rl_initialize(void) |
|
Line 364 rl_initialize(void) |
|
* trailing newline (if there is any) |
* trailing newline (if there is any) |
*/ |
*/ |
char * |
char * |
readline(const char *prompt) |
readline(const char *p) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
const char * volatile prompt = p; |
int count; |
int count; |
const char *ret; |
const char *ret; |
char *buf; |
char *buf; |
Line 331 readline(const char *prompt) |
|
Line 378 readline(const char *prompt) |
|
|
|
rl_done = 0; |
rl_done = 0; |
|
|
|
(void)setjmp(topbuf); |
|
|
/* update prompt accordingly to what has been passed */ |
/* update prompt accordingly to what has been passed */ |
if (!prompt) |
if (rl_set_prompt(prompt) == -1) |
prompt = ""; |
return NULL; |
if (strcmp(rl_prompt, prompt) != 0) { |
|
free(rl_prompt); |
|
rl_prompt = strdup(prompt); |
|
if (rl_prompt == NULL) |
|
return NULL; |
|
} |
|
|
|
if (rl_pre_input_hook) |
if (rl_pre_input_hook) |
(*rl_pre_input_hook)(NULL, 0); |
(*rl_pre_input_hook)(NULL, 0); |
Line 437 _rl_compat_sub(const char *str, const ch |
|
Line 480 _rl_compat_sub(const char *str, const ch |
|
} else |
} else |
*r++ = *s++; |
*r++ = *s++; |
} |
} |
*r = 0; |
*r = '\0'; |
return(result); |
return(result); |
} |
} |
|
|
Line 458 get_history_event(const char *cmd, int * |
|
Line 501 get_history_event(const char *cmd, int * |
|
return(NULL); |
return(NULL); |
|
|
/* find out which event to take */ |
/* find out which event to take */ |
if (cmd[idx] == history_expansion_char || cmd[idx] == 0) { |
if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') { |
if (history(h, &ev, H_FIRST) != 0) |
if (history(h, &ev, H_FIRST) != 0) |
return(NULL); |
return(NULL); |
*cindex = cmd[idx]? (idx + 1):idx; |
*cindex = cmd[idx]? (idx + 1):idx; |
Line 623 _history_expand_command(const char *comm |
|
Line 666 _history_expand_command(const char *comm |
|
return(-1); |
return(-1); |
|
|
if (!has_mods) { |
if (!has_mods) { |
*result = strdup(aptr? aptr : ptr); |
*result = strdup(aptr ? aptr : ptr); |
if (aptr) |
if (aptr) |
free(aptr); |
free(aptr); |
|
if (*result == NULL) |
|
return -1; |
return(1); |
return(1); |
} |
} |
|
|
Line 680 _history_expand_command(const char *comm |
|
Line 725 _history_expand_command(const char *comm |
|
if (aptr) |
if (aptr) |
free(aptr); |
free(aptr); |
|
|
if (*cmd == 0 || (cmd - (command + offs) >= cmdlen)) { |
if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) { |
*result = tmp; |
*result = tmp; |
return(1); |
return(1); |
} |
} |
Line 690 _history_expand_command(const char *comm |
|
Line 735 _history_expand_command(const char *comm |
|
continue; |
continue; |
else if (*cmd == 'h') { /* remove trailing path */ |
else if (*cmd == 'h') { /* remove trailing path */ |
if ((aptr = strrchr(tmp, '/')) != NULL) |
if ((aptr = strrchr(tmp, '/')) != NULL) |
*aptr = 0; |
*aptr = '\0'; |
} else if (*cmd == 't') { /* remove leading path */ |
} else if (*cmd == 't') { /* remove leading path */ |
if ((aptr = strrchr(tmp, '/')) != NULL) { |
if ((aptr = strrchr(tmp, '/')) != NULL) { |
aptr = strdup(aptr + 1); |
aptr = strdup(aptr + 1); |
Line 699 _history_expand_command(const char *comm |
|
Line 744 _history_expand_command(const char *comm |
|
} |
} |
} else if (*cmd == 'r') { /* remove trailing suffix */ |
} else if (*cmd == 'r') { /* remove trailing suffix */ |
if ((aptr = strrchr(tmp, '.')) != NULL) |
if ((aptr = strrchr(tmp, '.')) != NULL) |
*aptr = 0; |
*aptr = '\0'; |
} else if (*cmd == 'e') { /* remove all but suffix */ |
} else if (*cmd == 'e') { /* remove all but suffix */ |
if ((aptr = strrchr(tmp, '.')) != NULL) { |
if ((aptr = strrchr(tmp, '.')) != NULL) { |
aptr = strdup(aptr); |
aptr = strdup(aptr); |
Line 723 _history_expand_command(const char *comm |
|
Line 768 _history_expand_command(const char *comm |
|
what = realloc(from, size); |
what = realloc(from, size); |
if (what == NULL) { |
if (what == NULL) { |
free(from); |
free(from); |
|
free(tmp); |
return 0; |
return 0; |
} |
} |
len = 0; |
len = 0; |
Line 735 _history_expand_command(const char *comm |
|
Line 781 _history_expand_command(const char *comm |
|
(size <<= 1)); |
(size <<= 1)); |
if (nwhat == NULL) { |
if (nwhat == NULL) { |
free(what); |
free(what); |
|
free(tmp); |
return 0; |
return 0; |
} |
} |
what = nwhat; |
what = nwhat; |
Line 747 _history_expand_command(const char *comm |
|
Line 794 _history_expand_command(const char *comm |
|
free(what); |
free(what); |
if (search) { |
if (search) { |
from = strdup(search); |
from = strdup(search); |
if (from == NULL) |
if (from == NULL) { |
|
free(tmp); |
return 0; |
return 0; |
|
} |
} else { |
} else { |
from = NULL; |
from = NULL; |
|
free(tmp); |
return (-1); |
return (-1); |
} |
} |
} |
} |
Line 762 _history_expand_command(const char *comm |
|
Line 812 _history_expand_command(const char *comm |
|
with = realloc(to, size); |
with = realloc(to, size); |
if (with == NULL) { |
if (with == NULL) { |
free(to); |
free(to); |
|
free(tmp); |
return -1; |
return -1; |
} |
} |
len = 0; |
len = 0; |
Line 773 _history_expand_command(const char *comm |
|
Line 824 _history_expand_command(const char *comm |
|
nwith = realloc(with, size); |
nwith = realloc(with, size); |
if (nwith == NULL) { |
if (nwith == NULL) { |
free(with); |
free(with); |
|
free(tmp); |
return -1; |
return -1; |
} |
} |
with = nwith; |
with = nwith; |
Line 841 history_expand(char *str, char **output) |
|
Line 893 history_expand(char *str, char **output) |
|
return 0; |
return 0; |
} |
} |
|
|
#define ADD_STRING(what, len) \ |
#define ADD_STRING(what, len, fr) \ |
{ \ |
{ \ |
if (idx + len + 1 > size) { \ |
if (idx + len + 1 > size) { \ |
char *nresult = realloc(result, (size += len + 1));\ |
char *nresult = realloc(result, (size += len + 1));\ |
if (nresult == NULL) { \ |
if (nresult == NULL) { \ |
free(*output); \ |
free(*output); \ |
|
if (/*CONSTCOND*/fr) \ |
|
free(tmp); \ |
return 0; \ |
return 0; \ |
} \ |
} \ |
result = nresult; \ |
result = nresult; \ |
Line 858 history_expand(char *str, char **output) |
|
Line 912 history_expand(char *str, char **output) |
|
|
|
result = NULL; |
result = NULL; |
size = idx = 0; |
size = idx = 0; |
|
tmp = NULL; |
for (i = 0; str[i];) { |
for (i = 0; str[i];) { |
int qchar, loop_again; |
int qchar, loop_again; |
size_t len, start, j; |
size_t len, start, j; |
|
|
goto loop; |
goto loop; |
} |
} |
len = i - start; |
len = i - start; |
tmp = &str[start]; |
ADD_STRING(&str[start], len, 0); |
ADD_STRING(tmp, len); |
|
|
|
if (str[i] == '\0' || str[i] != history_expansion_char) { |
if (str[i] == '\0' || str[i] != history_expansion_char) { |
len = j - i; |
len = j - i; |
tmp = &str[i]; |
ADD_STRING(&str[i], len, 0); |
ADD_STRING(tmp, len); |
|
if (start == 0) |
if (start == 0) |
ret = 0; |
ret = 0; |
else |
else |
|
|
ret = _history_expand_command (str, i, (j - i), &tmp); |
ret = _history_expand_command (str, i, (j - i), &tmp); |
if (ret > 0 && tmp) { |
if (ret > 0 && tmp) { |
len = strlen(tmp); |
len = strlen(tmp); |
ADD_STRING(tmp, len); |
ADD_STRING(tmp, len, 1); |
|
} |
|
if (tmp) { |
free(tmp); |
free(tmp); |
|
tmp = NULL; |
} |
} |
i = j; |
i = j; |
} |
} |
|
|
history_arg_extract(int start, int end, const char *str) |
history_arg_extract(int start, int end, const char *str) |
{ |
{ |
size_t i, len, max; |
size_t i, len, max; |
char **arr, *result; |
char **arr, *result = NULL; |
|
|
arr = history_tokenize(str); |
arr = history_tokenize(str); |
if (!arr) |
if (!arr) |
return(NULL); |
return NULL; |
if (arr && *arr == NULL) { |
if (arr && *arr == NULL) |
free(arr); |
goto out; |
return(NULL); |
|
} |
|
|
|
for (max = 0; arr[max]; max++) |
for (max = 0; arr[max]; max++) |
continue; |
continue; |
max--; |
max--; |
|
|
if (start == '$') |
if (start == '$') |
start = max; |
start = (int)max; |
if (end == '$') |
if (end == '$') |
end = max; |
end = (int)max; |
if (end < 0) |
if (end < 0) |
end = max + end + 1; |
end = (int)max + end + 1; |
if (start < 0) |
if (start < 0) |
start = end; |
start = end; |
|
|
if (start < 0 || end < 0 || start > max || end > max || start > end) |
if (start < 0 || end < 0 || (size_t)start > max || |
return(NULL); |
(size_t)end > max || start > end) |
|
goto out; |
|
|
for (i = start, len = 0; i <= end; i++) |
for (i = start, len = 0; i <= (size_t)end; i++) |
len += strlen(arr[i]) + 1; |
len += strlen(arr[i]) + 1; |
len++; |
len++; |
result = malloc(len); |
result = malloc(len); |
if (result == NULL) |
if (result == NULL) |
return NULL; |
goto out; |
|
|
for (i = start, len = 0; i <= end; i++) { |
for (i = start, len = 0; i <= (size_t)end; i++) { |
(void)strcpy(result + len, arr[i]); |
(void)strcpy(result + len, arr[i]); |
len += strlen(arr[i]); |
len += strlen(arr[i]); |
if (i < end) |
if (i < (size_t)end) |
result[len++] = ' '; |
result[len++] = ' '; |
} |
} |
result[len] = 0; |
result[len] = '\0'; |
|
|
|
out: |
for (i = 0; arr[i]; i++) |
for (i = 0; arr[i]; i++) |
free(arr[i]); |
free(arr[i]); |
free(arr); |
free(arr); |
|
|
return(result); |
return result; |
} |
} |
|
|
/* |
/* |
Line 1089 history_is_stifled(void) |
|
Line 1145 history_is_stifled(void) |
|
return (max_input_history != INT_MAX); |
return (max_input_history != INT_MAX); |
} |
} |
|
|
|
static const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; |
|
|
|
int |
|
history_truncate_file (const char *filename, int nlines) |
|
{ |
|
int ret = 0; |
|
FILE *fp, *tp; |
|
char template[sizeof(_history_tmp_template)]; |
|
char buf[4096]; |
|
int fd; |
|
char *cp; |
|
off_t off; |
|
int count = 0; |
|
ssize_t left = 0; |
|
|
|
if (filename == NULL && (filename = _default_history_file()) == NULL) |
|
return errno; |
|
if ((fp = fopen(filename, "r+")) == NULL) |
|
return errno; |
|
strcpy(template, _history_tmp_template); |
|
if ((fd = mkstemp(template)) == -1) { |
|
ret = errno; |
|
goto out1; |
|
} |
|
|
|
if ((tp = fdopen(fd, "r+")) == NULL) { |
|
close(fd); |
|
ret = errno; |
|
goto out2; |
|
} |
|
|
|
for(;;) { |
|
if (fread(buf, sizeof(buf), 1, fp) != 1) { |
|
if (ferror(fp)) { |
|
ret = errno; |
|
break; |
|
} |
|
if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == |
|
(off_t)-1) { |
|
ret = errno; |
|
break; |
|
} |
|
left = fread(buf, 1, sizeof(buf), fp); |
|
if (ferror(fp)) { |
|
ret = errno; |
|
break; |
|
} |
|
if (left == 0) { |
|
count--; |
|
left = sizeof(buf); |
|
} else if (fwrite(buf, (size_t)left, 1, tp) != 1) { |
|
ret = errno; |
|
break; |
|
} |
|
fflush(tp); |
|
break; |
|
} |
|
if (fwrite(buf, sizeof(buf), 1, tp) != 1) { |
|
ret = errno; |
|
break; |
|
} |
|
count++; |
|
} |
|
if (ret) |
|
goto out3; |
|
cp = buf + left - 1; |
|
if(*cp != '\n') |
|
cp++; |
|
for(;;) { |
|
while (--cp >= buf) { |
|
if (*cp == '\n') { |
|
if (--nlines == 0) { |
|
if (++cp >= buf + sizeof(buf)) { |
|
count++; |
|
cp = buf; |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
if (nlines <= 0 || count == 0) |
|
break; |
|
count--; |
|
if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { |
|
ret = errno; |
|
break; |
|
} |
|
if (fread(buf, sizeof(buf), 1, tp) != 1) { |
|
if (ferror(tp)) { |
|
ret = errno; |
|
break; |
|
} |
|
ret = EAGAIN; |
|
break; |
|
} |
|
cp = buf + sizeof(buf); |
|
} |
|
|
|
if (ret || nlines > 0) |
|
goto out3; |
|
|
|
if (fseeko(fp, 0, SEEK_SET) == (off_t)-1) { |
|
ret = errno; |
|
goto out3; |
|
} |
|
|
|
if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == |
|
(off_t)-1) { |
|
ret = errno; |
|
goto out3; |
|
} |
|
|
|
for(;;) { |
|
if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) { |
|
if (ferror(fp)) |
|
ret = errno; |
|
break; |
|
} |
|
if (fwrite(buf, (size_t)left, 1, fp) != 1) { |
|
ret = errno; |
|
break; |
|
} |
|
} |
|
fflush(fp); |
|
if((off = ftello(fp)) > 0) |
|
(void)ftruncate(fileno(fp), off); |
|
out3: |
|
fclose(tp); |
|
out2: |
|
unlink(template); |
|
out1: |
|
fclose(fp); |
|
|
|
return ret; |
|
} |
|
|
|
|
/* |
/* |
* read history from a file given |
* read history from a file given |
Line 1100 read_history(const char *filename) |
|
Line 1292 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)); |
if (filename == NULL && (filename = _default_history_file()) == NULL) |
|
return errno; |
|
return (history(h, &ev, H_LOAD, filename) == -1 ? (errno ? errno : EINVAL) : 0); |
} |
} |
|
|
|
|
Line 1114 write_history(const char *filename) |
|
Line 1308 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)); |
if (filename == NULL && (filename = _default_history_file()) == NULL) |
|
return errno; |
|
return (history(h, &ev, H_SAVE, filename) == -1 ? (errno ? errno : EINVAL) : 0); |
} |
} |
|
|
|
|
Line 1138 history_get(int num) |
|
Line 1334 history_get(int num) |
|
return (NULL); |
return (NULL); |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
/* start from most recent */ |
/* start from the oldest */ |
if (history(h, &ev, H_FIRST) != 0) |
if (history(h, &ev, H_LAST) != 0) |
return (NULL); /* error */ |
return (NULL); /* error */ |
|
|
/* look backwards for event matching specified offset */ |
/* look forwards for event matching specified offset */ |
if (history(h, &ev, H_NEXT_EVENT, num)) |
if (history(h, &ev, H_NEXT_EVDATA, num, &she.data)) |
return (NULL); |
return (NULL); |
|
|
she.line = ev.str; |
she.line = ev.str; |
she.data = NULL; |
|
|
|
/* 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); |
Line 1176 add_history(const char *line) |
|
Line 1371 add_history(const char *line) |
|
|
|
|
|
/* |
/* |
|
* remove the specified entry from the history list and return it. |
|
*/ |
|
HIST_ENTRY * |
|
remove_history(int num) |
|
{ |
|
HIST_ENTRY *he; |
|
HistEvent ev; |
|
|
|
if (h == NULL || e == NULL) |
|
rl_initialize(); |
|
|
|
if ((he = malloc(sizeof(*he))) == NULL) |
|
return NULL; |
|
|
|
if (history(h, &ev, H_DELDATA, num, &he->data) != 0) { |
|
free(he); |
|
return NULL; |
|
} |
|
|
|
he->line = ev.str; |
|
if (history(h, &ev, H_GETSIZE) == 0) |
|
history_length = ev.num; |
|
|
|
return he; |
|
} |
|
|
|
|
|
/* |
|
* replace the line and data of the num-th entry |
|
*/ |
|
HIST_ENTRY * |
|
replace_history_entry(int num, const char *line, histdata_t data) |
|
{ |
|
HIST_ENTRY *he; |
|
HistEvent ev; |
|
int curr_num; |
|
|
|
if (h == NULL || e == NULL) |
|
rl_initialize(); |
|
|
|
/* save current position */ |
|
if (history(h, &ev, H_CURR) != 0) |
|
return NULL; |
|
curr_num = ev.num; |
|
|
|
/* start from the oldest */ |
|
if (history(h, &ev, H_LAST) != 0) |
|
return NULL; /* error */ |
|
|
|
if ((he = malloc(sizeof(*he))) == NULL) |
|
return NULL; |
|
|
|
/* look forwards for event matching specified offset */ |
|
if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) |
|
goto out; |
|
|
|
he->line = strdup(ev.str); |
|
if (he->line == NULL) |
|
goto out; |
|
|
|
if (history(h, &ev, H_REPLACE, line, data)) |
|
goto out; |
|
|
|
/* restore pointer to where it was */ |
|
if (history(h, &ev, H_SET, curr_num)) |
|
goto out; |
|
|
|
return he; |
|
out: |
|
free(he); |
|
return NULL; |
|
} |
|
|
|
/* |
* clear the history list - delete all entries |
* clear the history list - delete all entries |
*/ |
*/ |
void |
void |
Line 1184 clear_history(void) |
|
Line 1453 clear_history(void) |
|
HistEvent ev; |
HistEvent ev; |
|
|
history(h, &ev, H_CLEAR); |
history(h, &ev, H_CLEAR); |
|
history_length = 0; |
} |
} |
|
|
|
|
|
|
history_total_bytes(void) |
history_total_bytes(void) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
int curr_num, size; |
int curr_num; |
|
size_t size; |
|
|
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_CURR) != 0) |
return (-1); |
return (-1); |
Line 1242 history_total_bytes(void) |
|
Line 1513 history_total_bytes(void) |
|
/* get to the same position as before */ |
/* get to the same position as before */ |
history(h, &ev, H_PREV_EVENT, curr_num); |
history(h, &ev, H_PREV_EVENT, curr_num); |
|
|
return (size); |
return (int)(size); |
} |
} |
|
|
|
|
Line 1255 history_set_pos(int pos) |
|
Line 1526 history_set_pos(int pos) |
|
HistEvent ev; |
HistEvent ev; |
int curr_num; |
int curr_num; |
|
|
if (pos > history_length || pos < 0) |
if (pos >= history_length || pos < 0) |
return (-1); |
return (-1); |
|
|
history(h, &ev, H_CURR); |
history(h, &ev, H_CURR); |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
if (history(h, &ev, H_SET, pos)) { |
/* |
|
* use H_DELDATA to set to nth history (without delete) by passing |
|
* (void **)-1 |
|
*/ |
|
if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { |
history(h, &ev, H_SET, curr_num); |
history(h, &ev, H_SET, curr_num); |
return(-1); |
return(-1); |
} |
} |
Line 1368 history_search_pos(const char *str, |
|
Line 1643 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 pwres, *pass; |
return fn_tilde_expand(name); |
char *temp; |
|
size_t len = 0; |
|
char pwbuf[1024]; |
|
|
|
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'; |
|
} |
|
if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) |
|
pass = NULL; |
|
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 { |
|
if (*text == 0) |
|
filename = NULL; |
|
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 = filename ? strlen(filename) : 0; |
|
|
|
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) { |
|
/* skip . and .. */ |
|
if (entry->d_name[0] == '.' && (!entry->d_name[1] |
|
|| (entry->d_name[1] == '.' && !entry->d_name[2]))) |
|
continue; |
|
if (filename_len == 0) |
|
break; |
|
/* 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 1570 username_completion_function(const char |
|
Line 1683 username_completion_function(const char |
|
|
|
if (pwd == NULL) { |
if (pwd == NULL) { |
endpwent(); |
endpwent(); |
return (NULL); |
return NULL; |
} |
} |
return (strdup(pwd->pw_name)); |
return strdup(pwd->pw_name); |
} |
} |
|
|
|
|
/* |
/* |
* el-compatible wrapper around rl_complete; needed for key binding |
|
*/ |
|
/* ARGSUSED */ |
|
static unsigned char |
|
_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) |
|
{ |
|
return (unsigned char) rl_complete(0, ch); |
|
} |
|
|
|
/* |
|
* el-compatible wrapper to send TSTP on ^Z |
* el-compatible wrapper to send TSTP on ^Z |
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
Line 1598 _el_rl_tstp(EditLine *el __attribute__(( |
|
Line 1701 _el_rl_tstp(EditLine *el __attribute__(( |
|
} |
} |
|
|
/* |
/* |
* returns list of completions for text given |
|
*/ |
|
char ** |
|
completion_matches(const char *text, CPFunction *genfunc) |
|
{ |
|
char **match_list = NULL, *retstr, *prevstr; |
|
size_t match_list_len, max_equal, which, i; |
|
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); |
|
} |
|
|
|
/* |
|
* Display list of strings in columnar format on readline's output stream. |
* Display list of strings in columnar format on readline's output stream. |
* 'matches' is list of strings, 'len' is number of strings in 'matches', |
* 'matches' is list of strings, 'len' is number of strings in 'matches', |
* '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; |
|
|
|
/* |
|
* 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. */ |
fn_display_match_list(e, matches, (size_t)len, (size_t)max); |
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[0] = rl_completion_append_character; |
char *temp, **matches; |
buf[1] = '\0'; |
const char *ctemp; |
return buf; |
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_update_pos(); |
|
|
|
if (rl_attempted_completion_function) { |
|
int end = li->cursor - li->buffer; |
|
matches = (*rl_attempted_completion_function) (temp, (int) |
|
(end - len), end); |
|
} else |
|
matches = 0; |
|
if (!rl_attempted_completion_function || |
|
(!rl_attempted_completion_over && !matches)) |
|
matches = completion_matches(temp, (CPFunction *)complet_func); |
|
|
|
if (rl_attempted_completion_over) |
|
rl_attempted_completion_over = 0; |
|
|
|
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 |
/*ARGSUSED*/ |
rl_complete(int ignore __attribute__((__unused__)), int invoking_key) |
rl_complete(int ignore, int invoking_key) |
|
{ |
{ |
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
Line 1879 rl_complete(int ignore, int invoking_key |
|
Line 1740 rl_complete(int ignore, int invoking_key |
|
arr[1] = '\0'; |
arr[1] = '\0'; |
el_insertstr(e, arr); |
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, |
|
(size_t)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 1896 rl_complete(int ignore, int invoking_key |
|
Line 1769 rl_complete(int ignore, int invoking_key |
|
* bind key c to readline-type function func |
* bind key c to readline-type function func |
*/ |
*/ |
int |
int |
rl_bind_key(int c, int func(int, int)) |
rl_bind_key(int c, rl_command_func_t *func) |
{ |
{ |
int retval = -1; |
int retval = -1; |
|
|
Line 1963 rl_insert(int count, int c) |
|
Line 1836 rl_insert(int count, int c) |
|
return (0); |
return (0); |
} |
} |
|
|
|
int |
|
rl_insert_text(const char *text) |
|
{ |
|
if (!text || *text == 0) |
|
return (0); |
|
|
|
if (h == NULL || e == NULL) |
|
rl_initialize(); |
|
|
|
if (el_insertstr(e, text) < 0) |
|
return (0); |
|
return (int)strlen(text); |
|
} |
|
|
/*ARGSUSED*/ |
/*ARGSUSED*/ |
int |
int |
rl_newline(int count, int c) |
rl_newline(int count, int c) |
|
|
rl_add_defun(const char *name, Function *fun, int c) |
rl_add_defun(const char *name, Function *fun, int c) |
{ |
{ |
char dest[8]; |
char dest[8]; |
if (c >= sizeof(map) / sizeof(map[0]) || c < 0) |
if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) |
return -1; |
return -1; |
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); |
Line 2013 rl_callback_read_char() |
|
Line 1900 rl_callback_read_char() |
|
|
|
if (buf == NULL || count-- <= 0) |
if (buf == NULL || count-- <= 0) |
return; |
return; |
if (count == 0 && buf[0] == CTRL('d')) |
if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF]) |
done = 1; |
done = 1; |
if (buf[count] == '\n' || buf[count] == '\r') |
if (buf[count] == '\n' || buf[count] == '\r') |
done = 2; |
done = 2; |
Line 2026 rl_callback_read_char() |
|
Line 1913 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, VFunction *linefunc) |
rl_callback_handler_install(const char *prompt, VCPFunction *linefunc) |
{ |
{ |
if (e == NULL) { |
if (e == NULL) { |
rl_initialize(); |
rl_initialize(); |
} |
} |
if (rl_prompt) |
(void)rl_set_prompt(prompt); |
free(rl_prompt); |
|
rl_prompt = prompt ? strdup(strchr(prompt, *prompt)) : NULL; |
|
rl_linefunc = linefunc; |
rl_linefunc = linefunc; |
el_set(e, EL_UNBUFFERED, 1); |
el_set(e, EL_UNBUFFERED, 1); |
} |
} |
|
|
rl_callback_handler_remove(void) |
rl_callback_handler_remove(void) |
{ |
{ |
el_set(e, EL_UNBUFFERED, 0); |
el_set(e, EL_UNBUFFERED, 0); |
|
rl_linefunc = NULL; |
} |
} |
|
|
void |
void |
rl_redisplay(void) |
rl_redisplay(void) |
{ |
{ |
char a[2]; |
char a[2]; |
a[0] = CTRL('r'); |
a[0] = e->el_tty.t_c[TS_IO][C_REPRINT]; |
a[1] = '\0'; |
a[1] = '\0'; |
el_push(e, a); |
el_push(e, a); |
} |
} |
Line 2077 rl_prep_terminal(int meta_flag) |
|
Line 1963 rl_prep_terminal(int meta_flag) |
|
} |
} |
|
|
void |
void |
rl_deprep_terminal() |
rl_deprep_terminal(void) |
{ |
{ |
el_set(e, EL_PREP_TERM, 0); |
el_set(e, EL_PREP_TERM, 0); |
} |
} |
Line 2125 rl_stuff_char(int c) |
|
Line 2011 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 = 0; |
int n; |
|
ssize_t num_read = 0; |
|
|
*cp = 0; |
*cp = '\0'; |
while (rl_event_hook) { |
while (rl_event_hook) { |
|
|
(*rl_event_hook)(); |
(*rl_event_hook)(); |
Line 2161 _rl_event_read_char(EditLine *el, char * |
|
Line 2048 _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); |
return(num_read); |
return (int)num_read; |
} |
} |
|
|
static void |
static void |
Line 2169 _rl_update_pos(void) |
|
Line 2056 _rl_update_pos(void) |
|
{ |
{ |
const LineInfo *li = el_line(e); |
const LineInfo *li = el_line(e); |
|
|
rl_point = li->cursor - li->buffer; |
rl_point = (int)(li->cursor - li->buffer); |
rl_end = li->lastchar - li->buffer; |
rl_end = (int)(li->lastchar - li->buffer); |
|
} |
|
|
|
void |
|
rl_get_screen_size(int *rows, int *cols) |
|
{ |
|
if (rows) |
|
el_get(e, EL_GETTC, "li", rows); |
|
if (cols) |
|
el_get(e, EL_GETTC, "co", cols); |
|
} |
|
|
|
void |
|
rl_set_screen_size(int rows, int cols) |
|
{ |
|
char buf[64]; |
|
(void)snprintf(buf, sizeof(buf), "%d", rows); |
|
el_set(e, EL_SETTC, "li", buf); |
|
(void)snprintf(buf, sizeof(buf), "%d", cols); |
|
el_set(e, EL_SETTC, "co", buf); |
|
} |
|
|
|
char ** |
|
rl_completion_matches(const char *str, rl_compentry_func_t *fun) |
|
{ |
|
size_t len, max, i, j, min; |
|
char **list, *match, *a, *b; |
|
|
|
len = 1; |
|
max = 10; |
|
if ((list = malloc(max * sizeof(*list))) == NULL) |
|
return NULL; |
|
|
|
while ((match = (*fun)(str, (int)(len - 1))) != NULL) { |
|
list[len++] = match; |
|
if (len == max) { |
|
char **nl; |
|
max += 10; |
|
if ((nl = realloc(list, max * sizeof(*nl))) == NULL) |
|
goto out; |
|
list = nl; |
|
} |
|
} |
|
if (len == 1) |
|
goto out; |
|
list[len] = NULL; |
|
if (len == 2) { |
|
if ((list[0] = strdup(list[1])) == NULL) |
|
goto out; |
|
return list; |
|
} |
|
qsort(&list[1], len - 1, sizeof(*list), |
|
(int (*)(const void *, const void *)) strcmp); |
|
min = SIZE_T_MAX; |
|
for (i = 1, a = list[i]; i < len - 1; i++, a = b) { |
|
b = list[i + 1]; |
|
for (j = 0; a[j] && a[j] == b[j]; j++) |
|
continue; |
|
if (min > j) |
|
min = j; |
|
} |
|
if (min == 0 && *str) { |
|
if ((list[0] = strdup(str)) == NULL) |
|
goto out; |
|
} else { |
|
if ((list[0] = malloc(min + 1)) == NULL) |
|
goto out; |
|
(void)memcpy(list[0], list[1], min); |
|
list[0][min] = '\0'; |
|
} |
|
return list; |
|
|
|
out: |
|
free(list); |
|
return NULL; |
|
} |
|
|
|
char * |
|
rl_filename_completion_function (const char *text, int state) |
|
{ |
|
return fn_filename_completion_function(text, state); |
|
} |
|
|
|
void |
|
rl_forced_update_display(void) |
|
{ |
|
el_set(e, EL_REFRESH); |
|
} |
|
|
|
int |
|
_rl_abort_internal(void) |
|
{ |
|
el_beep(e); |
|
longjmp(topbuf, 1); |
|
/*NOTREACHED*/ |
|
} |
|
|
|
int |
|
_rl_qsort_string_compare(char **s1, char **s2) |
|
{ |
|
return strcoll(*s1, *s2); |
|
} |
|
|
|
HISTORY_STATE * |
|
history_get_history_state(void) |
|
{ |
|
HISTORY_STATE *hs; |
|
|
|
if ((hs = malloc(sizeof(HISTORY_STATE))) == NULL) |
|
return (NULL); |
|
hs->length = history_length; |
|
return (hs); |
|
} |
|
|
|
int |
|
/*ARGSUSED*/ |
|
rl_kill_text(int from, int to) |
|
{ |
|
return 0; |
|
} |
|
|
|
Keymap |
|
rl_make_bare_keymap(void) |
|
{ |
|
return NULL; |
|
} |
|
|
|
Keymap |
|
rl_get_keymap(void) |
|
{ |
|
return NULL; |
|
} |
|
|
|
void |
|
/*ARGSUSED*/ |
|
rl_set_keymap(Keymap k) |
|
{ |
|
} |
|
|
|
int |
|
/*ARGSUSED*/ |
|
rl_generic_bind(int type, const char * keyseq, const char * data, Keymap k) |
|
{ |
|
return 0; |
|
} |
|
|
|
int |
|
/*ARGSUSED*/ |
|
rl_bind_key_in_map(int key, rl_command_func_t *fun, Keymap k) |
|
{ |
|
return 0; |
|
} |
|
|
|
/* unsupported, but needed by python */ |
|
void |
|
rl_cleanup_after_signal(void) |
|
{ |
} |
} |