Index: bin/sh/histedit.c =================================================================== --- bin/sh/histedit.c +++ bin/sh/histedit.c @@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #include #include #include @@ -72,6 +74,7 @@ static char *fc_replace(const char *, char *, char *); static int not_fcnumber(const char *); static int str_to_event(const char *, int); +static unsigned char sh_complete(EditLine *, int); /* * Set history and editing status. Called whenever the status may @@ -122,7 +125,7 @@ el_set(el, EL_PROMPT, getprompt); el_set(el, EL_ADDFN, "sh-complete", "Filename completion", - _el_fn_complete); + sh_complete); } else { bad: out2fmt_flush("sh: can't initialize editing\n"); @@ -519,3 +522,80 @@ return (0); } #endif + +static char **sh_matches(const char *text, int start, int end) +{ + char *dirname, *path, *free_path; + char **matches; + size_t i, size; + + if (start > 0) + return NULL; + i = 0; + size = 16; + matches = NULL; + free_path = NULL; + if ((free_path = path = strdup(pathval())) == NULL) + goto out; + if ((matches = malloc(size * sizeof (char *))) == NULL) + goto out; + while ((dirname = strsep(&path, ":")) != NULL) { + DIR *dir; + struct dirent *entry; + + if ((dir = opendir(dirname)) == NULL) + continue; + while ((entry = readdir(dir)) != NULL) { + struct stat statb; + + if (strncmp(entry->d_name, text, end - start) != 0) + continue; + if (entry->d_type == DT_REG) + /* OK */; + else if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) { + continue; + } + else { + int dfd; + + if ((dfd = dirfd(dir)) == -1) + continue; + if (fstatat(dfd, entry->d_name, &statb, 0) == -1) + continue; + if (!S_ISREG(statb.st_mode)) + continue; + } + if (++i >= size - 1) { + char **rloc_matches; + + size *= 2; + rloc_matches = reallocarray(matches, size, sizeof (char *)); + if (rloc_matches == NULL) { + closedir(dir); + goto out; + } + matches = rloc_matches; + } + matches[i] = strdup(entry->d_name); + } + closedir(dir); + } +out: + free(free_path); + if (i == 0) { + free(matches); + return NULL; + } + matches[0] = strdup(i == 1 ? matches[1] : text); + matches[++i] = NULL; + + return matches; +} + +unsigned char +sh_complete(EditLine *sel, int ch __unused) +{ + return (unsigned char)fn_complete(sel, NULL, sh_matches, + L" \t\n\"\\'`@$><=;|&{(", NULL, NULL, (size_t)100, + NULL, &((int) {0}), NULL, NULL); +} Index: bin/sh/myhistedit.h =================================================================== --- bin/sh/myhistedit.h +++ bin/sh/myhistedit.h @@ -38,6 +38,8 @@ extern EditLine *el; extern int displayhist; +#include + void histedit(void); void sethistsize(const char *); void setterm(const char *); Index: lib/libedit/Makefile =================================================================== --- lib/libedit/Makefile +++ lib/libedit/Makefile @@ -65,7 +65,7 @@ editline.3 tok_wreset.3 \ editline.3 tok_wstr.3 -INCS= histedit.h +INCS= histedit.h filecomplete.h SRCS+= common.h emacs.h fcns.h func.h help.h vi.h CLEANFILES+= common.h emacs.h fcns.h func.h help.h vi.h