diff options
-rw-r--r-- | net/tnftp/files/libedit/filecomplete.c | 536 | ||||
-rw-r--r-- | net/tnftp/files/libedit/filecomplete.h | 52 | ||||
-rw-r--r-- | net/tnftp/files/libedit/readline.c | 528 | ||||
-rw-r--r-- | net/tnftp/files/libnetbsd/dirname.c | 84 |
4 files changed, 728 insertions, 472 deletions
diff --git a/net/tnftp/files/libedit/filecomplete.c b/net/tnftp/files/libedit/filecomplete.c new file mode 100644 index 00000000000..277abf9156e --- /dev/null +++ b/net/tnftp/files/libedit/filecomplete.c @@ -0,0 +1,536 @@ +/* NetBSD: filecomplete.c,v 1.2 2005/06/09 16:48:57 lukem Exp */ +/* from NetBSD: filecomplete.c,v 1.5 2005/05/18 22:34:41 christos Exp */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jaromir Dolecek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <dirent.h> +#include <string.h> +#include <pwd.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.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 +#include <alloca.h> +#endif +#include "el.h" +#include "fcns.h" /* for EL_NUM_FCNS */ +#include "histedit.h" +#include "filecomplete.h" + +static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', + '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; + + +/********************************/ +/* completion functions */ + +/* + * does tilde expansion of strings of type ``~user/foo'' + * if ``user'' isn't valid user name or ``txt'' doesn't start + * w/ '~', returns pointer to strdup()ed copy of ``txt'' + * + * it's callers's responsibility to free() returned string + */ +char * +tilde_expand(char *txt) +{ + struct passwd pwres, *pass; + char *temp; + size_t len = 0; + char pwbuf[1024]; + + if (txt[0] != '~') + return (strdup(txt)); + + temp = strchr(txt + 1, '/'); + if (temp == NULL) { + temp = strdup(txt + 1); + if (temp == NULL) + return NULL; + } else { + len = temp - txt + 1; /* text until string after slash */ + temp = malloc(len); + if (temp == NULL) + return NULL; + (void)strncpy(temp, txt + 1, len - 2); + temp[len - 2] = '\0'; + } + if (temp[0] == 0) { + if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) + pass = NULL; + } else { + if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) + pass = NULL; + } + free(temp); /* value no more needed */ + if (pass == NULL) + return (strdup(txt)); + + /* update pointer txt to point at string immedially following */ + /* first slash */ + txt += len; + + temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); + if (temp == NULL) + return NULL; + (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); + + return (temp); +} + + +/* + * return first found file name starting by the ``text'' or NULL if no + * such file can be found + * value of ``state'' is ignored + * + * it's caller's responsibility to free returned string + */ +char * +filename_completion_function(const char *text, int state) +{ + static DIR *dir = NULL; + static char *filename = NULL, *dirname = NULL, *dirpath = NULL; + static size_t filename_len = 0; + struct dirent *entry; + char *temp; + size_t len; + + if (state == 0 || dir == NULL) { + temp = strrchr(text, '/'); + if (temp) { + char *nptr; + temp++; + nptr = realloc(filename, strlen(temp) + 1); + if (nptr == NULL) { + free(filename); + return NULL; + } + filename = nptr; + (void)strcpy(filename, temp); + len = temp - text; /* including last slash */ + nptr = realloc(dirname, len + 1); + if (nptr == NULL) { + free(filename); + return NULL; + } + dirname = nptr; + (void)strncpy(dirname, text, len); + dirname[len] = '\0'; + } else { + if (*text == 0) + filename = NULL; + else { + filename = strdup(text); + if (filename == NULL) + return NULL; + } + dirname = NULL; + } + + if (dir != NULL) { + (void)closedir(dir); + dir = NULL; + } + + /* support for ``~user'' syntax */ + free(dirpath); + + if (dirname == NULL && (dirname = strdup("./")) == NULL) + return NULL; + + if (*dirname == '~') + dirpath = tilde_expand(dirname); + else + dirpath = strdup(dirname); + + if (dirpath == NULL) + return NULL; + + dir = opendir(dirpath); + if (!dir) + return (NULL); /* cannot open the directory */ + + /* will be used in cycle */ + filename_len = filename ? strlen(filename) : 0; + } + + /* find the match */ + while ((entry = readdir(dir)) != NULL) { + /* skip . and .. */ + if (entry->d_name[0] == '.' && (!entry->d_name[1] + || (entry->d_name[1] == '.' && !entry->d_name[2]))) + continue; + if (filename_len == 0) + break; + /* otherwise, get first entry where first */ + /* filename_len characters are equal */ + if (entry->d_name[0] == filename[0] +#if defined(__SVR4) || defined(__linux__) + && strlen(entry->d_name) >= filename_len +#else + && entry->d_namlen >= filename_len +#endif + && strncmp(entry->d_name, filename, + filename_len) == 0) + break; + } + + if (entry) { /* match found */ + struct stat stbuf; + const char *isdir = ""; + +#if defined(__SVR4) || defined(__linux__) + len = strlen(entry->d_name); +#else + len = entry->d_namlen; +#endif + temp = malloc(strlen(dirpath) + len + 1); + if (temp == NULL) + return NULL; + (void)sprintf(temp, "%s%s", dirpath, entry->d_name); /* safe */ + + /* test, if it's directory */ + if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) + isdir = "/"; + free(temp); + temp = malloc(strlen(dirname) + len + 1 + 1); + if (temp == NULL) + return NULL; + (void)sprintf(temp, "%s%s%s", dirname, entry->d_name, isdir); + } else { + (void)closedir(dir); + dir = NULL; + temp = NULL; + } + + return (temp); +} + + + +/* + * returns list of completions for text given + * non-static for readline. + */ +char ** completion_matches(const char *, char *(*)(const char *, int)); +char ** +completion_matches(const char *text, char *(*genfunc)(const char *, int)) +{ + char **match_list = NULL, *retstr, *prevstr; + size_t match_list_len, max_equal, which, i; + size_t matches; + + matches = 0; + match_list_len = 1; + while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { + /* allow for list terminator here */ + if (matches + 3 >= match_list_len) { + char **nmatch_list; + while (matches + 3 >= match_list_len) + match_list_len <<= 1; + nmatch_list = realloc(match_list, + match_list_len * sizeof(char *)); + if (nmatch_list == NULL) { + free(match_list); + return NULL; + } + match_list = nmatch_list; + + } + match_list[++matches] = retstr; + } + + if (!match_list) + return NULL; /* nothing found */ + + /* find least denominator and insert it to match_list[0] */ + which = 2; + prevstr = match_list[1]; + max_equal = strlen(prevstr); + for (; which <= matches; which++) { + for (i = 0; i < max_equal && + prevstr[i] == match_list[which][i]; i++) + continue; + max_equal = i; + } + + retstr = malloc(max_equal + 1); + if (retstr == NULL) { + free(match_list); + return NULL; + } + (void)strncpy(retstr, match_list[1], max_equal); + retstr[max_equal] = '\0'; + match_list[0] = retstr; + + /* add NULL as last pointer to the array */ + match_list[matches + 1] = (char *) NULL; + + return (match_list); +} + +/* + * Sort function for qsort(). Just wrapper around strcasecmp(). + */ +static int +_fn_qsort_string_compare(const void *i1, const void *i2) +{ + const char *s1 = ((const char * const *)i1)[0]; + const char *s2 = ((const char * const *)i2)[0]; + + return strcasecmp(s1, s2); +} + +/* + * Display list of strings in columnar format on readline's output stream. + * 'matches' is list of strings, 'len' is number of strings in 'matches', + * 'max' is maximum length of string in 'matches'. + */ +void +fn_display_match_list (EditLine *el, char **matches, int len, int max) +{ + int i, idx, limit, count; + int screenwidth = el->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 *), + _fn_qsort_string_compare); + + idx = 1; + for(; count > 0; count--) { + for(i = 0; i < limit && matches[idx]; i++, idx++) + (void)fprintf(el->el_outfile, "%-*s ", max, + matches[idx]); + (void)fprintf(el->el_outfile, "\n"); + } +} + +/* + * Complete the word at or before point, + * 'what_to_do' says what to do with the completion. + * \t means do standard completion. + * `?' means list the possible completions. + * `*' 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 + * '!' could never be invoked + */ +int +fn_complete(EditLine *el, + char *(*complet_func)(const char *, int), + char **(*attempted_completion_function)(const char *, int, int), + const char *word_break, const char *special_prefixes, + char append_character, int query_items, + int *completion_type, int *over, int *point, int *end) +{ + const LineInfo *li; + char *temp, **matches; + const char *ctemp; + size_t len; + int what_to_do = '\t'; + + if (el->el_state.lastcmd == el->el_state.thiscmd) + what_to_do = '?'; + + /* readline's rl_complete() has to be told what we did... */ + if (completion_type != NULL) + *completion_type = what_to_do; + + if (!complet_func) + complet_func = filename_completion_function; + + /* We now look backwards for the start of a filename/variable word */ + li = el_line(el); + ctemp = (const char *) li->cursor; + while (ctemp > li->buffer + && !strchr(word_break, ctemp[-1]) + && (!special_prefixes || !strchr(special_prefixes, ctemp[-1]) ) ) + ctemp--; + + len = li->cursor - ctemp; + temp = alloca(len + 1); + (void)strncpy(temp, ctemp, len); + temp[len] = '\0'; + + /* these can be used by function called in completion_matches() */ + /* or (*attempted_completion_function)() */ + if (point != 0) + *point = li->cursor - li->buffer; + if (end != NULL) + *end = li->lastchar - li->buffer; + + if (attempted_completion_function) { + int cur_off = li->cursor - li->buffer; + matches = (*attempted_completion_function) (temp, + (int)(cur_off - len), cur_off); + } else + matches = 0; + if (!attempted_completion_function || + (over != NULL && *over && !matches)) + matches = completion_matches(temp, complet_func); + + if (over != NULL) + *over = 0; + + if (matches) { + int i, retval = CC_REFRESH; + int matches_num, maxlen, match_len, match_display=1; + + /* + * Only replace the completed string with common part of + * possible matches if there is possible completion. + */ + if (matches[0][0] != '\0') { + el_deletestr(el, (int) len); + el_insertstr(el, matches[0]); + } + + if (what_to_do == '?') + goto display_matches; + + if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { + /* + * We found exact match. Add a space after + * it, unless we do filename completion and the + * object is a directory. + */ + size_t alen = strlen(matches[0]); + if ((complet_func != filename_completion_function + || (alen > 0 && (matches[0])[alen - 1] != '/')) + && append_character) { + char buf[2]; + buf[0] = append_character; + buf[1] = '\0'; + el_insertstr(el, buf); + } + } else if (what_to_do == '!') { + display_matches: + /* + * More than one match and requested to list possible + * matches. + */ + + for(i=1, maxlen=0; matches[i]; i++) { + match_len = strlen(matches[i]); + if (match_len > maxlen) + maxlen = match_len; + } + matches_num = i - 1; + + /* newline to get on next line from command line */ + (void)fprintf(el->el_outfile, "\n"); + + /* + * If there are too many items, ask user for display + * confirmation. + */ + if (matches_num > query_items) { + (void)fprintf(el->el_outfile, + "Display all %d possibilities? (y or n) ", + matches_num); + (void)fflush(el->el_outfile); + if (getc(stdin) != 'y') + match_display = 0; + (void)fprintf(el->el_outfile, "\n"); + } + + if (match_display) + fn_display_match_list(el, matches, matches_num, + maxlen); + retval = CC_REDISPLAY; + } else if (matches[0][0]) { + /* + * There was some common match, but the name was + * not complete enough. Next tab will print possible + * completions. + */ + el_beep(el); + } else { + /* lcd is not a valid object - further specification */ + /* is needed */ + el_beep(el); + retval = CC_NORM; + } + + /* free elements of array and the array itself */ + for (i = 0; matches[i]; i++) + free(matches[i]); + free(matches), matches = NULL; + + return (retval); + } + return (CC_NORM); +} + +/* + * el-compatible wrapper around rl_complete; needed for key binding + */ +/* ARGSUSED */ +unsigned char +_el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) +{ + return (unsigned char)fn_complete(el, NULL, NULL, + break_chars, NULL, ' ', 100, + NULL, NULL, NULL, NULL); +} diff --git a/net/tnftp/files/libedit/filecomplete.h b/net/tnftp/files/libedit/filecomplete.h new file mode 100644 index 00000000000..ad173b74b52 --- /dev/null +++ b/net/tnftp/files/libedit/filecomplete.h @@ -0,0 +1,52 @@ +/* NetBSD: filecomplete.h,v 1.1.1.1 2005/05/31 01:53:11 lukem Exp */ +/* from NetBSD: filecomplete.h,v 1.2 2005/05/07 16:28:32 dsl Exp */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jaromir Dolecek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _FILECOMPLETE_H_ +#define _FILECOMPLETE_H_ + +int fn_complete(EditLine *, + char *(*)(const char *, int), + char **(*)(const char *, int, int), + const char *, const char *, char, int, + int *, int *, int *, int *); + +void fn_display_match_list(EditLine *, char **, int, int); +char *tilde_expand(char *txt); +char *filename_completion_function(const char *, int); + +#endif diff --git a/net/tnftp/files/libedit/readline.c b/net/tnftp/files/libedit/readline.c index 3cb57b5ee1e..afeb75714d1 100644 --- a/net/tnftp/files/libedit/readline.c +++ b/net/tnftp/files/libedit/readline.c @@ -1,5 +1,5 @@ -/* NetBSD: readline.c,v 1.2 2005/05/11 01:17:39 lukem Exp */ -/* from NetBSD: readline.c,v 1.47 2004/09/08 18:15:57 christos Exp */ +/* NetBSD: readline.c,v 1.4 2005/06/09 16:48:58 lukem Exp */ +/* from NetBSD: readline.c,v 1.55 2005/05/27 14:01:46 agc Exp */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -37,11 +37,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -__RCSID("NetBSD: readline.c,v 1.2 2005/05/11 01:17:39 lukem Exp"); -#endif /* not lint && not SCCSID */ - #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> @@ -66,6 +61,7 @@ __RCSID("NetBSD: readline.c,v 1.2 2005/05/11 01:17:39 lukem Exp"); #include "fcns.h" /* for EL_NUM_FCNS */ #include "histedit.h" #include "readline/readline.h" +#include "filecomplete.h" /* for rl_complete() */ #define TAB '\r' @@ -86,7 +82,7 @@ FILE *rl_outstream = NULL; int rl_point = 0; int rl_end = 0; char *rl_line_buffer = NULL; -VFunction *rl_linefunc = NULL; +VCPFunction *rl_linefunc = NULL; int rl_done = 0; VFunction *rl_event_hook = NULL; @@ -142,7 +138,7 @@ int rl_completion_query_items = 100; * 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; +char *rl_special_prefixes = NULL; /* * This is the character appended to the completed words if at the end of @@ -152,13 +148,9 @@ 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; - static History *h = NULL; static EditLine *e = NULL; static Function *map[256]; -static int el_rl_complete_cmdnum = 0; /* internal functions */ static unsigned char _el_rl_complete(EditLine *, int); @@ -169,9 +161,8 @@ static int _history_expand_command(const char *, size_t, size_t, char **); static char *_rl_compat_sub(const char *, const char *, const char *, int); -static int rl_complete_internal(int); -static int _rl_qsort_string_compare(const void *, const void *); static int _rl_event_read_char(EditLine *, char *); +static void _rl_update_pos(void); /* ARGSUSED */ @@ -214,7 +205,6 @@ rl_initialize(void) { HistEvent ev; const LineInfo *li; - int i; int editmode = 1; struct termios t; @@ -282,17 +272,6 @@ rl_initialize(void) "ReadLine compatible suspend function", _el_rl_tstp); el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); - - /* - * Find out where the rl_complete function was added; this is - * used later to detect that lastcmd was also rl_complete. - */ - for(i=EL_NUM_FCNS; i < e->el_map.nfunc; i++) { - if (e->el_map.func[i] == _el_rl_complete) { - el_rl_complete_cmdnum = i; - break; - } - } /* read settings from configuration file */ el_source(e, NULL); @@ -304,7 +283,7 @@ rl_initialize(void) li = el_line(e); /* a cheesy way to get rid of const cast. */ rl_line_buffer = memchr(li->buffer, *li->buffer, 1); - rl_point = rl_end = 0; + _rl_update_pos(); if (rl_startup_hook) (*rl_startup_hook)(NULL, 0); @@ -1369,178 +1348,6 @@ history_search_pos(const char *str, /* completion functions */ /* - * does tilde expansion of strings of type ``~user/foo'' - * if ``user'' isn't valid user name or ``txt'' doesn't start - * w/ '~', returns pointer to strdup()ed copy of ``txt'' - * - * it's callers's responsibility to free() returned string - */ -char * -tilde_expand(char *txt) -{ - struct passwd *pass; - char *temp; - size_t len = 0; - - if (txt[0] != '~') - return (strdup(txt)); - - temp = strchr(txt + 1, '/'); - if (temp == NULL) { - temp = strdup(txt + 1); - if (temp == NULL) - return NULL; - } else { - len = temp - txt + 1; /* text until string after slash */ - temp = malloc(len); - if (temp == NULL) - return NULL; - (void)strncpy(temp, txt + 1, len - 2); - temp[len - 2] = '\0'; - } - pass = getpwnam(temp); - free(temp); /* value no more needed */ - if (pass == NULL) - return (strdup(txt)); - - /* update pointer txt to point at string immedially following */ - /* first slash */ - txt += len; - - temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); - if (temp == NULL) - return NULL; - (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); - - return (temp); -} - - -/* - * return first found file name starting by the ``text'' or NULL if no - * such file can be found - * value of ``state'' is ignored - * - * it's caller's responsibility to free returned string - */ -char * -filename_completion_function(const char *text, int state) -{ - static DIR *dir = NULL; - static char *filename = NULL, *dirname = NULL; - static size_t filename_len = 0; - struct dirent *entry; - char *temp; - size_t len; - - if (state == 0 || dir == NULL) { - temp = strrchr(text, '/'); - if (temp) { - char *nptr; - temp++; - nptr = realloc(filename, strlen(temp) + 1); - if (nptr == NULL) { - free(filename); - return NULL; - } - filename = nptr; - (void)strcpy(filename, temp); - len = temp - text; /* including last slash */ - nptr = realloc(dirname, len + 1); - if (nptr == NULL) { - free(filename); - return NULL; - } - dirname = nptr; - (void)strncpy(dirname, text, len); - dirname[len] = '\0'; - } else { - if (*text == 0) - filename = NULL; - else { - filename = strdup(text); - if (filename == NULL) - return NULL; - } - dirname = NULL; - } - - /* support for ``~user'' syntax */ - if (dirname && *dirname == '~') { - char *nptr; - temp = tilde_expand(dirname); - if (temp == NULL) - return NULL; - nptr = realloc(dirname, strlen(temp) + 1); - if (nptr == NULL) { - free(dirname); - return NULL; - } - dirname = nptr; - (void)strcpy(dirname, temp); /* safe */ - free(temp); /* no longer needed */ - } - /* will be used in cycle */ - filename_len = filename ? strlen(filename) : 0; - - if (dir != NULL) { - (void)closedir(dir); - dir = NULL; - } - dir = opendir(dirname ? dirname : "."); - if (!dir) - return (NULL); /* cannot open the directory */ - } - /* find the match */ - while ((entry = readdir(dir)) != NULL) { - /* skip . and .. */ - if (entry->d_name[0] == '.' && (!entry->d_name[1] - || (entry->d_name[1] == '.' && !entry->d_name[2]))) - continue; - if (filename_len == 0) - break; - /* otherwise, get first entry where first */ - /* filename_len characters are equal */ - if (entry->d_name[0] == filename[0] -#if defined(__SVR4) || defined(__linux__) - && strlen(entry->d_name) >= filename_len -#else - && entry->d_namlen >= filename_len -#endif - && strncmp(entry->d_name, filename, - filename_len) == 0) - break; - } - - if (entry) { /* match found */ - - struct stat stbuf; -#if defined(__SVR4) || defined(__linux__) - len = strlen(entry->d_name) + -#else - len = entry->d_namlen + -#endif - ((dirname) ? strlen(dirname) : 0) + 1 + 1; - temp = malloc(len); - if (temp == NULL) - return NULL; - (void)sprintf(temp, "%s%s", - dirname ? dirname : "", entry->d_name); /* safe */ - - /* test, if it's directory */ - if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) - strcat(temp, "/"); /* safe */ - } else { - (void)closedir(dir); - dir = NULL; - temp = NULL; - } - - return (temp); -} - - -/* * a completion generator for usernames; returns _first_ username * which starts with supplied text * text contains a partial username preceded by random character @@ -1550,7 +1357,8 @@ filename_completion_function(const char *text, int state) char * username_completion_function(const char *text, int state) { - struct passwd *pwd; + struct passwd *pwd, pwres; + char pwbuf[1024]; if (text[0] == '\0') return (NULL); @@ -1561,7 +1369,8 @@ username_completion_function(const char *text, int state) if (state == 0) setpwent(); - while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] + while (getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pwd) == 0 + && pwd != NULL && text[0] == pwd->pw_name[0] && strcmp(text, pwd->pw_name) == 0); if (pwd == NULL) { @@ -1573,16 +1382,6 @@ username_completion_function(const char *text, int state) /* - * el-compatible wrapper around rl_complete; needed for key binding - */ -/* ARGSUSED */ -static unsigned char -_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) -{ - return (unsigned char) rl_complete(0, ch); -} - -/* * el-compatible wrapper to send TSTP on ^Z */ /* ARGSUSED */ @@ -1594,273 +1393,24 @@ _el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__un } /* - * returns list of completions for text given - */ -char ** -completion_matches(const char *text, CPFunction *genfunc) -{ - char **match_list = NULL, *retstr, *prevstr; - size_t match_list_len, max_equal, which, i; - size_t matches; - - if (h == NULL || e == NULL) - rl_initialize(); - - matches = 0; - match_list_len = 1; - while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { - /* allow for list terminator here */ - if (matches + 3 >= match_list_len) { - char **nmatch_list; - while (matches + 3 >= match_list_len) - match_list_len <<= 1; - nmatch_list = realloc(match_list, - match_list_len * sizeof(char *)); - if (nmatch_list == NULL) { - free(match_list); - return NULL; - } - match_list = nmatch_list; - - } - match_list[++matches] = retstr; - } - - if (!match_list) - return NULL; /* nothing found */ - - /* find least denominator and insert it to match_list[0] */ - which = 2; - prevstr = match_list[1]; - max_equal = strlen(prevstr); - for (; which <= matches; which++) { - for (i = 0; i < max_equal && - prevstr[i] == match_list[which][i]; i++) - continue; - max_equal = i; - } - - retstr = malloc(max_equal + 1); - if (retstr == NULL) { - free(match_list); - return NULL; - } - (void)strncpy(retstr, match_list[1], max_equal); - retstr[max_equal] = '\0'; - match_list[0] = retstr; - - /* add NULL as last pointer to the array */ - match_list[matches + 1] = (char *) NULL; - - return (match_list); -} - -/* - * Sort function for qsort(). Just wrapper around strcasecmp(). - */ -static int -_rl_qsort_string_compare(i1, i2) - const void *i1, *i2; -{ - const char *s1 = ((const char * const *)i1)[0]; - const char *s2 = ((const char * const *)i2)[0]; - - return strcasecmp(s1, s2); -} - -/* * Display list of strings in columnar format on readline's output stream. * '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; +rl_display_match_list(char **matches, int len, int 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++) - (void)fprintf(e->el_outfile, "%-*s ", max, - matches[idx]); - (void)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 -rl_complete_internal(int what_to_do) -{ - Function *complet_func; - const LineInfo *li; - char *temp, **matches; - const char *ctemp; - size_t len; - - rl_completion_type = what_to_do; - - if (h == NULL || e == NULL) - rl_initialize(); - - complet_func = rl_completion_entry_function; - if (!complet_func) - complet_func = (Function *)(void *)filename_completion_function; - - /* We now look backwards for the start of a filename/variable word */ - li = el_line(e); - ctemp = (const char *) li->cursor; - while (ctemp > li->buffer - && !strchr(rl_basic_word_break_characters, ctemp[-1]) - && (!rl_special_prefixes - || !strchr(rl_special_prefixes, ctemp[-1]) ) ) - ctemp--; - - len = li->cursor - ctemp; - temp = alloca(len + 1); - (void)strncpy(temp, ctemp, len); - temp[len] = '\0'; - - /* these can be used by function called in completion_matches() */ - /* or (*rl_attempted_completion_function)() */ - rl_point = li->cursor - li->buffer; - rl_end = li->lastchar - li->buffer; - - if (rl_attempted_completion_function) { - int end = li->cursor - li->buffer; - matches = (*rl_attempted_completion_function) (temp, (int) - (end - len), end); - } else - matches = 0; - if (!rl_attempted_completion_function || !matches) - matches = completion_matches(temp, (CPFunction *)complet_func); - - if (matches) { - int i, retval = CC_REFRESH; - int matches_num, maxlen, match_len, match_display=1; - - /* - * Only replace the completed string with common part of - * possible matches if there is possible completion. - */ - if (matches[0][0] != '\0') { - el_deletestr(e, (int) len); - el_insertstr(e, matches[0]); - } - - if (what_to_do == '?') - goto display_matches; - - if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { - /* - * We found exact match. Add a space after - * it, unless we do filename completion and the - * object is a directory. - */ - size_t alen = strlen(matches[0]); - if ((complet_func != - (Function *)filename_completion_function - || (alen > 0 && (matches[0])[alen - 1] != '/')) - && rl_completion_append_character) { - char buf[2]; - buf[0] = rl_completion_append_character; - buf[1] = '\0'; - el_insertstr(e, buf); - } - } else if (what_to_do == '!') { - display_matches: - /* - * More than one match and requested to list possible - * matches. - */ - - for(i=1, maxlen=0; matches[i]; i++) { - match_len = strlen(matches[i]); - if (match_len > maxlen) - maxlen = match_len; - } - matches_num = i - 1; - - /* newline to get on next line from command line */ - (void)fprintf(e->el_outfile, "\n"); - - /* - * If there are too many items, ask user for display - * confirmation. - */ - if (matches_num > rl_completion_query_items) { - (void)fprintf(e->el_outfile, - "Display all %d possibilities? (y or n) ", - matches_num); - (void)fflush(e->el_outfile); - if (getc(stdin) != 'y') - match_display = 0; - (void)fprintf(e->el_outfile, "\n"); - } - - if (match_display) - rl_display_match_list(matches, matches_num, - maxlen); - retval = CC_REDISPLAY; - } else if (matches[0][0]) { - /* - * There was some common match, but the name was - * not complete enough. Next tab will print possible - * completions. - */ - el_beep(e); - } else { - /* lcd is not a valid object - further specification */ - /* is needed */ - el_beep(e); - retval = CC_NORM; - } - - /* free elements of array and the array itself */ - for (i = 0; matches[i]; i++) - free(matches[i]); - free(matches), matches = NULL; - - return (retval); - } - return (CC_NORM); + fn_display_match_list(e, matches, len, max); } /* * complete word at current point */ +/* ARGSUSED */ int -rl_complete(int ignore, int invoking_key) +rl_complete(int ignore __attribute__((__unused__)), int invoking_key) { if (h == NULL || e == NULL) rl_initialize(); @@ -1871,15 +1421,26 @@ rl_complete(int ignore, int invoking_key) arr[1] = '\0'; el_insertstr(e, arr); return (CC_REFRESH); - } else if (e->el_state.lastcmd == el_rl_complete_cmdnum) - return rl_complete_internal('?'); - else if (_rl_complete_show_all) - return rl_complete_internal('!'); - else - return (rl_complete_internal(TAB)); + } + + /* Just look at how many global variables modify this operation! */ + return fn_complete(e, + (CPFunction *)rl_completion_entry_function, + rl_attempted_completion_function, + rl_basic_word_break_characters, rl_special_prefixes, + rl_completion_append_character, rl_completion_query_items, + &rl_completion_type, &rl_attempted_completion_over, + &rl_point, &rl_end); } +/* ARGSUSED */ +static unsigned char +_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) +{ + return (unsigned char)rl_complete(0, ch); +} + /* * misc other functions */ @@ -1971,6 +1532,9 @@ rl_bind_wrapper(EditLine *el, unsigned char c) { if (map[c] == NULL) return CC_ERROR; + + _rl_update_pos(); + (*map[c])(NULL, c); /* If rl_done was set by the above call, deal with it here */ @@ -2015,11 +1579,12 @@ rl_callback_read_char() } else wbuf = NULL; (*(void (*)(const char *))rl_linefunc)(wbuf); + el_set(e, EL_UNBUFFERED, 1); } } void -rl_callback_handler_install (const char *prompt, VFunction *linefunc) +rl_callback_handler_install (const char *prompt, VCPFunction *linefunc) { if (e == NULL) { rl_initialize(); @@ -2090,6 +1655,16 @@ rl_parse_and_bind(const char *line) return (argc ? 1 : 0); } +int +rl_variable_bind(const char *var, const char *value) +{ + /* + * The proper return value is undocument, but this is what the + * readline source seems to do. + */ + return ((el_set(e, EL_BIND, "", var, value) == -1) ? 1 : 0); +} + void rl_stuff_char(int c) { @@ -2141,3 +1716,12 @@ _rl_event_read_char(EditLine *el, char *cp) el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); return(num_read); } + +static void +_rl_update_pos(void) +{ + const LineInfo *li = el_line(e); + + rl_point = li->cursor - li->buffer; + rl_end = li->lastchar - li->buffer; +} diff --git a/net/tnftp/files/libnetbsd/dirname.c b/net/tnftp/files/libnetbsd/dirname.c new file mode 100644 index 00000000000..a751c0e036a --- /dev/null +++ b/net/tnftp/files/libnetbsd/dirname.c @@ -0,0 +1,84 @@ +/* NetBSD: dirname.c,v 1.1 2005/06/01 15:07:55 lukem Exp */ +/* from NetBSD: dirname.c,v 1.7 2002/10/17 11:36:39 tron Exp */ + +/*- + * Copyright (c) 1997, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Klaus Klein and Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tnftp.h" + +char * +dirname(path) + char *path; +{ + static char singledot[] = "."; + static char result[PATH_MAX]; + char *lastp; + size_t len; + + /* + * If `path' is a null pointer or points to an empty string, + * return a pointer to the string ".". + */ + if ((path == NULL) || (*path == '\0')) + return (singledot); + + /* Strip trailing slashes, if any. */ + lastp = path + strlen(path) - 1; + while (lastp != path && *lastp == '/') + lastp--; + + /* Terminate path at the last occurence of '/'. */ + do { + if (*lastp == '/') { + /* Strip trailing slashes, if any. */ + while (lastp != path && *lastp == '/') + lastp--; + + /* ...and copy the result into the result buffer. */ + len = (lastp - path) + 1 /* last char */; + if (len > (PATH_MAX - 1)) + len = PATH_MAX - 1; + + memcpy(result, path, len); + result[len] = '\0'; + + return (result); + } + } while (--lastp >= path); + + /* No /'s found, return a pointer to the string ".". */ + return (singledot); +} |