version 1.4, 1998/05/20 01:03:06 |
version 1.18, 2001/01/05 22:45:30 |
Line 52 __RCSID("$NetBSD$"); |
|
Line 52 __RCSID("$NetBSD$"); |
|
#include <unistd.h> |
#include <unistd.h> |
#include <limits.h> |
#include <limits.h> |
#include "histedit.h" |
#include "histedit.h" |
#include "readline.h" |
#include "readline/readline.h" |
#include "sys.h" |
#include "sys.h" |
#include "el.h" |
#include "el.h" |
|
#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 */ |
const char *rl_library_version = "EditLine wrapper"; |
const char *rl_library_version = "EditLine wrapper"; |
char *rl_readline_name = ""; |
char *rl_readline_name = ""; |
FILE *rl_instream = NULL; |
FILE *rl_instream = NULL; |
FILE *rl_outstream = NULL; |
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; |
|
|
int history_base = 1; /* probably never subject to change */ |
int history_base = 1; /* probably never subject to change */ |
int history_length = 0; |
int history_length = 0; |
int max_input_history = 0; |
int max_input_history = 0; |
char history_expansion_char = '!'; |
char history_expansion_char = '!'; |
char history_subst_char = '^'; |
char history_subst_char = '^'; |
char *history_no_expand_chars = " \t\n=("; |
char *history_no_expand_chars = " \t\n=("; |
Function *history_inhibit_expansion_function = NULL; |
Function *history_inhibit_expansion_function = NULL; |
|
|
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 = " \t\n\"\\'`@$><=;|&{("; |
char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; |
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; |
CPFunction *rl_completion_entry_function = NULL; |
CPPFunction *rl_attempted_completion_function = NULL; |
CPPFunction *rl_attempted_completion_function = NULL; |
|
|
|
/* |
|
* This is set to character indicating type of completion being done by |
|
* rl_complete_internal(); this is available for application completion |
|
* functions. |
|
*/ |
|
int rl_completion_type = 0; |
|
|
|
/* |
|
* If more than this number of items results from query for possible |
|
* completions, we ask user if they are sure to really display the list. |
|
*/ |
|
int rl_completion_query_items = 100; |
|
|
|
/* |
|
* List of characters which are word break characters, but should be left |
|
* in the parsed text when it is passed to the completion function. |
|
* Shell uses this to help determine what kind of completing to do. |
|
*/ |
|
char *rl_special_prefixes = (char *)NULL; |
|
|
|
/* |
|
* This is the character appended to the completed words if at the end of |
|
* the line. Default is ' ' (a space). |
|
*/ |
|
int rl_completion_append_character = ' '; |
|
|
|
/* 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; |
|
|
/* used for readline emulation */ |
|
static History *h = NULL; |
static History *h = NULL; |
static EditLine *e = NULL; |
static EditLine *e = NULL; |
|
static int el_rl_complete_cmdnum = 0; |
|
|
/* internal functions */ |
/* internal functions */ |
static unsigned char _el_rl_complete __P((EditLine *, int)); |
static unsigned char _el_rl_complete(EditLine *, int); |
static char *_get_prompt __P((EditLine *)); |
static char *_get_prompt(EditLine *); |
static HIST_ENTRY *_move_history __P((int)); |
static HIST_ENTRY *_move_history(int); |
static int _history_search_gen __P((const char *, int, int)); |
static int _history_search_gen(const char *, int, int); |
static int _history_expand_command __P((const char *, int, char **)); |
static int _history_expand_command(const char *, size_t, char **); |
static char *_rl_compat_sub __P((const char *, const char *, |
static char *_rl_compat_sub(const char *, const char *, |
const char *, int)); |
const char *, int); |
static int rl_complete_internal __P((int)); |
static int rl_complete_internal(int); |
|
static int _rl_qsort_string_compare(const void *, const void *); |
|
|
/* |
/* |
* needed for easy prompt switching |
* needed for prompt switching in readline() |
*/ |
*/ |
static char *el_rl_prompt = NULL; |
static char *el_rl_prompt = NULL; |
|
|
|
|
|
/* ARGSUSED */ |
static char * |
static char * |
_get_prompt(el) |
_get_prompt(EditLine *el) |
EditLine *el; |
|
{ |
{ |
return el_rl_prompt; |
return (el_rl_prompt); |
} |
} |
|
|
|
|
/* |
/* |
* generic function for moving around history |
* generic function for moving around history |
*/ |
*/ |
static HIST_ENTRY * |
static HIST_ENTRY * |
_move_history(op) |
_move_history(int op) |
int op; |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
static HIST_ENTRY rl_he; |
static HIST_ENTRY rl_he; |
Line 129 _move_history(op) |
|
Line 164 _move_history(op) |
|
rl_he.line = ev.str; |
rl_he.line = ev.str; |
rl_he.data = ""; |
rl_he.data = ""; |
|
|
return &rl_he; |
return (&rl_he); |
} |
} |
|
|
|
|
/* |
/* |
* READLINE compatibility stuff |
* READLINE compatibility stuff |
*/ |
*/ |
|
|
/* |
/* |
* initialize rl compat stuff |
* initialize rl compat stuff |
*/ |
*/ |
int |
int |
rl_initialize() |
rl_initialize(void) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
const LineInfo *li; |
const LineInfo *li; |
|
int i; |
|
int editmode = 1; |
|
struct termios t; |
|
|
if (e != NULL) |
if (e != NULL) |
el_end(e); |
el_end(e); |
|
|
rl_instream = stdin; |
rl_instream = stdin; |
if (!rl_outstream) |
if (!rl_outstream) |
rl_outstream = stdout; |
rl_outstream = stdout; |
|
|
|
/* |
|
* See if we don't really want to run the editor |
|
*/ |
|
if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) |
|
editmode = 0; |
|
|
e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); |
e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); |
|
|
|
if (!editmode) |
|
el_set(e, EL_EDITMODE, 0); |
|
|
h = history_init(); |
h = history_init(); |
if (!e || !h) |
if (!e || !h) |
return -1; |
return (-1); |
|
|
history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ |
history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ |
history_length = 0; |
history_length = 0; |
|
|
/* so this can be overriden */ |
/* so this can be overriden */ |
el_set(e, EL_EDITOR, "emacs"); |
el_set(e, EL_EDITOR, "emacs"); |
|
|
/* for word completition - this has to go AFTER rebinding keys */ |
/* |
/* to emacs-style */ |
* Word completition - this has to go AFTER rebinding keys |
|
* to emacs-style. |
|
*/ |
el_set(e, EL_ADDFN, "rl_complete", |
el_set(e, EL_ADDFN, "rl_complete", |
"ReadLine compatible completition function", |
"ReadLine compatible completition 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 |
|
* 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); |
|
|
/* some readline apps do use this */ |
/* |
|
* Unfortunately, some applications really do use rl_point |
|
* and rl_line_buffer directly. |
|
*/ |
li = el_line(e); |
li = el_line(e); |
|
/* LINTED const cast */ |
rl_line_buffer = (char *) li->buffer; |
rl_line_buffer = (char *) li->buffer; |
rl_point = rl_end = 0; |
rl_point = rl_end = 0; |
|
|
return 0; |
return (0); |
} |
} |
|
|
|
|
/* |
/* |
* read one line from input stream and return it, chomping |
* read one line from input stream and return it, chomping |
* trailing newline (if there is any) |
* trailing newline (if there is any) |
Line 207 readline(const char *prompt) |
|
Line 273 readline(const char *prompt) |
|
if (e == NULL || h == NULL) |
if (e == NULL || h == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
/* set the prompt */ |
/* update prompt accordingly to what has been passed */ |
|
if (!prompt) |
|
prompt = ""; |
if (strcmp(el_rl_prompt, prompt) != 0) { |
if (strcmp(el_rl_prompt, prompt) != 0) { |
free(el_rl_prompt); |
free(el_rl_prompt); |
el_rl_prompt = strdup(prompt); |
el_rl_prompt = strdup(prompt); |
Line 217 readline(const char *prompt) |
|
Line 285 readline(const char *prompt) |
|
|
|
if (ret && count > 0) { |
if (ret && count > 0) { |
char *foo; |
char *foo; |
off_t lastidx; |
int lastidx; |
|
|
foo = strdup(ret); |
foo = strdup(ret); |
lastidx = count - 1; |
lastidx = count - 1; |
Line 231 readline(const char *prompt) |
|
Line 299 readline(const char *prompt) |
|
history(h, &ev, H_GETSIZE); |
history(h, &ev, H_GETSIZE); |
history_length = ev.num; |
history_length = ev.num; |
|
|
|
/* LINTED const cast */ |
return (char *) ret; |
return (char *) ret; |
} |
} |
|
|
Line 243 readline(const char *prompt) |
|
Line 312 readline(const char *prompt) |
|
* history expansion functions |
* history expansion functions |
*/ |
*/ |
void |
void |
using_history() |
using_history(void) |
{ |
{ |
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
} |
} |
|
|
|
|
/* |
/* |
* 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 occurences of what, otherwise only the |
* first one |
* first one |
*/ |
*/ |
static char * |
static char * |
_rl_compat_sub(str, what, with, globally) |
_rl_compat_sub(const char *str, const char *what, const char *with, |
const char *str, *what, *with; |
int globally) |
int globally; |
{ |
{ |
char *result; |
char *result; |
const char *temp, *new; |
const char *temp, *new; |
int len, with_len, what_len, add; |
int size, len, i, with_len, what_len, add; |
size_t size, i; |
|
|
result = malloc((size = 16)); |
result = malloc((size = 16)); |
temp = str; |
temp = str; |
Line 277 _rl_compat_sub(str, what, with, globally |
|
Line 347 _rl_compat_sub(str, what, with, globally |
|
size += add + 1; |
size += add + 1; |
result = realloc(result, size); |
result = realloc(result, size); |
} |
} |
(void)strncpy(&result[len], temp, i); |
(void) strncpy(&result[len], temp, i); |
len += i; |
len += i; |
(void)strcpy(&result[len], with); /* safe */ |
(void) strcpy(&result[len], with); /* safe */ |
len += with_len; |
len += with_len; |
temp = new + what_len; |
temp = new + what_len; |
} else { |
} else { |
Line 288 _rl_compat_sub(str, what, with, globally |
|
Line 358 _rl_compat_sub(str, what, with, globally |
|
size += add + 1; |
size += add + 1; |
result = realloc(result, size); |
result = realloc(result, size); |
} |
} |
(void)strcpy(&result[len], temp); /* safe */ |
(void) strcpy(&result[len], temp); /* safe */ |
len += add; |
len += add; |
temp = NULL; |
temp = NULL; |
} |
} |
} while (temp); |
} while (temp && globally); |
result[len] = '\0'; |
result[len] = '\0'; |
|
|
return result; |
return (result); |
} |
} |
|
|
|
|
/* |
/* |
* 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 |
Line 310 _rl_compat_sub(str, what, with, globally |
|
Line 381 _rl_compat_sub(str, what, with, globally |
|
* 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(command, len, result) |
_history_expand_command(const char *command, size_t cmdlen, char **result) |
const char *command; |
{ |
int len; |
char **arr, *tempcmd, *line, *search = NULL, *cmd; |
char **result; |
const char *event_data = NULL; |
{ |
static char *from = NULL, *to = NULL; |
char **arr, *temp, *line, *search = NULL, *cmd; |
int start = -1, end = -1, max, i, idx; |
const char *event_data = NULL; |
int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, g_on = 0; |
static const char *from = NULL, *to = NULL; |
int event_num = 0, retval; |
int start = -1, end = -1, max, i, size, idx; |
size_t cmdsize; |
int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, |
|
g_on = 0; |
|
int event_num = 0, retval; |
|
|
|
*result = NULL; |
*result = NULL; |
|
|
cmd = alloca(len + 1); |
cmd = alloca(cmdlen + 1); |
(void)strncpy(cmd, command, len); |
(void) strncpy(cmd, command, cmdlen); |
cmd[len] = 0; |
cmd[cmdlen] = 0; |
|
|
idx = 1; |
idx = 1; |
/* find out which event to take */ |
/* find out which event to take */ |
Line 335 _history_expand_command(command, len, re |
|
Line 403 _history_expand_command(command, len, re |
|
event_num = history_length; |
event_num = history_length; |
idx++; |
idx++; |
} else { |
} else { |
int off, len, num; |
int off, num; |
|
size_t len; |
off = idx; |
off = idx; |
while (cmd[off] && !strchr(":^$*-%", cmd[off])) |
while (cmd[off] && !strchr(":^$*-%", cmd[off])) |
off++; |
off++; |
Line 354 _history_expand_command(command, len, re |
|
Line 423 _history_expand_command(command, len, re |
|
if (cmd[off - 1] == '?') |
if (cmd[off - 1] == '?') |
len--; |
len--; |
else if (cmd[off] != '\n' && cmd[off] != '\0') |
else if (cmd[off] != '\n' && cmd[off] != '\0') |
return -1; |
return (-1); |
prefix = 0; |
prefix = 0; |
} |
} |
search = alloca(len + 1); |
search = alloca(len + 1); |
(void)strncpy(search, &cmd[idx], len); |
(void) strncpy(search, &cmd[idx], len); |
search[len] = '\0'; |
search[len] = '\0'; |
|
|
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_CURR) != 0) |
return -1; |
return (-1); |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
if (prefix) |
if (prefix) |
Line 372 _history_expand_command(command, len, re |
|
Line 441 _history_expand_command(command, len, re |
|
|
|
if (retval == -1) { |
if (retval == -1) { |
fprintf(rl_outstream, "%s: Event not found\n", |
fprintf(rl_outstream, "%s: Event not found\n", |
search); |
search); |
return -1; |
return (-1); |
} |
} |
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_CURR) != 0) |
return -1; |
return (-1); |
event_data = ev.str; |
event_data = ev.str; |
|
|
/* roll back to original position */ |
/* roll back to original position */ |
Line 389 _history_expand_command(command, len, re |
|
Line 458 _history_expand_command(command, len, re |
|
HIST_ENTRY *rl_he; |
HIST_ENTRY *rl_he; |
rl_he = history_get(event_num); |
rl_he = history_get(event_num); |
if (!rl_he) |
if (!rl_he) |
return 0; |
return (0); |
event_data = rl_he->line; |
event_data = rl_he->line; |
} else |
} else |
return -1; |
return (-1); |
|
|
if (cmd[idx] != ':') |
if (cmd[idx] != ':') |
return -1; |
return (-1); |
cmd += idx + 1; |
cmd += idx + 1; |
|
|
/* recognize cmd */ |
/* recognize cmd */ |
Line 446 _history_expand_command(command, len, re |
|
Line 515 _history_expand_command(command, len, re |
|
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, size, from_len; |
int len, from_len; |
|
size_t size; |
|
|
if (*cmd == '&' && (from == NULL || to == NULL)) |
if (*cmd == '&' && (from == NULL || to == NULL)) |
continue; |
continue; |
else if (*cmd == 's') { |
else if (*cmd == 's') { |
delim = *(++cmd), cmd++; |
delim = *(++cmd), cmd++; |
size = 16; |
size = 16; |
what = realloc((void *) from, size); |
what = realloc(from, size); |
len = 0; |
len = 0; |
for (; *cmd && *cmd != delim; cmd++) { |
for (; *cmd && *cmd != delim; cmd++) { |
if (*cmd == '\\' |
if (*cmd == '\\' |
Line 473 _history_expand_command(command, len, re |
|
Line 543 _history_expand_command(command, len, re |
|
from = strdup(search); |
from = strdup(search); |
else { |
else { |
from = NULL; |
from = NULL; |
return -1; |
return (-1); |
} |
} |
} |
} |
cmd++; /* shift after delim */ |
cmd++; /* shift after delim */ |
Line 481 _history_expand_command(command, len, re |
|
Line 551 _history_expand_command(command, len, re |
|
continue; |
continue; |
|
|
size = 16; |
size = 16; |
with = realloc((void *) to, size); |
with = realloc(to, size); |
len = 0; |
len = 0; |
from_len = strlen(from); |
from_len = strlen(from); |
for (; *cmd && *cmd != delim; cmd++) { |
for (; *cmd && *cmd != delim; cmd++) { |
Line 491 _history_expand_command(command, len, re |
|
Line 561 _history_expand_command(command, len, re |
|
} |
} |
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 504 _history_expand_command(command, len, re |
|
Line 574 _history_expand_command(command, len, re |
|
with[len] = '\0'; |
with[len] = '\0'; |
to = with; |
to = with; |
|
|
temp = _rl_compat_sub(line, from, to, |
tempcmd = _rl_compat_sub(line, from, to, |
(g_on) ? 1 : 0); |
(g_on) ? 1 : 0); |
free(line); |
free(line); |
line = temp; |
line = tempcmd; |
g_on = 0; |
g_on = 0; |
} |
} |
} |
} |
Line 518 _history_expand_command(command, len, re |
|
Line 588 _history_expand_command(command, len, re |
|
if (arr && *arr == NULL) |
if (arr && *arr == NULL) |
free(arr), arr = NULL; |
free(arr), arr = NULL; |
if (!arr) |
if (!arr) |
return -1; |
return (-1); |
|
|
/* find out max valid idx to array of array */ |
/* find out max valid idx to array of array */ |
max = 0; |
max = 0; |
Line 534 _history_expand_command(command, len, re |
|
Line 604 _history_expand_command(command, len, re |
|
|
|
/* check boundaries ... */ |
/* check boundaries ... */ |
if (start > max || end > max || start > end) |
if (start > max || end > max || start > end) |
return -1; |
return (-1); |
|
|
for (i = 0; i <= max; i++) { |
for (i = 0; i <= max; i++) { |
char *temp; |
char *temp; |
if (h_on && (i == 1 || h_on > 1) && |
if (h_on && (i == 1 || h_on > 1) && |
(temp = strrchr(arr[i], '/'))) |
(temp = strrchr(arr[i], '/'))) |
*(temp + 1) = '\0'; |
*(temp + 1) = '\0'; |
if (t_on && (i == 1 || t_on > 1) && |
if (t_on && (i == 1 || t_on > 1) && |
(temp = strrchr(arr[i], '/'))) |
(temp = strrchr(arr[i], '/'))) |
(void)strcpy(arr[i], temp + 1); |
(void) strcpy(arr[i], temp + 1); |
if (r_on && (i == 1 || r_on > 1) && |
if (r_on && (i == 1 || r_on > 1) && |
(temp = strrchr(arr[i], '.'))) |
(temp = strrchr(arr[i], '.'))) |
*temp = '\0'; |
*temp = '\0'; |
if (e_on && (i == 1 || e_on > 1) && |
if (e_on && (i == 1 || e_on > 1) && |
(temp = strrchr(arr[i], '.'))) |
(temp = strrchr(arr[i], '.'))) |
(void)strcpy(arr[i], temp); |
(void) strcpy(arr[i], temp); |
} |
} |
|
|
size = 1, len = 0; |
cmdsize = 1, cmdlen = 0; |
temp = malloc(size); |
tempcmd = malloc(cmdsize); |
for (i = start; start <= i && i <= end; i++) { |
for (i = start; start <= i && i <= end; i++) { |
int arr_len; |
int arr_len; |
|
|
arr_len = strlen(arr[i]); |
arr_len = strlen(arr[i]); |
if (len + arr_len + 1 >= size) { |
if (cmdlen + arr_len + 1 >= cmdsize) { |
size += arr_len + 1; |
cmdsize += arr_len + 1; |
temp = realloc(temp, size); |
tempcmd = realloc(tempcmd, cmdsize); |
} |
} |
(void)strcpy(&temp[len], arr[i]); /* safe */ |
(void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ |
len += arr_len; |
cmdlen += arr_len; |
temp[len++] = ' '; /* add a space */ |
tempcmd[cmdlen++] = ' '; /* add a space */ |
} |
} |
while (len > 0 && isspace((unsigned char) temp[len - 1])) |
while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1])) |
len--; |
cmdlen--; |
temp[len] = '\0'; |
tempcmd[cmdlen] = '\0'; |
|
|
*result = temp; |
*result = tempcmd; |
|
|
for (i = 0; i <= max; i++) |
for (i = 0; i <= max; i++) |
free(arr[i]); |
free(arr[i]); |
Line 578 _history_expand_command(command, len, re |
|
Line 648 _history_expand_command(command, len, re |
|
return (p_on) ? 2 : 1; |
return (p_on) ? 2 : 1; |
} |
} |
|
|
|
|
/* |
/* |
* csh-style history expansion |
* csh-style history expansion |
*/ |
*/ |
int |
int |
history_expand(str, output) |
history_expand(char *str, char **output) |
char *str; |
|
char **output; |
|
{ |
{ |
int i, retval = 0, size, idx; |
int i, retval = 0, idx; |
char *temp, *result; |
size_t size; |
|
char *temp, *result; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
Line 600 history_expand(str, output) |
|
Line 670 history_expand(str, output) |
|
temp[0] = temp[1] = history_expansion_char; |
temp[0] = temp[1] = history_expansion_char; |
temp[2] = ':'; |
temp[2] = ':'; |
temp[3] = 's'; |
temp[3] = 's'; |
(void)strcpy(temp + 4, str); |
(void) strcpy(temp + 4, str); |
str = temp; |
str = temp; |
} |
} |
#define ADD_STRING(what, len) \ |
#define ADD_STRING(what, len) \ |
{ \ |
{ \ |
if (idx + len + 1 > size) \ |
if (idx + len + 1 > size) \ |
result = realloc(result, (size += len + 1)); \ |
result = realloc(result, (size += len + 1)); \ |
Line 615 history_expand(str, output) |
|
Line 685 history_expand(str, output) |
|
result = NULL; |
result = NULL; |
size = idx = 0; |
size = idx = 0; |
for (i = 0; str[i];) { |
for (i = 0; str[i];) { |
int start, j, len, loop_again; |
int start, j, loop_again; |
|
size_t len; |
|
|
loop_again = 1; |
loop_again = 1; |
start = j = i; |
start = j = i; |
|
|
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] == 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, j) == 0)) |
break; |
break; |
} |
} |
|
|
|
|
retval = 1; |
retval = 1; |
break; |
break; |
} |
} |
retval = _history_expand_command(&str[i], j - i, &temp); |
retval = _history_expand_command(&str[i], (size_t) (j - i), |
|
&temp); |
if (retval != -1) { |
if (retval != -1) { |
len = strlen(temp); |
len = strlen(temp); |
ADD_STRING(temp, len); |
ADD_STRING(temp, len); |
|
|
free(*output); |
free(*output); |
*output = result; |
*output = result; |
|
|
return retval; |
return (retval); |
} |
} |
|
|
|
|
/* |
/* |
* returns array of tokens parsed out of string, much as the shell might |
* Parse the string into individual tokens, similarily to how shell would do it. |
*/ |
*/ |
char ** |
char ** |
history_tokenize(str) |
history_tokenize(const char *str) |
const char *str; |
|
{ |
{ |
int size = 1, result_idx = 0, i, start, len; |
int size = 1, result_idx = 0, i, start; |
|
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]; i++) { |
Line 703 history_tokenize(str) |
|
Line 776 history_tokenize(str) |
|
i++; |
i++; |
start = i; |
start = i; |
for (; str[i]; i++) { |
for (; str[i]; i++) { |
if (str[i] == '\\') |
if (str[i] == '\\') { |
i++; |
if (str[i+1] != '\0') |
else if (str[i] == delim) |
i++; |
|
} else if (str[i] == delim) |
delim = '\0'; |
delim = '\0'; |
else if (!delim && |
else if (!delim && |
(isspace((unsigned char) str[i]) || |
(isspace((unsigned char) str[i]) || |
strchr("()<>;&|$", str[i]))) |
strchr("()<>;&|$", str[i]))) |
break; |
break; |
else if (!delim && strchr("'`\"", str[i])) |
else if (!delim && strchr("'`\"", str[i])) |
delim = str[i]; |
delim = str[i]; |
Line 721 history_tokenize(str) |
|
Line 795 history_tokenize(str) |
|
} |
} |
len = i - start; |
len = i - start; |
temp = malloc(len + 1); |
temp = malloc(len + 1); |
(void)strncpy(temp, &str[start], len); |
(void) strncpy(temp, &str[start], len); |
temp[len] = '\0'; |
temp[len] = '\0'; |
result[result_idx++] = temp; |
result[result_idx++] = temp; |
result[result_idx] = NULL; |
result[result_idx] = NULL; |
} |
} |
|
|
return result; |
return (result); |
} |
} |
|
|
|
|
/* |
/* |
* limit size of history record to ``max'' events |
* limit size of history record to ``max'' events |
*/ |
*/ |
void |
void |
stifle_history(max) |
stifle_history(int max) |
int max; |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
|
Line 746 stifle_history(max) |
|
Line 820 stifle_history(max) |
|
max_input_history = max; |
max_input_history = max; |
} |
} |
|
|
|
|
/* |
/* |
* "unlimit" size of history - set the limit to maximum allowed int value |
* "unlimit" size of history - set the limit to maximum allowed int value |
*/ |
*/ |
int |
int |
unstifle_history() |
unstifle_history(void) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
int omax; |
int omax; |
Line 758 unstifle_history() |
|
Line 833 unstifle_history() |
|
history(h, &ev, H_SETSIZE, INT_MAX); |
history(h, &ev, H_SETSIZE, INT_MAX); |
omax = max_input_history; |
omax = max_input_history; |
max_input_history = INT_MAX; |
max_input_history = INT_MAX; |
return omax; /* some value _must_ be returned */ |
return (omax); /* some value _must_ be returned */ |
} |
} |
|
|
|
|
int |
int |
history_is_stifled() |
history_is_stifled(void) |
{ |
{ |
|
|
/* cannot return true answer */ |
/* cannot return true answer */ |
return (max_input_history != INT_MAX); |
return (max_input_history != INT_MAX); |
} |
} |
|
|
|
|
/* |
/* |
* read history from a file given |
* read history from a file given |
*/ |
*/ |
int |
int |
read_history(filename) |
read_history(const char *filename) |
const char *filename; |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
return history(h, &ev, H_LOAD, filename); |
return (history(h, &ev, H_LOAD, filename)); |
} |
} |
|
|
|
|
/* |
/* |
* write history to a file given |
* write history to a file given |
*/ |
*/ |
int |
int |
write_history(filename) |
write_history(const char *filename) |
const char *filename; |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
return history(h, &ev, H_SAVE, filename); |
return (history(h, &ev, H_SAVE, filename)); |
} |
} |
|
|
|
|
/* |
/* |
* returns history ``num''th event |
* returns history ``num''th event |
* |
* |
* returned pointer points to static variable |
* returned pointer points to static variable |
*/ |
*/ |
HIST_ENTRY * |
HIST_ENTRY * |
history_get(num) |
history_get(int num) |
int num; |
|
{ |
{ |
static HIST_ENTRY she; |
static HIST_ENTRY she; |
HistEvent ev; |
HistEvent ev; |
Line 814 history_get(num) |
|
Line 891 history_get(num) |
|
|
|
/* rewind to beginning */ |
/* rewind to beginning */ |
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) |
if (history(h, &ev, H_LAST) != 0) |
return NULL; /* error */ |
return (NULL); /* error */ |
while (i < num && history(h, &ev, H_PREV) == 0) |
while (i < num && history(h, &ev, H_PREV) == 0) |
i++; |
i++; |
if (i != num) |
if (i != num) |
return NULL; /* not so many entries */ |
return (NULL); /* not so many entries */ |
|
|
she.line = ev.str; |
she.line = ev.str; |
she.data = NULL; |
she.data = NULL; |
Line 830 history_get(num) |
|
Line 907 history_get(num) |
|
(void) history(h, &ev, H_FIRST); |
(void) history(h, &ev, H_FIRST); |
(void) history(h, &ev, H_NEXT_EVENT, curr_num); |
(void) history(h, &ev, H_NEXT_EVENT, curr_num); |
|
|
return &she; |
return (&she); |
} |
} |
|
|
|
|
/* |
/* |
* add the line to history table |
* add the line to history table |
*/ |
*/ |
int |
int |
add_history(line) |
add_history(const char *line) |
const char *line; |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
|
Line 852 add_history(line) |
|
Line 929 add_history(line) |
|
return (!(history_length > 0)); /* return 0 if all is okay */ |
return (!(history_length > 0)); /* return 0 if all is okay */ |
} |
} |
|
|
|
|
/* |
/* |
* clear the history list - delete all entries |
* clear the history list - delete all entries |
*/ |
*/ |
void |
void |
clear_history() |
clear_history(void) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
|
|
history(h, &ev, H_CLEAR); |
history(h, &ev, H_CLEAR); |
} |
} |
|
|
|
|
/* |
/* |
* returns offset of the current history event |
* returns offset of the current history event |
*/ |
*/ |
int |
int |
where_history() |
where_history(void) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
int curr_num, off; |
int curr_num, off; |
|
|
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_CURR) != 0) |
return 0; |
return (0); |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
history(h, &ev, H_FIRST); |
history(h, &ev, H_FIRST); |
|
|
while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) |
while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) |
off++; |
off++; |
|
|
return off; |
return (off); |
} |
} |
|
|
|
|
/* |
/* |
* returns current history event or NULL if there is no such event |
* returns current history event or NULL if there is no such event |
*/ |
*/ |
HIST_ENTRY * |
HIST_ENTRY * |
current_history() |
current_history(void) |
{ |
{ |
return _move_history(H_CURR); |
|
|
return (_move_history(H_CURR)); |
} |
} |
|
|
|
|
/* |
/* |
* returns total number of bytes history events' data are using |
* returns total number of bytes history events' data are using |
*/ |
*/ |
int |
int |
history_total_bytes() |
history_total_bytes(void) |
{ |
{ |
HistEvent ev; |
HistEvent ev; |
int curr_num, size; |
int curr_num, size; |
|
|
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_CURR) != 0) |
return -1; |
return (-1); |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
history(h, &ev, H_FIRST); |
history(h, &ev, H_FIRST); |
Line 914 history_total_bytes() |
|
Line 997 history_total_bytes() |
|
/* 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 (size); |
} |
} |
|
|
|
|
/* |
/* |
* sets the position in the history list to ``pos'' |
* sets the position in the history list to ``pos'' |
*/ |
*/ |
int |
int |
history_set_pos(pos) |
history_set_pos(int pos) |
int pos; |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
int off, curr_num; |
int off, 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; |
Line 940 history_set_pos(pos) |
|
Line 1023 history_set_pos(pos) |
|
if (off != pos) { /* do a rollback in case of error */ |
if (off != pos) { /* do a rollback in case of error */ |
history(h, &ev, H_FIRST); |
history(h, &ev, H_FIRST); |
history(h, &ev, H_NEXT_EVENT, curr_num); |
history(h, &ev, H_NEXT_EVENT, curr_num); |
return -1; |
return (-1); |
} |
} |
return 0; |
return (0); |
} |
} |
|
|
|
|
/* |
/* |
* returns previous event in history and shifts pointer accordingly |
* returns previous event in history and shifts pointer accordingly |
*/ |
*/ |
HIST_ENTRY * |
HIST_ENTRY * |
previous_history() |
previous_history(void) |
{ |
{ |
return _move_history(H_PREV); |
|
|
return (_move_history(H_PREV)); |
} |
} |
|
|
|
|
/* |
/* |
* returns next event in history and shifts pointer accordingly |
* returns next event in history and shifts pointer accordingly |
*/ |
*/ |
HIST_ENTRY * |
HIST_ENTRY * |
next_history() |
next_history(void) |
{ |
{ |
return _move_history(H_NEXT); |
|
|
return (_move_history(H_NEXT)); |
} |
} |
|
|
|
|
/* |
/* |
* generic history search function |
* generic history search function |
*/ |
*/ |
static int |
static int |
_history_search_gen(str, direction, pos) |
_history_search_gen(const char *str, int direction, int pos) |
const char *str; |
{ |
int direction, pos; |
HistEvent ev; |
{ |
const char *strp; |
HistEvent ev; |
int curr_num; |
const char *strp; |
|
int curr_num; |
|
|
|
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_CURR) != 0) |
return -1; |
return (-1); |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
for (;;) { |
for (;;) { |
Line 989 _history_search_gen(str, direction, pos) |
|
Line 1075 _history_search_gen(str, direction, pos) |
|
|
|
history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, 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 |
* searches for first history event containing the str |
*/ |
*/ |
int |
int |
history_search(str, direction) |
history_search(const char *str, int direction) |
const char *str; |
|
int direction; |
|
{ |
{ |
return _history_search_gen(str, direction, -1); |
|
|
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(str, direction) |
history_search_prefix(const char *str, int direction) |
const char *str; |
|
int direction; |
|
{ |
{ |
return _history_search_gen(str, direction, 0); |
|
|
return (_history_search_gen(str, direction, 0)); |
} |
} |
|
|
|
|
/* |
/* |
* search for event in history containing str, starting at offset |
* search for event in history containing str, starting at offset |
* abs(pos); continue backward, if pos<0, forward otherwise |
* abs(pos); continue backward, if pos<0, forward otherwise |
*/ |
*/ |
|
/* ARGSUSED */ |
int |
int |
history_search_pos(str, direction, pos) |
history_search_pos(const char *str, int direction, int pos) |
const char *str; |
|
int direction, pos; |
|
{ |
{ |
HistEvent ev; |
HistEvent ev; |
int curr_num, off; |
int curr_num, off; |
|
|
off = (pos > 0) ? pos : -pos; |
off = (pos > 0) ? pos : -pos; |
pos = (pos > 0) ? 1 : -1; |
pos = (pos > 0) ? 1 : -1; |
|
|
if (history(h, &ev, H_CURR) != 0) |
if (history(h, &ev, H_CURR) != 0) |
return -1; |
return (-1); |
curr_num = ev.num; |
curr_num = ev.num; |
|
|
if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) |
if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) |
return -1; |
return (-1); |
|
|
|
|
for (;;) { |
for (;;) { |
if (strstr(ev.str, str)) |
if (strstr(ev.str, str)) |
return off; |
return (off); |
if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) |
if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) |
break; |
break; |
} |
} |
Line 1047 history_search_pos(str, direction, pos) |
|
Line 1133 history_search_pos(str, direction, pos) |
|
/* set "current" pointer back to previous state */ |
/* set "current" pointer back to previous state */ |
history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); |
history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); |
|
|
return -1; |
return (-1); |
} |
} |
|
|
|
|
/********************************/ |
/********************************/ |
/* completition functions */ |
/* completition functions */ |
|
|
/* |
/* |
* does tilde expansion of strings of type ``~user/foo'' |
* does tilde expansion of strings of type ``~user/foo'' |
Line 1062 history_search_pos(str, direction, pos) |
|
Line 1148 history_search_pos(str, direction, pos) |
|
* it's callers's responsibility to free() returned string |
* it's callers's responsibility to free() returned string |
*/ |
*/ |
char * |
char * |
tilde_expand(txt) |
tilde_expand(char *txt) |
char *txt; |
|
{ |
{ |
struct passwd *pass; |
struct passwd *pass; |
char *temp; |
char *temp; |
size_t len = 0; |
size_t len = 0; |
|
|
if (txt[0] != '~') |
if (txt[0] != '~') |
return strdup(txt); |
return (strdup(txt)); |
|
|
temp = strchr(txt + 1, '/'); |
temp = strchr(txt + 1, '/'); |
if (temp == NULL) |
if (temp == NULL) |
Line 1078 tilde_expand(txt) |
|
Line 1163 tilde_expand(txt) |
|
else { |
else { |
len = temp - txt + 1; /* text until string after slash */ |
len = temp - txt + 1; /* text until string after slash */ |
temp = malloc(len); |
temp = malloc(len); |
(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); |
free(temp); /* value no more needed */ |
free(temp); /* value no more needed */ |
if (pass == NULL) |
if (pass == NULL) |
return strdup(txt); |
return (strdup(txt)); |
|
|
/* update pointer txt to point at string immedially following */ |
/* update pointer txt to point at string immedially following */ |
/* first slash */ |
/* first slash */ |
txt += len; |
txt += len; |
|
|
temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); |
temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); |
(void)sprintf(temp, "%s/%s", pass->pw_dir, txt); |
(void) sprintf(temp, "%s/%s", pass->pw_dir, txt); |
|
|
return temp; |
return (temp); |
} |
} |
|
|
|
|
/* |
/* |
* return first found file name starting by the ``text'' or NULL if no |
* return first found file name starting by the ``text'' or NULL if no |
* such file can be found |
* such file can be found |
Line 1103 tilde_expand(txt) |
|
Line 1189 tilde_expand(txt) |
|
* |
* |
* it's caller's responsibility to free returned string |
* it's caller's responsibility to free returned string |
*/ |
*/ |
char * |
char * |
filename_completion_function(text, state) |
filename_completion_function(const char *text, int state) |
const char *text; |
{ |
int state; |
static DIR *dir = NULL; |
{ |
static char *filename = NULL, *dirname = NULL; |
static DIR *dir = NULL; |
static size_t filename_len = 0; |
static char *filename = NULL, *dirname = NULL; |
struct dirent *entry; |
static size_t filename_len = 0; |
char *temp; |
struct dirent *entry; |
size_t len; |
char *temp; |
|
size_t len; |
|
|
|
if (state == 0 || dir == NULL) { |
if (state == 0 || dir == NULL) { |
if (dir != NULL) { |
if (dir != NULL) { |
Line 1124 filename_completion_function(text, state |
|
Line 1208 filename_completion_function(text, state |
|
if (temp) { |
if (temp) { |
temp++; |
temp++; |
filename = realloc(filename, strlen(temp) + 1); |
filename = realloc(filename, strlen(temp) + 1); |
(void)strcpy(filename, temp); |
(void) strcpy(filename, temp); |
len = temp - text; /* including last slash */ |
len = temp - text; /* including last slash */ |
dirname = realloc(dirname, len + 1); |
dirname = realloc(dirname, len + 1); |
(void)strncpy(dirname, text, len); |
(void) strncpy(dirname, text, len); |
dirname[len] = '\0'; |
dirname[len] = '\0'; |
} else { |
} else { |
filename = strdup(text); |
filename = strdup(text); |
Line 1138 filename_completion_function(text, state |
|
Line 1222 filename_completion_function(text, state |
|
if (dirname && *dirname == '~') { |
if (dirname && *dirname == '~') { |
temp = tilde_expand(dirname); |
temp = tilde_expand(dirname); |
dirname = realloc(dirname, strlen(temp) + 1); |
dirname = realloc(dirname, strlen(temp) + 1); |
(void)strcpy(dirname, temp); /* safe */ |
(void) strcpy(dirname, temp); /* safe */ |
free(temp); /* no more needed */ |
free(temp); /* no longer needed */ |
} |
} |
/* will be used in cycle */ |
/* will be used in cycle */ |
filename_len = strlen(filename); |
filename_len = strlen(filename); |
if (filename_len == 0) |
if (filename_len == 0) |
return NULL; /* no expansion possible */ |
return (NULL); /* no expansion possible */ |
|
|
dir = opendir(dirname ? dirname : "."); |
dir = opendir(dirname ? dirname : "."); |
if (!dir) |
if (!dir) |
return NULL; /* cannot open the directory */ |
return (NULL); /* cannot open the directory */ |
} |
} |
/* find the match */ |
/* find the match */ |
while ((entry = readdir(dir))) { |
while ((entry = readdir(dir)) != NULL) { |
/* 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] |
#ifndef __SVR4 |
#if defined(__SVR4) || defined(__linux__) |
&& entry->d_namlen >= filename_len |
|
#else |
|
&& strlen(entry->d_name) >= filename_len |
&& strlen(entry->d_name) >= filename_len |
|
#else |
|
&& entry->d_namlen >= filename_len |
#endif |
#endif |
&& strncmp(entry->d_name, filename, |
&& strncmp(entry->d_name, filename, |
filename_len) == 0) |
filename_len) == 0) |
break; |
break; |
} |
} |
|
|
if (entry) { /* match found */ |
if (entry) { /* match found */ |
|
|
struct stat stbuf; |
struct stat stbuf; |
#ifndef __SVR4 |
#if defined(__SVR4) || defined(__linux__) |
len = entry->d_namlen + |
|
#else |
|
len = strlen(entry->d_name) + |
len = strlen(entry->d_name) + |
|
#else |
|
len = entry->d_namlen + |
#endif |
#endif |
((dirname) ? strlen(dirname) : 0) + 1 + 1; |
((dirname) ? strlen(dirname) : 0) + 1 + 1; |
temp = malloc(len); |
temp = malloc(len); |
(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 */ |
if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) |
if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) |
Line 1184 filename_completion_function(text, state |
|
Line 1268 filename_completion_function(text, state |
|
} else |
} else |
temp = NULL; |
temp = NULL; |
|
|
return temp; |
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 1194 filename_completion_function(text, state |
|
Line 1279 filename_completion_function(text, state |
|
* (usually '~'); state is ignored |
* (usually '~'); state is ignored |
* it's callers responsibility to free returned value |
* it's callers responsibility to free returned value |
*/ |
*/ |
char * |
char * |
username_completion_function(text, state) |
username_completion_function(const char *text, int state) |
const char *text; |
|
int state; |
|
{ |
{ |
struct passwd *pwd; |
struct passwd *pwd; |
|
|
if (text[0] == '\0') |
if (text[0] == '\0') |
return NULL; |
return (NULL); |
|
|
if (*text == '~') |
if (*text == '~') |
text++; |
text++; |
Line 1211 username_completion_function(text, state |
|
Line 1294 username_completion_function(text, state |
|
setpwent(); |
setpwent(); |
|
|
while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] |
while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] |
&& strcmp(text, pwd->pw_name) == 0); |
&& strcmp(text, pwd->pw_name) == 0); |
|
|
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 |
* el-compatible wrapper around rl_complete; needed for key binding |
*/ |
*/ |
|
/* ARGSUSED */ |
static unsigned char |
static unsigned char |
_el_rl_complete(el, ch) |
_el_rl_complete(EditLine *el, int ch) |
EditLine *el; |
|
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 completitions for text given |
*/ |
*/ |
char ** |
char ** |
completion_matches(text, genfunc) |
completion_matches(const char *text, CPFunction *genfunc) |
const char *text; |
{ |
CPFunction *genfunc; |
char **match_list = NULL, *retstr, *prevstr; |
{ |
size_t match_list_len, max_equal, which, i; |
char **match_list = NULL, *retstr, *prevstr; |
int matches; |
size_t matches, math_list_len, max_equal, len, which, |
|
i; |
|
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
matches = 0; |
matches = 0; |
math_list_len = 1; |
match_list_len = 1; |
while ((retstr = (*genfunc) (text, matches))) { |
while ((retstr = (*genfunc) (text, matches)) != NULL) { |
if (matches + 1 >= math_list_len) { |
if (matches + 1 >= match_list_len) { |
math_list_len <<= 1; |
match_list_len <<= 1; |
match_list = realloc(match_list, |
match_list = realloc(match_list, |
math_list_len * sizeof(char *)); |
match_list_len * sizeof(char *)); |
} |
} |
match_list[++matches] = retstr; |
match_list[++matches] = retstr; |
} |
} |
Line 1263 completion_matches(text, genfunc) |
|
Line 1345 completion_matches(text, genfunc) |
|
/* find least denominator and insert it to match_list[0] */ |
/* find least denominator and insert it to match_list[0] */ |
which = 2; |
which = 2; |
prevstr = match_list[1]; |
prevstr = match_list[1]; |
len = max_equal = strlen(prevstr); |
max_equal = strlen(prevstr); |
for (; which < matches; which++) { |
for (; which <= matches; which++) { |
for (i = 0; i < max_equal && |
for (i = 0; i < max_equal && |
prevstr[i] == match_list[which][i]; i++) |
prevstr[i] == match_list[which][i]; i++) |
continue; |
continue; |
Line 1272 completion_matches(text, genfunc) |
|
Line 1354 completion_matches(text, genfunc) |
|
} |
} |
|
|
retstr = malloc(max_equal + 1); |
retstr = malloc(max_equal + 1); |
(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; |
|
|
/* add NULL as last pointer to the array */ |
/* add NULL as last pointer to the array */ |
if (matches + 1 >= math_list_len) |
if (matches + 1 >= match_list_len) |
match_list = realloc(match_list, |
match_list = realloc(match_list, |
(math_list_len + 1) * sizeof(char *)); |
(match_list_len + 1) * sizeof(char *)); |
match_list[matches + 1] = (char *) NULL; |
match_list[matches + 1] = (char *) NULL; |
|
|
return match_list; |
return (match_list); |
|
} |
|
|
|
/* |
|
* Sort function for qsort(). Just wrapper around strcasecmp(). |
|
*/ |
|
static int |
|
_rl_qsort_string_compare(i1, i2) |
|
const void *i1, *i2; |
|
{ |
|
/*LINTED const castaway*/ |
|
const char *s1 = ((const char **)i1)[0]; |
|
/*LINTED const castaway*/ |
|
const char *s2 = ((const char **)i2)[0]; |
|
|
|
return strcasecmp(s1, s2); |
} |
} |
|
|
/* |
/* |
* called by rl_complete() |
* Display list of strings in columnar format on readline's output stream. |
|
* 'matches' is list of strings, 'len' is number of strings in 'matches', |
|
* 'max' is maximum length of string in 'matches'. |
|
*/ |
|
void |
|
rl_display_match_list (matches, len, 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. */ |
|
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++) |
|
fprintf(e->el_outfile, "%-*s ", max, matches[idx]); |
|
fprintf(e->el_outfile, "\n"); |
|
} |
|
} |
|
|
|
/* |
|
* Complete the word at or before point, called by rl_complete() |
|
* 'what_to_do' says what to do with the completion. |
|
* `?' means list the possible completions. |
|
* 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 |
static int |
rl_complete_internal(what_to_do) |
rl_complete_internal(int what_to_do) |
int what_to_do; |
|
{ |
{ |
CPFunction *complet_func; |
CPFunction *complet_func; |
const LineInfo *li; |
const LineInfo *li; |
char *temp, *temp2, **arr; |
char *temp, **matches; |
int len; |
const char *ctemp; |
|
size_t len; |
|
|
|
rl_completion_type = what_to_do; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
Line 1304 rl_complete_internal(what_to_do) |
|
Line 1449 rl_complete_internal(what_to_do) |
|
if (!complet_func) |
if (!complet_func) |
complet_func = filename_completion_function; |
complet_func = filename_completion_function; |
|
|
|
/* We now look backwards for the start of a filename/variable word */ |
li = el_line(e); |
li = el_line(e); |
temp = (char *) li->cursor; |
ctemp = (const char *) li->cursor; |
while (temp > li->buffer && |
while (ctemp > li->buffer |
!strchr(rl_basic_word_break_characters, *(temp - 1))) |
&& !strchr(rl_basic_word_break_characters, ctemp[-1]) |
temp--; |
&& (!rl_special_prefixes |
|
|| !strchr(rl_special_prefixes, ctemp[-1]) ) ) |
len = li->cursor - temp; |
ctemp--; |
temp2 = alloca(len + 1); |
|
(void)strncpy(temp2, temp, len); |
len = li->cursor - ctemp; |
temp = temp2; |
temp = alloca(len + 1); |
|
(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 1322 rl_complete_internal(what_to_do) |
|
Line 1469 rl_complete_internal(what_to_do) |
|
rl_end = li->lastchar - li->buffer; |
rl_end = li->lastchar - li->buffer; |
|
|
if (!rl_attempted_completion_function) |
if (!rl_attempted_completion_function) |
arr = completion_matches(temp, complet_func); |
matches = completion_matches(temp, complet_func); |
else { |
else { |
int end = li->cursor - li->buffer; |
int end = li->cursor - li->buffer; |
arr = (*rl_attempted_completion_function) (temp, |
matches = (*rl_attempted_completion_function) (temp, (int) |
end - len, end); |
(end - len), end); |
} |
} |
free(temp); /* no more needed */ |
|
|
if (matches) { |
if (arr) { |
int i, retval = CC_REFRESH; |
int i; |
int matches_num, maxlen, match_len, match_display=1; |
|
|
el_deletestr(e, len); |
/* |
el_insertstr(e, arr[0]); |
* Only replace the completed string with common part of |
if (strcmp(arr[0], arr[1]) == 0) { |
* possible matches if there is possible completion. |
/* lcd is valid object, so add a space to mark it */ |
*/ |
/* in case of filename completition, add a space */ |
if (matches[0][0] != '\0') { |
/* only if object found is not directory */ |
el_deletestr(e, (int) len); |
int len = strlen(arr[0]); |
el_insertstr(e, matches[0]); |
if (complet_func != filename_completion_function |
} |
|| (len > 0 && (arr[0])[len - 1] != '/')) |
|
el_insertstr(e, " "); |
if (what_to_do == '?') |
} else |
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 completition and the |
|
* object is a directory. |
|
*/ |
|
size_t alen = strlen(matches[0]); |
|
if ((complet_func != 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 */ |
|
fprintf(e->el_outfile, "\n"); |
|
|
|
/* |
|
* If there are too many items, ask user for display |
|
* confirmation. |
|
*/ |
|
if (matches_num > rl_completion_query_items) { |
|
fprintf(e->el_outfile, |
|
"Display all %d possibilities? (y or n) ", |
|
matches_num); |
|
fflush(e->el_outfile); |
|
if (getc(stdin) != 'y') |
|
match_display = 0; |
|
fprintf(e->el_outfile, "\n"); |
|
} |
|
|
|
if (match_display) |
|
rl_display_match_list(matches, matches_num, |
|
maxlen); |
|
retval = CC_REDISPLAY; |
|
} else { |
/* lcd is not a valid object - further specification */ |
/* lcd is not a valid object - further specification */ |
/* is needed */ |
/* is needed */ |
el_beep(e); |
el_beep(e); |
|
retval = CC_NORM; |
|
} |
|
|
/* free elements of array and the array itself */ |
/* free elements of array and the array itself */ |
for (i = 0; arr[i]; i++) |
for (i = 0; matches[i]; i++) |
free(arr[i]); |
free(matches[i]); |
free(arr), arr = NULL; |
free(matches), matches = NULL; |
|
|
return CC_REFRESH; |
return (retval); |
} |
} |
return CC_NORM; |
return (CC_NORM); |
} |
} |
|
|
|
|
/* |
/* |
* complete word at current point |
* complete word at current point |
*/ |
*/ |
int |
int |
rl_complete(ignore, invoking_key) |
rl_complete(int ignore, int invoking_key) |
int ignore, invoking_key; |
|
{ |
{ |
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
if (rl_inhibit_completion) { |
if (rl_inhibit_completion) { |
rl_insert(ignore, invoking_key); |
rl_insert(ignore, invoking_key); |
return CC_REFRESH; |
return (CC_REFRESH); |
} else |
} else if (e->el_state.lastcmd == el_rl_complete_cmdnum) |
return rl_complete_internal(invoking_key); |
return rl_complete_internal('?'); |
|
else if (_rl_complete_show_all) |
return CC_REFRESH; |
return rl_complete_internal('!'); |
|
else |
|
return (rl_complete_internal(TAB)); |
} |
} |
|
|
|
|
/* |
/* |
* misc other functions |
* misc other functions |
*/ |
*/ |
|
|
/* |
/* |
* bind key c to readline-type function func |
* bind key c to readline-type function func |
*/ |
*/ |
int |
int |
rl_bind_key(c, func) |
rl_bind_key(int c, int func(int, int)) |
int c; |
|
int func __P((int, int)); |
|
{ |
{ |
int retval = -1; |
int retval = -1; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
Line 1399 rl_bind_key(c, func) |
|
Line 1601 rl_bind_key(c, func) |
|
e->el_map.key[c] = ED_INSERT; |
e->el_map.key[c] = ED_INSERT; |
retval = 0; |
retval = 0; |
} |
} |
return retval; |
return (retval); |
} |
} |
|
|
|
|
/* |
/* |
* read one key from input - handles chars pushed back |
* read one key from input - handles chars pushed back |
* to input stream also |
* to input stream also |
*/ |
*/ |
int |
int |
rl_read_key() |
rl_read_key(void) |
{ |
{ |
char fooarr[2 * sizeof(int)]; |
char fooarr[2 * sizeof(int)]; |
|
|
if (e == NULL || h == NULL) |
if (e == NULL || h == NULL) |
rl_initialize(); |
rl_initialize(); |
|
|
return el_getc(e, fooarr); |
return (el_getc(e, fooarr)); |
} |
} |
|
|
|
|
/* |
/* |
* reset the terminal |
* reset the terminal |
*/ |
*/ |
|
/* ARGSUSED */ |
void |
void |
rl_reset_terminal(p) |
rl_reset_terminal(const char *p) |
const char *p; |
|
{ |
{ |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
el_reset(e); |
el_reset(e); |
} |
} |
|
|
|
|
/* |
/* |
* insert character ``c'' back into input stream, ``count'' times |
* insert character ``c'' back into input stream, ``count'' times |
*/ |
*/ |
int |
int |
rl_insert(count, c) |
rl_insert(int count, int c) |
int count, c; |
|
{ |
{ |
char arr[2]; |
char arr[2]; |
|
|
if (h == NULL || e == NULL) |
if (h == NULL || e == NULL) |
rl_initialize(); |
rl_initialize(); |
Line 1448 rl_insert(count, c) |
|
Line 1653 rl_insert(count, c) |
|
for (; count > 0; count--) |
for (; count > 0; count--) |
el_push(e, arr); |
el_push(e, arr); |
|
|
return 0; |
return (0); |
} |
} |