version 1.27, 2003/03/10 00:56:38 |
version 1.44, 2003/12/05 13:37:48 |
Line 51 __RCSID("$NetBSD$"); |
|
Line 51 __RCSID("$NetBSD$"); |
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <limits.h> |
#include <limits.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#ifdef HAVE_VIS_H |
|
#include <vis.h> |
|
#else |
|
#include "np/vis.h" |
|
#endif |
#ifdef HAVE_ALLOCA_H |
#ifdef HAVE_ALLOCA_H |
#include <alloca.h> |
#include <alloca.h> |
#endif |
#endif |
Line 60 __RCSID("$NetBSD$"); |
|
Line 67 __RCSID("$NetBSD$"); |
|
#include "fcns.h" /* for EL_NUM_FCNS */ |
#include "fcns.h" /* for EL_NUM_FCNS */ |
|
|
/* for rl_complete() */ |
/* for rl_complete() */ |
#define TAB '\r' |
#define TAB '\r' |
|
|
/* see comment at the #ifdef for sense of this */ |
/* see comment at the #ifdef for sense of this */ |
#define GDB_411_HACK |
/* #define GDB_411_HACK */ |
|
|
/* 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 */ |
Line 78 FILE *rl_outstream = NULL; |
|
Line 85 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; |
|
int rl_done = 0; |
|
VFunction *rl_event_hook = NULL; |
|
|
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 86 char history_expansion_char = '!'; |
|
Line 96 char history_expansion_char = '!'; |
|
char history_subst_char = '^'; |
char history_subst_char = '^'; |
char *history_no_expand_chars = expand_chars; |
char *history_no_expand_chars = expand_chars; |
Function *history_inhibit_expansion_function = NULL; |
Function *history_inhibit_expansion_function = NULL; |
|
char *history_arg_extract(int start, int end, const char *str); |
|
|
int rl_inhibit_completion = 0; |
int rl_inhibit_completion = 0; |
int rl_attempted_completion_over = 0; |
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; |
CPFunction *rl_completion_entry_function = NULL; |
Function *rl_completion_entry_function = NULL; |
CPPFunction *rl_attempted_completion_function = NULL; |
CPPFunction *rl_attempted_completion_function = NULL; |
|
Function *rl_pre_input_hook = NULL; |
|
Function *rl_startup1_hook = NULL; |
|
Function *rl_getc_function = NULL; |
|
char *rl_terminal_name = NULL; |
|
int rl_already_prompted = 0; |
|
int rl_filename_completion_desired = 0; |
|
int rl_ignore_completion_duplicates = 0; |
|
int rl_catch_signals = 1; |
|
VFunction *rl_redisplay_function = NULL; |
|
Function *rl_startup_hook = NULL; |
|
VFunction *rl_completion_display_matches_hook = NULL; |
|
VFunction *rl_prep_term_function = NULL; |
|
VFunction *rl_deprep_term_function = NULL; |
|
|
/* |
/* |
|
* The current prompt string. |
|
*/ |
|
char *rl_prompt = NULL; |
|
/* |
* This is set to character indicating type of completion being done by |
* This is set to character indicating type of completion being done by |
* rl_complete_internal(); this is available for application completion |
* rl_complete_internal(); this is available for application completion |
* functions. |
* functions. |
Line 128 static int _rl_complete_show_all = 0; |
|
Line 156 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 int el_rl_complete_cmdnum = 0; |
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 char *_get_prompt(EditLine *); |
static char *_get_prompt(EditLine *); |
static HIST_ENTRY *_move_history(int); |
static HIST_ENTRY *_move_history(int); |
static int _history_search_gen(const char *, int, int); |
static int _history_expand_command(const char *, size_t, size_t, |
static int _history_expand_command(const char *, 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_complete_internal(int); |
static int _rl_qsort_string_compare(const void *, const void *); |
static int _rl_qsort_string_compare(const void *, const void *); |
|
static int _rl_event_read_char(EditLine *, char *); |
/* |
|
* needed for prompt switching in readline() |
|
*/ |
|
static char *el_rl_prompt = NULL; |
|
|
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static char * |
static char * |
_get_prompt(EditLine *el) |
_get_prompt(EditLine *el __attribute__((__unused__))) |
{ |
{ |
return (el_rl_prompt); |
rl_already_prompted = 1; |
|
return (rl_prompt); |
} |
} |
|
|
|
|
Line 168 _move_history(int op) |
|
Line 194 _move_history(int op) |
|
return (HIST_ENTRY *) NULL; |
return (HIST_ENTRY *) NULL; |
|
|
rl_he.line = ev.str; |
rl_he.line = ev.str; |
rl_he.data = ""; |
rl_he.data = NULL; |
|
|
return (&rl_he); |
return (&rl_he); |
} |
} |
Line 221 rl_initialize(void) |
|
Line 247 rl_initialize(void) |
|
el_set(e, EL_HIST, history, h); |
el_set(e, EL_HIST, history, h); |
|
|
/* for proper prompt printing in readline() */ |
/* for proper prompt printing in readline() */ |
el_rl_prompt = strdup(""); |
rl_prompt = strdup(""); |
if (el_rl_prompt == NULL) { |
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); |
el_set(e, EL_SIGNAL, 1); |
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 overriden */ |
el_set(e, EL_EDITOR, "emacs"); |
el_set(e, EL_EDITOR, "emacs"); |
|
if (rl_terminal_name != NULL) |
|
el_set(e, EL_TERMINAL, rl_terminal_name); |
|
else |
|
el_get(e, EL_TERMINAL, &rl_terminal_name); |
|
|
/* |
/* |
* Word completition - this has to go AFTER rebinding keys |
* Word completion - this has to go AFTER rebinding keys |
* to emacs-style. |
* to emacs-style. |
*/ |
*/ |
el_set(e, EL_ADDFN, "rl_complete", |
el_set(e, EL_ADDFN, "rl_complete", |
"ReadLine compatible completition 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 |
* Find out where the rl_complete function was added; this is |
* used later to detect that lastcmd was also rl_complete. |
* used later to detect that lastcmd was also rl_complete. |
Line 266 rl_initialize(void) |
|
Line 295 rl_initialize(void) |
|
rl_line_buffer = memchr(li->buffer, *li->buffer, 1); |
rl_line_buffer = memchr(li->buffer, *li->buffer, 1); |
rl_point = rl_end = 0; |
rl_point = rl_end = 0; |
|
|
|
if (rl_startup_hook) |
|
(*rl_startup_hook)(NULL, 0); |
|
|
return (0); |
return (0); |
} |
} |
|
|
Line 281 readline(const char *prompt) |
|
Line 313 readline(const char *prompt) |
|
int count; |
int count; |
const char *ret; |
const char *ret; |
char *buf; |
char *buf; |
|
static int used_event_hook; |
|
|
if (e == NULL || h == NULL) |
if (e == NULL || h == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
|
rl_done = 0; |
|
|
/* update prompt accordingly to what has been passed */ |
/* update prompt accordingly to what has been passed */ |
if (!prompt) |
if (!prompt) |
prompt = ""; |
prompt = ""; |
if (strcmp(el_rl_prompt, prompt) != 0) { |
if (strcmp(rl_prompt, prompt) != 0) { |
free(el_rl_prompt); |
free(rl_prompt); |
el_rl_prompt = strdup(prompt); |
rl_prompt = strdup(prompt); |
if (el_rl_prompt == NULL) |
if (rl_prompt == NULL) |
return NULL; |
return NULL; |
} |
} |
|
|
|
if (rl_pre_input_hook) |
|
(*rl_pre_input_hook)(NULL, 0); |
|
|
|
if (rl_event_hook && !(e->el_flags&NO_TTY)) { |
|
el_set(e, EL_GETCFN, _rl_event_read_char); |
|
used_event_hook = 1; |
|
} |
|
|
|
if (!rl_event_hook && used_event_hook) { |
|
el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); |
|
used_event_hook = 0; |
|
} |
|
|
|
rl_already_prompted = 0; |
|
|
/* get one line from input stream */ |
/* get one line from input stream */ |
ret = el_gets(e, &count); |
ret = el_gets(e, &count); |
|
|
Line 333 using_history(void) |
|
Line 384 using_history(void) |
|
|
|
/* |
/* |
* substitute ``what'' with ``with'', returning resulting string; if |
* substitute ``what'' with ``with'', returning resulting string; if |
* globally == 1, substitutes all occurences of what, otherwise only the |
* globally == 1, substitutes all occurrences of what, otherwise only the |
* first one |
* first one |
*/ |
*/ |
static char * |
static char * |
_rl_compat_sub(const char *str, const char *what, const char *with, |
_rl_compat_sub(const char *str, const char *what, const char *with, |
int globally) |
int globally) |
{ |
{ |
char *result; |
const char *s; |
const char *temp, *new; |
char *r, *result; |
int len, with_len, what_len, add; |
size_t len, with_len, what_len; |
size_t size, i; |
|
|
|
result = malloc((size = 16)); |
len = strlen(str); |
if (result == NULL) |
|
return NULL; |
|
temp = str; |
|
with_len = strlen(with); |
with_len = strlen(with); |
what_len = strlen(what); |
what_len = strlen(what); |
len = 0; |
|
do { |
/* calculate length we need for result */ |
new = strstr(temp, what); |
s = str; |
if (new) { |
while (*s) { |
i = new - temp; |
if (*s == *what && !strncmp(s, what, what_len)) { |
add = i + with_len; |
len += with_len - what_len; |
if (i + add + 1 >= size) { |
if (!globally) |
char *nresult; |
break; |
size += add + 1; |
s += what_len; |
nresult = realloc(result, size); |
} else |
if (nresult == NULL) { |
s++; |
free(result); |
} |
return NULL; |
r = result = malloc(len + 1); |
} |
if (result == NULL) |
result = nresult; |
return NULL; |
} |
s = str; |
(void) strncpy(&result[len], temp, i); |
while (*s) { |
len += i; |
if (*s == *what && !strncmp(s, what, what_len)) { |
(void) strcpy(&result[len], with); /* safe */ |
(void)strncpy(r, with, with_len); |
len += with_len; |
r += with_len; |
temp = new + what_len; |
s += what_len; |
} else { |
if (!globally) { |
add = strlen(temp); |
(void)strcpy(r, s); |
if (len + add + 1 >= size) { |
return(result); |
char *nresult; |
|
size += add + 1; |
|
nresult = realloc(result, size); |
|
if (nresult == NULL) { |
|
free(result); |
|
return NULL; |
|
} |
|
result = nresult; |
|
} |
} |
(void) strcpy(&result[len], temp); /* safe */ |
} else |
len += add; |
*r++ = *s++; |
temp = NULL; |
} |
|
*r = 0; |
|
return(result); |
|
} |
|
|
|
static char *last_search_pat; /* last !?pat[?] search pattern */ |
|
static char *last_search_match; /* last !?pat[?] that matched */ |
|
|
|
const char * |
|
get_history_event(const char *cmd, int *cindex, int qchar) |
|
{ |
|
int idx, sign, sub, num, begin, ret; |
|
size_t len; |
|
char *pat; |
|
const char *rptr; |
|
HistEvent ev; |
|
|
|
idx = *cindex; |
|
if (cmd[idx++] != history_expansion_char) |
|
return(NULL); |
|
|
|
/* find out which event to take */ |
|
if (cmd[idx] == history_expansion_char || cmd[idx] == 0) { |
|
if (history(h, &ev, H_FIRST) != 0) |
|
return(NULL); |
|
*cindex = cmd[idx]? (idx + 1):idx; |
|
return(ev.str); |
|
} |
|
sign = 0; |
|
if (cmd[idx] == '-') { |
|
sign = 1; |
|
idx++; |
|
} |
|
|
|
if ('0' <= cmd[idx] && cmd[idx] <= '9') { |
|
HIST_ENTRY *rl_he; |
|
|
|
num = 0; |
|
while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { |
|
num = num * 10 + cmd[idx] - '0'; |
|
idx++; |
} |
} |
} while (temp && globally); |
if (sign) |
result[len] = '\0'; |
num = history_length - num + 1; |
|
|
return (result); |
if (!(rl_he = history_get(num))) |
} |
return(NULL); |
|
|
|
*cindex = idx; |
|
return(rl_he->line); |
|
} |
|
sub = 0; |
|
if (cmd[idx] == '?') { |
|
sub = 1; |
|
idx++; |
|
} |
|
begin = idx; |
|
while (cmd[idx]) { |
|
if (cmd[idx] == '\n') |
|
break; |
|
if (sub && cmd[idx] == '?') |
|
break; |
|
if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' |
|
|| cmd[idx] == '\t' || cmd[idx] == qchar)) |
|
break; |
|
idx++; |
|
} |
|
len = idx - begin; |
|
if (sub && cmd[idx] == '?') |
|
idx++; |
|
if (sub && len == 0 && last_search_pat && *last_search_pat) |
|
pat = last_search_pat; |
|
else if (len == 0) |
|
return(NULL); |
|
else { |
|
if ((pat = malloc(len + 1)) == NULL) |
|
return NULL; |
|
(void)strncpy(pat, cmd + begin, len); |
|
pat[len] = '\0'; |
|
} |
|
|
|
if (history(h, &ev, H_CURR) != 0) { |
|
if (pat != last_search_pat) |
|
free(pat); |
|
return (NULL); |
|
} |
|
num = ev.num; |
|
|
|
if (sub) { |
|
if (pat != last_search_pat) { |
|
if (last_search_pat) |
|
free(last_search_pat); |
|
last_search_pat = pat; |
|
} |
|
ret = history_search(pat, -1); |
|
} else |
|
ret = history_search_prefix(pat, -1); |
|
|
|
if (ret == -1) { |
|
/* restore to end of list on failed search */ |
|
history(h, &ev, H_FIRST); |
|
(void)fprintf(rl_outstream, "%s: Event not found\n", pat); |
|
if (pat != last_search_pat) |
|
free(pat); |
|
return(NULL); |
|
} |
|
|
|
if (sub && len) { |
|
if (last_search_match && last_search_match != pat) |
|
free(last_search_match); |
|
last_search_match = pat; |
|
} |
|
|
|
if (pat != last_search_pat) |
|
free(pat); |
|
|
|
if (history(h, &ev, H_CURR) != 0) |
|
return(NULL); |
|
*cindex = idx; |
|
rptr = ev.str; |
|
|
|
/* roll back to original position */ |
|
(void)history(h, &ev, H_SET, num); |
|
|
|
return rptr; |
|
} |
|
|
/* |
/* |
* the real function doing history expansion - takes as argument command |
* the real function doing history expansion - takes as argument command |
* to do and data upon which the command should be executed |
* to do and data upon which the command should be executed |
* does expansion the way I've understood readline documentation |
* does expansion the way I've understood readline documentation |
* word designator ``%'' isn't supported (yet ?) |
|
* |
* |
* 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, |
Line 407 _rl_compat_sub(const char *str, const ch |
|
Line 563 _rl_compat_sub(const char *str, const ch |
|
* it's callers responsibility to free() string returned in *result |
* it's callers responsibility to free() string returned in *result |
*/ |
*/ |
static int |
static int |
_history_expand_command(const char *command, size_t cmdlen, char **result) |
_history_expand_command(const char *command, size_t offs, size_t cmdlen, |
|
char **result) |
{ |
{ |
char **arr, *tempcmd, *line, *search = NULL, *cmd; |
char *tmp, *search = NULL, *aptr; |
const char *event_data = NULL; |
const char *ptr, *cmd; |
static char *from = NULL, *to = NULL; |
static char *from = NULL, *to = NULL; |
int start = -1, end = -1, max, i, idx; |
int start, end, idx, has_mods = 0; |
int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, g_on = 0; |
int p_on = 0, g_on = 0; |
int event_num = 0, retval; |
|
size_t cmdsize; |
|
|
|
*result = NULL; |
*result = NULL; |
|
aptr = NULL; |
|
ptr = NULL; |
|
|
cmd = alloca(cmdlen + 1); |
/* First get event specifier */ |
(void) strncpy(cmd, command, cmdlen); |
idx = 0; |
cmd[cmdlen] = 0; |
|
|
|
idx = 1; |
if (strchr(":^*$", command[offs + 1])) { |
/* find out which event to take */ |
char str[4]; |
if (cmd[idx] == history_expansion_char) { |
/* |
event_num = history_length; |
* "!:" is shorthand for "!!:". |
idx++; |
* "!^", "!*" and "!$" are shorthand for |
|
* "!!:^", "!!:*" and "!!:$" respectively. |
|
*/ |
|
str[0] = str[1] = '!'; |
|
str[2] = '0'; |
|
ptr = get_history_event(str, &idx, 0); |
|
idx = (command[offs + 1] == ':')? 1:0; |
|
has_mods = 1; |
} else { |
} else { |
int off, num; |
if (command[offs + 1] == '#') { |
size_t len; |
/* use command so far */ |
off = idx; |
if ((aptr = malloc(offs + 1)) == NULL) |
while (cmd[off] && !strchr(":^$*-%", cmd[off])) |
return -1; |
off++; |
(void)strncpy(aptr, command, offs); |
num = atoi(&cmd[idx]); |
aptr[offs] = '\0'; |
if (num != 0) { |
idx = 1; |
event_num = num; |
|
if (num < 0) |
|
event_num += history_length + 1; |
|
} else { |
} else { |
int prefix = 1, curr_num; |
int qchar; |
HistEvent ev; |
|
|
|
len = off - idx; |
|
if (cmd[idx] == '?') { |
|
idx++, len--; |
|
if (cmd[off - 1] == '?') |
|
len--; |
|
else if (cmd[off] != '\n' && cmd[off] != '\0') |
|
return (-1); |
|
prefix = 0; |
|
} |
|
search = alloca(len + 1); |
|
(void) strncpy(search, &cmd[idx], len); |
|
search[len] = '\0'; |
|
|
|
if (history(h, &ev, H_CURR) != 0) |
|
return (-1); |
|
curr_num = ev.num; |
|
|
|
if (prefix) |
qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; |
retval = history_search_prefix(search, -1); |
ptr = get_history_event(command + offs, &idx, qchar); |
else |
|
retval = history_search(search, -1); |
|
|
|
if (retval == -1) { |
|
fprintf(rl_outstream, "%s: Event not found\n", |
|
search); |
|
return (-1); |
|
} |
|
if (history(h, &ev, H_CURR) != 0) |
|
return (-1); |
|
event_data = ev.str; |
|
|
|
/* roll back to original position */ |
|
history(h, &ev, H_NEXT_EVENT, curr_num); |
|
} |
} |
idx = off; |
has_mods = command[offs + idx] == ':'; |
} |
} |
|
|
if (!event_data && event_num >= 0) { |
if (ptr == NULL && aptr == NULL) |
HIST_ENTRY *rl_he; |
return(-1); |
rl_he = history_get(event_num); |
|
if (!rl_he) |
if (!has_mods) { |
return (0); |
*result = strdup(aptr? aptr : ptr); |
event_data = rl_he->line; |
if (aptr) |
|
free(aptr); |
|
return(1); |
|
} |
|
|
|
cmd = command + offs + idx + 1; |
|
|
|
/* Now parse any word designators */ |
|
|
|
if (*cmd == '%') /* last word matched by ?pat? */ |
|
tmp = strdup(last_search_match? last_search_match:""); |
|
else if (strchr("^*$-0123456789", *cmd)) { |
|
start = end = -1; |
|
if (*cmd == '^') |
|
start = end = 1, cmd++; |
|
else if (*cmd == '$') |
|
start = -1, cmd++; |
|
else if (*cmd == '*') |
|
start = 1, cmd++; |
|
else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { |
|
start = 0; |
|
while (*cmd && '0' <= *cmd && *cmd <= '9') |
|
start = start * 10 + *cmd++ - '0'; |
|
|
|
if (*cmd == '-') { |
|
if (isdigit((unsigned char) cmd[1])) { |
|
cmd++; |
|
end = 0; |
|
while (*cmd && '0' <= *cmd && *cmd <= '9') |
|
end = end * 10 + *cmd++ - '0'; |
|
} else if (cmd[1] == '$') { |
|
cmd += 2; |
|
end = -1; |
|
} else { |
|
cmd++; |
|
end = -2; |
|
} |
|
} else if (*cmd == '*') |
|
end = -1, cmd++; |
|
else |
|
end = start; |
|
} |
|
tmp = history_arg_extract(start, end, aptr? aptr:ptr); |
|
if (tmp == NULL) { |
|
(void)fprintf(rl_outstream, "%s: Bad word specifier", |
|
command + offs + idx); |
|
if (aptr) |
|
free(aptr); |
|
return(-1); |
|
} |
} else |
} else |
return (-1); |
tmp = strdup(aptr? aptr:ptr); |
|
|
if (cmd[idx] != ':') |
if (aptr) |
return (-1); |
free(aptr); |
cmd += idx + 1; |
|
|
|
/* recognize cmd */ |
if (*cmd == 0 || (cmd - (command + offs) >= cmdlen)) { |
if (*cmd == '^') |
*result = tmp; |
start = end = 1, cmd++; |
return(1); |
else if (*cmd == '$') |
|
start = end = -1, cmd++; |
|
else if (*cmd == '*') |
|
start = 1, end = -1, cmd++; |
|
else if (isdigit((unsigned char) *cmd)) { |
|
const char *temp; |
|
int shifted = 0; |
|
|
|
start = atoi(cmd); |
|
temp = cmd; |
|
for (; isdigit((unsigned char) *cmd); cmd++); |
|
if (temp != cmd) |
|
shifted = 1; |
|
if (shifted && *cmd == '-') { |
|
if (!isdigit((unsigned char) *(cmd + 1))) |
|
end = -2; |
|
else { |
|
end = atoi(cmd + 1); |
|
for (; isdigit((unsigned char) *cmd); cmd++); |
|
} |
|
} else if (shifted && *cmd == '*') |
|
end = -1, cmd++; |
|
else if (shifted) |
|
end = start; |
|
} |
} |
if (*cmd == ':') |
|
cmd++; |
|
|
|
line = strdup(event_data); |
|
if (line == NULL) |
|
return NULL; |
|
for (; *cmd; cmd++) { |
for (; *cmd; cmd++) { |
if (*cmd == ':') |
if (*cmd == ':') |
continue; |
continue; |
else if (*cmd == 'h') |
else if (*cmd == 'h') { /* remove trailing path */ |
h_on = 1 | g_on, g_on = 0; |
if ((aptr = strrchr(tmp, '/')) != NULL) |
else if (*cmd == 't') |
*aptr = 0; |
t_on = 1 | g_on, g_on = 0; |
} else if (*cmd == 't') { /* remove leading path */ |
else if (*cmd == 'r') |
if ((aptr = strrchr(tmp, '/')) != NULL) { |
r_on = 1 | g_on, g_on = 0; |
aptr = strdup(aptr + 1); |
else if (*cmd == 'e') |
free(tmp); |
e_on = 1 | g_on, g_on = 0; |
tmp = aptr; |
else if (*cmd == 'p') |
} |
p_on = 1 | g_on, g_on = 0; |
} else if (*cmd == 'r') { /* remove trailing suffix */ |
|
if ((aptr = strrchr(tmp, '.')) != NULL) |
|
*aptr = 0; |
|
} else if (*cmd == 'e') { /* remove all but suffix */ |
|
if ((aptr = strrchr(tmp, '.')) != NULL) { |
|
aptr = strdup(aptr); |
|
free(tmp); |
|
tmp = aptr; |
|
} |
|
} else if (*cmd == 'p') /* print only */ |
|
p_on = 1; |
else if (*cmd == 'g') |
else if (*cmd == 'g') |
g_on = 2; |
g_on = 2; |
else if (*cmd == 's' || *cmd == '&') { |
else if (*cmd == 's' || *cmd == '&') { |
char *what, *with, delim; |
char *what, *with, delim; |
int len, from_len; |
size_t len, from_len; |
size_t size; |
size_t size; |
|
|
if (*cmd == '&' && (from == NULL || to == NULL)) |
if (*cmd == '&' && (from == NULL || to == NULL)) |
Line 555 _history_expand_command(const char *comm |
|
Line 712 _history_expand_command(const char *comm |
|
what = realloc(from, size); |
what = realloc(from, size); |
if (what == NULL) { |
if (what == NULL) { |
free(from); |
free(from); |
return NULL; |
return 0; |
} |
} |
len = 0; |
len = 0; |
for (; *cmd && *cmd != delim; cmd++) { |
for (; *cmd && *cmd != delim; cmd++) { |
if (*cmd == '\\' |
if (*cmd == '\\' && cmd[1] == delim) |
&& *(cmd + 1) == delim) |
|
cmd++; |
cmd++; |
if (len >= size) { |
if (len >= size) { |
char *nwhat; |
char *nwhat; |
nwhat = realloc(what, |
nwhat = realloc(what, |
(size <<= 1)); |
(size <<= 1)); |
if (nwhat == NULL) { |
if (nwhat == NULL) { |
free(what); |
free(what); |
return NULL; |
return 0; |
} |
} |
what = nwhat; |
what = nwhat; |
} |
} |
Line 581 _history_expand_command(const char *comm |
|
Line 737 _history_expand_command(const char *comm |
|
if (search) { |
if (search) { |
from = strdup(search); |
from = strdup(search); |
if (from == NULL) |
if (from == NULL) |
return NULL; |
return 0; |
} else { |
} else { |
from = NULL; |
from = NULL; |
return (-1); |
return (-1); |
Line 612 _history_expand_command(const char *comm |
|
Line 768 _history_expand_command(const char *comm |
|
} |
} |
if (*cmd == '&') { |
if (*cmd == '&') { |
/* safe */ |
/* safe */ |
(void) strcpy(&with[len], from); |
(void)strcpy(&with[len], from); |
len += from_len; |
len += from_len; |
continue; |
continue; |
} |
} |
Line 624 _history_expand_command(const char *comm |
|
Line 780 _history_expand_command(const char *comm |
|
} |
} |
with[len] = '\0'; |
with[len] = '\0'; |
to = with; |
to = with; |
|
|
tempcmd = _rl_compat_sub(line, from, to, |
|
(g_on) ? 1 : 0); |
|
if (tempcmd) { |
|
free(line); |
|
line = tempcmd; |
|
} |
|
g_on = 0; |
|
} |
} |
} |
|
} |
|
|
|
arr = history_tokenize(line); |
aptr = _rl_compat_sub(tmp, from, to, g_on); |
free(line); /* no more needed */ |
if (aptr) { |
if (arr && *arr == NULL) |
free(tmp); |
free(arr), arr = NULL; |
tmp = aptr; |
if (!arr) |
|
return (-1); |
|
|
|
/* find out max valid idx to array of array */ |
|
max = 0; |
|
for (i = 0; arr[i]; i++) |
|
max++; |
|
max--; |
|
|
|
/* set boundaries to something relevant */ |
|
if (start < 0) |
|
start = 1; |
|
if (end < 0) |
|
end = max - ((end < -1) ? 1 : 0); |
|
|
|
/* check boundaries ... */ |
|
if (start > max || end > max || start > end) |
|
return (-1); |
|
|
|
for (i = 0; i <= max; i++) { |
|
char *temp; |
|
if (h_on && (i == 1 || h_on > 1) && |
|
(temp = strrchr(arr[i], '/'))) |
|
*(temp + 1) = '\0'; |
|
if (t_on && (i == 1 || t_on > 1) && |
|
(temp = strrchr(arr[i], '/'))) |
|
(void) strcpy(arr[i], temp + 1); |
|
if (r_on && (i == 1 || r_on > 1) && |
|
(temp = strrchr(arr[i], '.'))) |
|
*temp = '\0'; |
|
if (e_on && (i == 1 || e_on > 1) && |
|
(temp = strrchr(arr[i], '.'))) |
|
(void) strcpy(arr[i], temp); |
|
} |
|
|
|
cmdsize = 1, cmdlen = 0; |
|
if ((tempcmd = malloc(cmdsize)) == NULL) |
|
return NULL; |
|
for (i = start; start <= i && i <= end; i++) { |
|
int arr_len; |
|
|
|
arr_len = strlen(arr[i]); |
|
if (cmdlen + arr_len + 1 >= cmdsize) { |
|
char *ntempcmd; |
|
cmdsize += arr_len + 1; |
|
ntempcmd = realloc(tempcmd, cmdsize); |
|
if (ntempcmd == NULL) { |
|
free(tempcmd); |
|
return NULL; |
|
} |
} |
tempcmd = ntempcmd; |
g_on = 0; |
} |
} |
(void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ |
|
cmdlen += arr_len; |
|
tempcmd[cmdlen++] = ' '; /* add a space */ |
|
} |
} |
while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1])) |
*result = tmp; |
cmdlen--; |
return (p_on? 2:1); |
tempcmd[cmdlen] = '\0'; |
|
|
|
*result = tempcmd; |
|
|
|
for (i = 0; i <= max; i++) |
|
free(arr[i]); |
|
free(arr), arr = (char **) NULL; |
|
return (p_on) ? 2 : 1; |
|
} |
} |
|
|
|
|
Line 715 _history_expand_command(const char *comm |
|
Line 801 _history_expand_command(const char *comm |
|
int |
int |
history_expand(char *str, char **output) |
history_expand(char *str, char **output) |
{ |
{ |
int i, retval = 0, idx; |
int ret = 0; |
size_t size; |
size_t idx, i, size; |
char *temp, *result; |
char *tmp, *result; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
*output = strdup(str); /* do it early */ |
if (history_expansion_char == 0) { |
if (*output == NULL) |
*output = strdup(str); |
return NULL; |
return(0); |
|
} |
|
|
|
*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^ */ |
temp = alloca(4 + strlen(str) + 1); |
*output = malloc(strlen(str) + 4 + 1); |
temp[0] = temp[1] = history_expansion_char; |
if (*output == NULL) |
temp[2] = ':'; |
return 0; |
temp[3] = 's'; |
(*output)[0] = (*output)[1] = history_expansion_char; |
(void) strcpy(temp + 4, str); |
(*output)[2] = ':'; |
str = temp; |
(*output)[3] = 's'; |
|
(void)strcpy((*output) + 4, str); |
|
str = *output; |
|
} else { |
|
*output = strdup(str); |
|
if (*output == NULL) |
|
return 0; |
} |
} |
#define ADD_STRING(what, len) \ |
|
|
#define ADD_STRING(what, len) \ |
{ \ |
{ \ |
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); \ |
return NULL; \ |
return 0; \ |
} \ |
} \ |
result = nresult; \ |
result = nresult; \ |
} \ |
} \ |
Line 753 history_expand(char *str, char **output) |
|
Line 848 history_expand(char *str, char **output) |
|
result = NULL; |
result = NULL; |
size = idx = 0; |
size = idx = 0; |
for (i = 0; str[i];) { |
for (i = 0; str[i];) { |
int start, j, loop_again; |
int qchar, loop_again; |
size_t len; |
size_t len, start, j; |
|
|
|
qchar = 0; |
loop_again = 1; |
loop_again = 1; |
start = j = i; |
start = j = i; |
loop: |
loop: |
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]); |
(void)strcpy(&str[j], &str[j + 1]); |
continue; |
continue; |
} |
} |
if (!loop_again) { |
if (!loop_again) { |
if (str[j] == '?') { |
if (isspace((unsigned char) str[j]) |
while (str[j] && str[++j] != '?'); |
|| str[j] == qchar) |
if (str[j] == '?') |
|
j++; |
|
} else if (isspace((unsigned char) str[j])) |
|
break; |
break; |
} |
} |
if (str[j] == history_expansion_char |
if (str[j] == history_expansion_char |
&& !strchr(history_no_expand_chars, str[j + 1]) |
&& !strchr(history_no_expand_chars, str[j + 1]) |
&& (!history_inhibit_expansion_function || |
&& (!history_inhibit_expansion_function || |
(*history_inhibit_expansion_function)(str, j) == 0)) |
(*history_inhibit_expansion_function)(str, |
|
(int)j) == 0)) |
break; |
break; |
} |
} |
|
|
if (str[j] && str[j + 1] != '#' && loop_again) { |
if (str[j] && loop_again) { |
i = j; |
i = j; |
|
qchar = (j > 0 && str[j - 1] == '"' )? '"':0; |
j++; |
j++; |
if (str[j] == history_expansion_char) |
if (str[j] == history_expansion_char) |
j++; |
j++; |
|
|
goto loop; |
goto loop; |
} |
} |
len = i - start; |
len = i - start; |
temp = &str[start]; |
tmp = &str[start]; |
ADD_STRING(temp, len); |
ADD_STRING(tmp, len); |
|
|
if (str[i] == '\0' || str[i] != history_expansion_char |
if (str[i] == '\0' || str[i] != history_expansion_char) { |
|| str[i + 1] == '#') { |
|
len = j - i; |
len = j - i; |
temp = &str[i]; |
tmp = &str[i]; |
ADD_STRING(temp, len); |
ADD_STRING(tmp, len); |
if (start == 0) |
if (start == 0) |
retval = 0; |
ret = 0; |
else |
else |
retval = 1; |
ret = 1; |
break; |
break; |
} |
} |
retval = _history_expand_command(&str[i], (size_t) (j - i), |
ret = _history_expand_command (str, i, (j - i), &tmp); |
&temp); |
if (ret > 0 && tmp) { |
if (retval != -1) { |
len = strlen(tmp); |
len = strlen(temp); |
ADD_STRING(tmp, len); |
ADD_STRING(temp, len); |
free(tmp); |
} |
} |
i = j; |
i = j; |
} /* for(i ...) */ |
} |
|
|
if (retval == 2) { |
/* ret is 2 for "print only" option */ |
add_history(temp); |
if (ret == 2) { |
|
add_history(result); |
#ifdef GDB_411_HACK |
#ifdef GDB_411_HACK |
/* gdb 4.11 has been shipped with readline, where */ |
/* gdb 4.11 has been shipped with readline, where */ |
/* history_expand() returned -1 when the line */ |
/* history_expand() returned -1 when the line */ |
/* should not be executed; in readline 2.1+ */ |
/* should not be executed; in readline 2.1+ */ |
/* it should return 2 in such a case */ |
/* it should return 2 in such a case */ |
retval = -1; |
ret = -1; |
#endif |
#endif |
} |
} |
free(*output); |
free(*output); |
*output = result; |
*output = result; |
|
|
return (retval); |
return (ret); |
} |
} |
|
|
|
/* |
|
* Return a string consisting of arguments of "str" from "start" to "end". |
|
*/ |
|
char * |
|
history_arg_extract(int start, int end, const char *str) |
|
{ |
|
size_t i, len, max; |
|
char **arr, *result; |
|
|
|
arr = history_tokenize(str); |
|
if (!arr) |
|
return(NULL); |
|
if (arr && *arr == NULL) { |
|
free(arr); |
|
return(NULL); |
|
} |
|
|
|
for (max = 0; arr[max]; max++) |
|
continue; |
|
max--; |
|
|
|
if (start == '$') |
|
start = max; |
|
if (end == '$') |
|
end = max; |
|
if (end < 0) |
|
end = max + end + 1; |
|
if (start < 0) |
|
start = end; |
|
|
|
if (start < 0 || end < 0 || start > max || end > max || start > end) |
|
return(NULL); |
|
|
|
for (i = start, len = 0; i <= end; i++) |
|
len += strlen(arr[i]) + 1; |
|
len++; |
|
result = malloc(len); |
|
if (result == NULL) |
|
return NULL; |
|
|
|
for (i = start, len = 0; i <= end; i++) { |
|
(void)strcpy(result + len, arr[i]); |
|
len += strlen(arr[i]); |
|
if (i < end) |
|
result[len++] = ' '; |
|
} |
|
result[len] = 0; |
|
|
|
for (i = 0; arr[i]; i++) |
|
free(arr[i]); |
|
free(arr); |
|
|
|
return(result); |
|
} |
|
|
/* |
/* |
* Parse the string into individual tokens, similarily to how shell would do it. |
* Parse the string into individual tokens, |
|
* similar to how shell would do it. |
*/ |
*/ |
char ** |
char ** |
history_tokenize(const char *str) |
history_tokenize(const char *str) |
{ |
{ |
int size = 1, result_idx = 0, i, start; |
int size = 1, idx = 0, i, start; |
size_t len; |
size_t len; |
char **result = NULL, *temp, delim = '\0'; |
char **result = NULL, *temp, delim = '\0'; |
|
|
for (i = 0; str[i]; i++) { |
for (i = 0; str[i];) { |
while (isspace((unsigned char) str[i])) |
while (isspace((unsigned char) str[i])) |
i++; |
i++; |
start = i; |
start = i; |
for (; str[i]; i++) { |
for (; str[i];) { |
if (str[i] == '\\') { |
if (str[i] == '\\') { |
if (str[i+1] != '\0') |
if (str[i+1] != '\0') |
i++; |
i++; |
Line 855 history_tokenize(const char *str) |
|
Line 1005 history_tokenize(const char *str) |
|
break; |
break; |
else if (!delim && strchr("'`\"", str[i])) |
else if (!delim && strchr("'`\"", str[i])) |
delim = str[i]; |
delim = str[i]; |
|
if (str[i]) |
|
i++; |
} |
} |
|
|
if (result_idx + 2 >= size) { |
if (idx + 2 >= size) { |
char **nresult; |
char **nresult; |
size <<= 1; |
size <<= 1; |
nresult = realloc(result, size * sizeof(char *)); |
nresult = realloc(result, size * sizeof(char *)); |
Line 870 history_tokenize(const char *str) |
|
Line 1022 history_tokenize(const char *str) |
|
len = i - start; |
len = i - start; |
temp = malloc(len + 1); |
temp = malloc(len + 1); |
if (temp == NULL) { |
if (temp == NULL) { |
|
for (i = 0; i < idx; i++) |
|
free(result[i]); |
free(result); |
free(result); |
return NULL; |
return NULL; |
} |
} |
(void) strncpy(temp, &str[start], len); |
(void)strncpy(temp, &str[start], len); |
temp[len] = '\0'; |
temp[len] = '\0'; |
result[result_idx++] = temp; |
result[idx++] = temp; |
result[result_idx] = NULL; |
result[idx] = NULL; |
|
if (str[i]) |
|
i++; |
} |
} |
|
|
return (result); |
return (result); |
} |
} |
|
|
Line 962 history_get(int num) |
|
Line 1117 history_get(int num) |
|
{ |
{ |
static HIST_ENTRY she; |
static HIST_ENTRY she; |
HistEvent ev; |
HistEvent ev; |
int i = 1, curr_num; |
int curr_num; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
/* rewind to beginning */ |
/* 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; |
if (history(h, &ev, H_LAST) != 0) |
|
|
/* start from most recent */ |
|
if (history(h, &ev, H_FIRST) != 0) |
return (NULL); /* error */ |
return (NULL); /* error */ |
while (i < num && history(h, &ev, H_PREV) == 0) |
|
i++; |
/* look backwards for event matching specified offset */ |
if (i != num) |
if (history(h, &ev, H_NEXT_EVENT, num)) |
return (NULL); /* not so many entries */ |
return (NULL); |
|
|
she.line = ev.str; |
she.line = ev.str; |
she.data = NULL; |
she.data = NULL; |
|
|
/* rewind history to the same event it was before */ |
/* restore pointer to where it was */ |
(void) history(h, &ev, H_FIRST); |
(void)history(h, &ev, H_SET, curr_num); |
(void) history(h, &ev, H_NEXT_EVENT, curr_num); |
|
|
|
return (&she); |
return (&she); |
} |
} |
Line 1000 add_history(const char *line) |
|
Line 1156 add_history(const char *line) |
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
(void) history(h, &ev, H_ENTER, line); |
(void)history(h, &ev, H_ENTER, line); |
if (history(h, &ev, H_GETSIZE) == 0) |
if (history(h, &ev, H_GETSIZE) == 0) |
history_length = ev.num; |
history_length = ev.num; |
|
|
return (!(history_length > 0)); /* return 0 if all is okay */ |
return (!(history_length > 0)); /* return 0 if all is okay */ |
} |
} |
|
|
|
|
|
|
history_set_pos(int pos) |
history_set_pos(int pos) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
int off, 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; |
history(h, &ev, H_FIRST); |
|
off = 0; |
|
while (off < pos && history(h, &ev, H_NEXT) == 0) |
|
off++; |
|
|
|
if (off != pos) { /* do a rollback in case of error */ |
if (history(h, &ev, H_SET, pos)) { |
history(h, &ev, H_FIRST); |
history(h, &ev, H_SET, curr_num); |
history(h, &ev, H_NEXT_EVENT, curr_num); |
return(-1); |
return (-1); |
|
} |
} |
return (0); |
return (0); |
} |
} |
Line 1130 next_history(void) |
|
Line 1281 next_history(void) |
|
|
|
|
|
/* |
/* |
* generic history search function |
* searches for first history event containing the str |
*/ |
*/ |
static int |
int |
_history_search_gen(const char *str, int direction, int pos) |
history_search(const char *str, int direction) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
const char *strp; |
const char *strp; |
Line 1144 _history_search_gen(const char *str, int |
|
Line 1295 _history_search_gen(const char *str, int |
|
curr_num = ev.num; |
curr_num = ev.num; |
|
|
for (;;) { |
for (;;) { |
strp = strstr(ev.str, str); |
if ((strp = strstr(ev.str, str)) != NULL) |
if (strp && (pos < 0 || &ev.str[pos] == strp)) |
|
return (int) (strp - ev.str); |
return (int) (strp - ev.str); |
if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0) |
if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) |
break; |
break; |
} |
} |
|
history(h, &ev, H_SET, curr_num); |
history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); |
|
|
|
return (-1); |
return (-1); |
} |
} |
|
|
|
|
/* |
/* |
* searches for first history event containing the str |
|
*/ |
|
int |
|
history_search(const char *str, int direction) |
|
{ |
|
|
|
return (_history_search_gen(str, direction, -1)); |
|
} |
|
|
|
|
|
/* |
|
* searches for first history event beginning with str |
* searches for first history event beginning with str |
*/ |
*/ |
int |
int |
history_search_prefix(const char *str, int direction) |
history_search_prefix(const char *str, int direction) |
{ |
{ |
|
HistEvent ev; |
|
|
return (_history_search_gen(str, direction, 0)); |
return (history(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str)); |
} |
} |
|
|
|
|
Line 1185 history_search_prefix(const char *str, i |
|
Line 1323 history_search_prefix(const char *str, i |
|
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
int |
int |
history_search_pos(const char *str, int direction, int pos) |
history_search_pos(const char *str, |
|
int direction __attribute__((__unused__)), int pos) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
int curr_num, off; |
int curr_num, off; |
Line 1216 history_search_pos(const char *str, int |
|
Line 1355 history_search_pos(const char *str, int |
|
|
|
|
|
/********************************/ |
/********************************/ |
/* completition functions */ |
/* completion functions */ |
|
|
/* |
/* |
* does tilde expansion of strings of type ``~user/foo'' |
* does tilde expansion of strings of type ``~user/foo'' |
Line 1245 tilde_expand(char *txt) |
|
Line 1384 tilde_expand(char *txt) |
|
temp = malloc(len); |
temp = malloc(len); |
if (temp == NULL) |
if (temp == NULL) |
return NULL; |
return NULL; |
(void) strncpy(temp, txt + 1, len - 2); |
(void)strncpy(temp, txt + 1, len - 2); |
temp[len - 2] = '\0'; |
temp[len - 2] = '\0'; |
} |
} |
pass = getpwnam(temp); |
pass = getpwnam(temp); |
Line 1260 tilde_expand(char *txt) |
|
Line 1399 tilde_expand(char *txt) |
|
temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); |
temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); |
if (temp == NULL) |
if (temp == NULL) |
return NULL; |
return NULL; |
(void) sprintf(temp, "%s/%s", pass->pw_dir, txt); |
(void)sprintf(temp, "%s/%s", pass->pw_dir, txt); |
|
|
return (temp); |
return (temp); |
} |
} |
Line 1294 filename_completion_function(const char |
|
Line 1433 filename_completion_function(const char |
|
return NULL; |
return NULL; |
} |
} |
filename = nptr; |
filename = nptr; |
(void) strcpy(filename, temp); |
(void)strcpy(filename, temp); |
len = temp - text; /* including last slash */ |
len = temp - text; /* including last slash */ |
nptr = realloc(dirname, len + 1); |
nptr = realloc(dirname, len + 1); |
if (nptr == NULL) { |
if (nptr == NULL) { |
Line 1302 filename_completion_function(const char |
|
Line 1441 filename_completion_function(const char |
|
return NULL; |
return NULL; |
} |
} |
dirname = nptr; |
dirname = nptr; |
(void) strncpy(dirname, text, len); |
(void)strncpy(dirname, text, len); |
dirname[len] = '\0'; |
dirname[len] = '\0'; |
} else { |
} else { |
filename = strdup(text); |
if (*text == 0) |
if (filename == NULL) |
filename = NULL; |
return NULL; |
else { |
|
filename = strdup(text); |
|
if (filename == NULL) |
|
return NULL; |
|
} |
dirname = NULL; |
dirname = NULL; |
} |
} |
|
|
Line 1323 filename_completion_function(const char |
|
Line 1466 filename_completion_function(const char |
|
return NULL; |
return NULL; |
} |
} |
dirname = nptr; |
dirname = nptr; |
(void) strcpy(dirname, temp); /* safe */ |
(void)strcpy(dirname, temp); /* safe */ |
free(temp); /* no longer needed */ |
free(temp); /* no longer needed */ |
} |
} |
/* will be used in cycle */ |
/* will be used in cycle */ |
filename_len = strlen(filename); |
filename_len = filename ? strlen(filename) : 0; |
if (filename_len == 0) |
|
return (NULL); /* no expansion possible */ |
|
|
|
if (dir != NULL) { |
if (dir != NULL) { |
(void)closedir(dir); |
(void)closedir(dir); |
Line 1341 filename_completion_function(const char |
|
Line 1482 filename_completion_function(const char |
|
} |
} |
/* find the match */ |
/* find the match */ |
while ((entry = readdir(dir)) != NULL) { |
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 */ |
/* otherwise, get first entry where first */ |
/* filename_len characters are equal */ |
/* filename_len characters are equal */ |
if (entry->d_name[0] == filename[0] |
if (entry->d_name[0] == filename[0] |
Line 1366 filename_completion_function(const char |
|
Line 1513 filename_completion_function(const char |
|
temp = malloc(len); |
temp = malloc(len); |
if (temp == NULL) |
if (temp == NULL) |
return NULL; |
return NULL; |
(void) sprintf(temp, "%s%s", |
(void)sprintf(temp, "%s%s", |
dirname ? dirname : "", entry->d_name); /* safe */ |
dirname ? dirname : "", entry->d_name); /* safe */ |
|
|
/* test, if it's directory */ |
/* test, if it's directory */ |
Line 1419 username_completion_function(const char |
|
Line 1566 username_completion_function(const char |
|
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
static unsigned char |
static unsigned char |
_el_rl_complete(EditLine *el, int ch) |
_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) |
{ |
{ |
return (unsigned char) rl_complete(0, ch); |
return (unsigned char) rl_complete(0, ch); |
} |
} |
|
|
|
|
/* |
/* |
* returns list of completitions for text given |
* returns list of completions for text given |
*/ |
*/ |
char ** |
char ** |
completion_matches(const char *text, CPFunction *genfunc) |
completion_matches(const char *text, CPFunction *genfunc) |
{ |
{ |
char **match_list = NULL, *retstr, *prevstr; |
char **match_list = NULL, *retstr, *prevstr; |
size_t match_list_len, max_equal, which, i; |
size_t match_list_len, max_equal, which, i; |
int matches; |
size_t matches; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
matches = 0; |
matches = 0; |
match_list_len = 1; |
match_list_len = 1; |
while ((retstr = (*genfunc) (text, matches)) != NULL) { |
while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { |
/* allow for list terminator here */ |
/* allow for list terminator here */ |
if (matches + 2 >= match_list_len) { |
if (matches + 3 >= match_list_len) { |
char **nmatch_list; |
char **nmatch_list; |
match_list_len <<= 1; |
while (matches + 3 >= match_list_len) |
|
match_list_len <<= 1; |
nmatch_list = realloc(match_list, |
nmatch_list = realloc(match_list, |
match_list_len * sizeof(char *)); |
match_list_len * sizeof(char *)); |
if (nmatch_list == NULL) { |
if (nmatch_list == NULL) { |
Line 1476 completion_matches(const char *text, CPF |
|
Line 1624 completion_matches(const char *text, CPF |
|
free(match_list); |
free(match_list); |
return NULL; |
return NULL; |
} |
} |
(void) strncpy(retstr, match_list[1], max_equal); |
(void)strncpy(retstr, match_list[1], max_equal); |
retstr[max_equal] = '\0'; |
retstr[max_equal] = '\0'; |
match_list[0] = retstr; |
match_list[0] = retstr; |
|
|
Line 1531 rl_display_match_list (matches, len, max |
|
Line 1679 rl_display_match_list (matches, len, max |
|
|
|
idx = 1; |
idx = 1; |
for(; count > 0; count--) { |
for(; count > 0; count--) { |
for(i=0; i < limit && matches[idx]; i++, idx++) |
for(i = 0; i < limit && matches[idx]; i++, idx++) |
fprintf(e->el_outfile, "%-*s ", max, matches[idx]); |
(void)fprintf(e->el_outfile, "%-*s ", max, |
fprintf(e->el_outfile, "\n"); |
matches[idx]); |
|
(void)fprintf(e->el_outfile, "\n"); |
} |
} |
} |
} |
|
|
Line 1551 rl_display_match_list (matches, len, max |
|
Line 1700 rl_display_match_list (matches, len, max |
|
static int |
static int |
rl_complete_internal(int what_to_do) |
rl_complete_internal(int what_to_do) |
{ |
{ |
CPFunction *complet_func; |
Function *complet_func; |
const LineInfo *li; |
const LineInfo *li; |
char *temp, **matches; |
char *temp, **matches; |
const char *ctemp; |
const char *ctemp; |
Line 1564 rl_complete_internal(int what_to_do) |
|
Line 1713 rl_complete_internal(int what_to_do) |
|
|
|
complet_func = rl_completion_entry_function; |
complet_func = rl_completion_entry_function; |
if (!complet_func) |
if (!complet_func) |
complet_func = filename_completion_function; |
complet_func = (Function *)(void *)filename_completion_function; |
|
|
/* We now look backwards for the start of a filename/variable word */ |
/* We now look backwards for the start of a filename/variable word */ |
li = el_line(e); |
li = el_line(e); |
Line 1572 rl_complete_internal(int what_to_do) |
|
Line 1721 rl_complete_internal(int what_to_do) |
|
while (ctemp > li->buffer |
while (ctemp > li->buffer |
&& !strchr(rl_basic_word_break_characters, ctemp[-1]) |
&& !strchr(rl_basic_word_break_characters, ctemp[-1]) |
&& (!rl_special_prefixes |
&& (!rl_special_prefixes |
|| !strchr(rl_special_prefixes, ctemp[-1]) ) ) |
|| !strchr(rl_special_prefixes, ctemp[-1]) ) ) |
ctemp--; |
ctemp--; |
|
|
len = li->cursor - ctemp; |
len = li->cursor - ctemp; |
temp = alloca(len + 1); |
temp = alloca(len + 1); |
(void) strncpy(temp, ctemp, len); |
(void)strncpy(temp, ctemp, len); |
temp[len] = '\0'; |
temp[len] = '\0'; |
|
|
/* these can be used by function called in completion_matches() */ |
/* these can be used by function called in completion_matches() */ |
Line 1585 rl_complete_internal(int what_to_do) |
|
Line 1734 rl_complete_internal(int what_to_do) |
|
rl_point = li->cursor - li->buffer; |
rl_point = li->cursor - li->buffer; |
rl_end = li->lastchar - li->buffer; |
rl_end = li->lastchar - li->buffer; |
|
|
if (!rl_attempted_completion_function) |
if (rl_attempted_completion_function) { |
matches = completion_matches(temp, complet_func); |
|
else { |
|
int end = li->cursor - li->buffer; |
int end = li->cursor - li->buffer; |
matches = (*rl_attempted_completion_function) (temp, (int) |
matches = (*rl_attempted_completion_function) (temp, (int) |
(end - len), end); |
(end - len), end); |
} |
} else |
|
matches = 0; |
|
if (!rl_attempted_completion_function || !matches) |
|
matches = completion_matches(temp, (CPFunction *)complet_func); |
|
|
if (matches) { |
if (matches) { |
int i, retval = CC_REFRESH; |
int i, retval = CC_REFRESH; |
Line 1612 rl_complete_internal(int what_to_do) |
|
Line 1762 rl_complete_internal(int what_to_do) |
|
if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { |
if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { |
/* |
/* |
* We found exact match. Add a space after |
* We found exact match. Add a space after |
* it, unless we do filename completition and the |
* it, unless we do filename completion and the |
* object is a directory. |
* object is a directory. |
*/ |
*/ |
size_t alen = strlen(matches[0]); |
size_t alen = strlen(matches[0]); |
if ((complet_func != filename_completion_function |
if ((complet_func != |
|
(Function *)filename_completion_function |
|| (alen > 0 && (matches[0])[alen - 1] != '/')) |
|| (alen > 0 && (matches[0])[alen - 1] != '/')) |
&& rl_completion_append_character) { |
&& rl_completion_append_character) { |
char buf[2]; |
char buf[2]; |
Line 1639 rl_complete_internal(int what_to_do) |
|
Line 1790 rl_complete_internal(int what_to_do) |
|
matches_num = i - 1; |
matches_num = i - 1; |
|
|
/* newline to get on next line from command line */ |
/* newline to get on next line from command line */ |
fprintf(e->el_outfile, "\n"); |
(void)fprintf(e->el_outfile, "\n"); |
|
|
/* |
/* |
* If there are too many items, ask user for display |
* If there are too many items, ask user for display |
* confirmation. |
* confirmation. |
*/ |
*/ |
if (matches_num > rl_completion_query_items) { |
if (matches_num > rl_completion_query_items) { |
fprintf(e->el_outfile, |
(void)fprintf(e->el_outfile, |
"Display all %d possibilities? (y or n) ", |
"Display all %d possibilities? (y or n) ", |
matches_num); |
matches_num); |
fflush(e->el_outfile); |
(void)fflush(e->el_outfile); |
if (getc(stdin) != 'y') |
if (getc(stdin) != 'y') |
match_display = 0; |
match_display = 0; |
fprintf(e->el_outfile, "\n"); |
(void)fprintf(e->el_outfile, "\n"); |
} |
} |
|
|
if (match_display) |
if (match_display) |
Line 1750 rl_read_key(void) |
|
Line 1901 rl_read_key(void) |
|
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
void |
void |
rl_reset_terminal(const char *p) |
rl_reset_terminal(const char *p __attribute__((__unused__))) |
{ |
{ |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
Line 1779 rl_insert(int count, int c) |
|
Line 1930 rl_insert(int count, int c) |
|
|
|
return (0); |
return (0); |
} |
} |
|
|
|
/*ARGSUSED*/ |
|
int |
|
rl_newline(int count, int c) |
|
{ |
|
/* |
|
* Readline-4.0 appears to ignore the args. |
|
*/ |
|
return rl_insert(1, '\n'); |
|
} |
|
|
|
/*ARGSUSED*/ |
|
static unsigned char |
|
rl_bind_wrapper(EditLine *el, unsigned char c) |
|
{ |
|
if (map[c] == NULL) |
|
return CC_ERROR; |
|
(*map[c])(NULL, c); |
|
|
|
/* If rl_done was set by the above call, deal with it here */ |
|
if (rl_done) |
|
return CC_EOF; |
|
|
|
return CC_NORM; |
|
} |
|
|
|
int |
|
rl_add_defun(const char *name, Function *fun, int c) |
|
{ |
|
char dest[8]; |
|
if (c >= sizeof(map) / sizeof(map[0]) || c < 0) |
|
return -1; |
|
map[(unsigned char)c] = fun; |
|
el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); |
|
vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); |
|
el_set(e, EL_BIND, dest, name); |
|
return 0; |
|
} |
|
|
|
void |
|
rl_callback_read_char() |
|
{ |
|
int count = 0, done = 0; |
|
const char *buf = el_gets(e, &count); |
|
char *wbuf; |
|
|
|
if (buf == NULL || count-- <= 0) |
|
return; |
|
if (count == 0 && buf[0] == CTRL('d')) |
|
done = 1; |
|
if (buf[count] == '\n' || buf[count] == '\r') |
|
done = 2; |
|
|
|
if (done && rl_linefunc != NULL) { |
|
el_set(e, EL_UNBUFFERED, 0); |
|
if (done == 2) { |
|
if ((wbuf = strdup(buf)) != NULL) |
|
wbuf[count] = '\0'; |
|
} else |
|
wbuf = NULL; |
|
(*(void (*)(const char *))rl_linefunc)(wbuf); |
|
} |
|
} |
|
|
|
void |
|
rl_callback_handler_install (const char *prompt, VFunction *linefunc) |
|
{ |
|
if (e == NULL) { |
|
rl_initialize(); |
|
} |
|
if (rl_prompt) |
|
free(rl_prompt); |
|
rl_prompt = prompt ? strdup(strchr(prompt, *prompt)) : NULL; |
|
rl_linefunc = linefunc; |
|
el_set(e, EL_UNBUFFERED, 1); |
|
} |
|
|
|
void |
|
rl_callback_handler_remove(void) |
|
{ |
|
el_set(e, EL_UNBUFFERED, 0); |
|
} |
|
|
|
void |
|
rl_redisplay(void) |
|
{ |
|
char a[2]; |
|
a[0] = CTRL('r'); |
|
a[1] = '\0'; |
|
el_push(e, a); |
|
} |
|
|
|
int |
|
rl_get_previous_history(int count, int key) |
|
{ |
|
char a[2]; |
|
a[0] = key; |
|
a[1] = '\0'; |
|
while (count--) |
|
el_push(e, a); |
|
return 0; |
|
} |
|
|
|
void |
|
/*ARGSUSED*/ |
|
rl_prep_terminal(int meta_flag) |
|
{ |
|
el_set(e, EL_PREP_TERM, 1); |
|
} |
|
|
|
void |
|
rl_deprep_terminal() |
|
{ |
|
el_set(e, EL_PREP_TERM, 0); |
|
} |
|
|
|
int |
|
rl_read_init_file(const char *s) |
|
{ |
|
return(el_source(e, s)); |
|
} |
|
|
|
int |
|
rl_parse_and_bind(const char *line) |
|
{ |
|
const char **argv; |
|
int argc; |
|
Tokenizer *tok; |
|
|
|
tok = tok_init(NULL); |
|
tok_str(tok, line, &argc, &argv); |
|
argc = el_parse(e, argc, argv); |
|
tok_end(tok); |
|
return (argc ? 1 : 0); |
|
} |
|
|
|
void |
|
rl_stuff_char(int c) |
|
{ |
|
char buf[2]; |
|
|
|
buf[0] = c; |
|
buf[1] = '\0'; |
|
el_insertstr(e, buf); |
|
} |
|
|
|
static int |
|
_rl_event_read_char(EditLine *el, char *cp) |
|
{ |
|
int n, num_read = 0; |
|
|
|
*cp = 0; |
|
while (rl_event_hook) { |
|
|
|
(*rl_event_hook)(); |
|
|
|
#if defined(FIONREAD) |
|
if (ioctl(el->el_infd, FIONREAD, &n) < 0) |
|
return(-1); |
|
if (n) |
|
num_read = read(el->el_infd, cp, 1); |
|
else |
|
num_read = 0; |
|
#elif defined(F_SETFL) && defined(O_NDELAY) |
|
if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) |
|
return(-1); |
|
if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) |
|
return(-1); |
|
num_read = read(el->el_infd, cp, 1); |
|
if (fcntl(el->el_infd, F_SETFL, n)) |
|
return(-1); |
|
#else |
|
/* not non-blocking, but what you gonna do? */ |
|
num_read = read(el->el_infd, cp, 1); |
|
return(-1); |
|
#endif |
|
|
|
if (num_read < 0 && errno == EAGAIN) |
|
continue; |
|
if (num_read == 0) |
|
continue; |
|
break; |
|
} |
|
if (!rl_event_hook) |
|
el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); |
|
return(num_read); |
|
} |