"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/src/complete.c" (4 Jul 2020, 10615 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "complete.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

    1 /*  $NetBSD: complete.c,v 1.11 2020/07/04 09:59:07 lukem Exp $  */
    2 /*  from    NetBSD: complete.c,v 1.47 2019/01/28 12:04:16 christos Exp  */
    3 
    4 /*-
    5  * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Luke Mewburn.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include "tnftp.h"
   34 
   35 #if 0   /* tnftp */
   36 
   37 #include <sys/cdefs.h>
   38 #ifndef lint
   39 __RCSID(" NetBSD: complete.c,v 1.47 2019/01/28 12:04:16 christos Exp  ");
   40 #endif /* not lint */
   41 
   42 /*
   43  * FTP user program - command and file completion routines
   44  */
   45 
   46 #include <sys/stat.h>
   47 
   48 #include <ctype.h>
   49 #include <err.h>
   50 #include <dirent.h>
   51 #include <stdio.h>
   52 #include <stdlib.h>
   53 #include <string.h>
   54 
   55 #endif  /* tnftp */
   56 
   57 #include "ftp_var.h"
   58 
   59 #ifndef NO_EDITCOMPLETE
   60 
   61 static int       comparstr      (const void *, const void *);
   62 static unsigned char complete_ambiguous (char *, int, StringList *);
   63 static unsigned char complete_command   (char *, int);
   64 static unsigned char complete_local (char *, int);
   65 static unsigned char complete_option    (char *, int);
   66 static unsigned char complete_remote    (char *, int);
   67 
   68 static int
   69 comparstr(const void *a, const void *b)
   70 {
   71     return (strcmp(*(const char * const *)a, *(const char * const *)b));
   72 }
   73 
   74 /*
   75  * Determine if complete is ambiguous. If unique, insert.
   76  * If no choices, error. If unambiguous prefix, insert that.
   77  * Otherwise, list choices. words is assumed to be filtered
   78  * to only contain possible choices.
   79  * Args:
   80  *  word    word which started the match
   81  *  list    list by default
   82  *  words   stringlist containing possible matches
   83  * Returns a result as per el_set(EL_ADDFN, ...)
   84  */
   85 static unsigned char
   86 complete_ambiguous(char *word, int list, StringList *words)
   87 {
   88     char insertstr[MAXPATHLEN];
   89     char *lastmatch, *p;
   90     size_t i, j;
   91     size_t matchlen, wordlen;
   92 
   93     wordlen = strlen(word);
   94     if (words->sl_cur == 0)
   95         return (CC_ERROR);  /* no choices available */
   96 
   97     if (words->sl_cur == 1) {   /* only once choice available */
   98         p = words->sl_str[0] + wordlen;
   99         if (*p == '\0')     /* at end of word? */
  100             return (CC_REFRESH);
  101         ftpvis(insertstr, sizeof(insertstr), p, strlen(p));
  102         if (el_insertstr(el, insertstr) == -1)
  103             return (CC_ERROR);
  104         else
  105             return (CC_REFRESH);
  106     }
  107 
  108     if (!list) {
  109         lastmatch = words->sl_str[0];
  110         matchlen = strlen(lastmatch);
  111         for (i = 1 ; i < words->sl_cur ; i++) {
  112             for (j = wordlen; j < strlen(words->sl_str[i]); j++)
  113                 if (lastmatch[j] != words->sl_str[i][j])
  114                     break;
  115             if (j < matchlen)
  116                 matchlen = j;
  117         }
  118         if (matchlen > wordlen) {
  119             ftpvis(insertstr, sizeof(insertstr),
  120                 lastmatch + wordlen, matchlen - wordlen);
  121             if (el_insertstr(el, insertstr) == -1)
  122                 return (CC_ERROR);
  123             else
  124                 return (CC_REFRESH_BEEP);
  125         }
  126     }
  127 
  128     putc('\n', ttyout);
  129     qsort(words->sl_str, words->sl_cur, sizeof(char *), comparstr);
  130     list_vertical(words);
  131     return (CC_REDISPLAY);
  132 }
  133 
  134 /*
  135  * Complete a command
  136  */
  137 static unsigned char
  138 complete_command(char *word, int list)
  139 {
  140     struct cmd *c;
  141     StringList *words;
  142     size_t wordlen;
  143     unsigned char rv;
  144 
  145     words = ftp_sl_init();
  146     wordlen = strlen(word);
  147 
  148     for (c = cmdtab; c->c_name != NULL; c++) {
  149         if (wordlen > strlen(c->c_name))
  150             continue;
  151         if (strncmp(word, c->c_name, wordlen) == 0)
  152             ftp_sl_add(words, ftp_strdup(c->c_name));
  153     }
  154 
  155     rv = complete_ambiguous(word, list, words);
  156     if (rv == CC_REFRESH) {
  157         if (el_insertstr(el, " ") == -1)
  158             rv = CC_ERROR;
  159     }
  160     sl_free(words, 1);
  161     return (rv);
  162 }
  163 
  164 /*
  165  * Complete a local file
  166  */
  167 static unsigned char
  168 complete_local(char *word, int list)
  169 {
  170     StringList *words;
  171     char dir[MAXPATHLEN];
  172     char *file;
  173     DIR *dd;
  174     struct dirent *dp;
  175     unsigned char rv;
  176     size_t len;
  177 
  178     if ((file = strrchr(word, '/')) == NULL) {
  179         dir[0] = '.';
  180         dir[1] = '\0';
  181         file = word;
  182     } else {
  183         if (file == word) {
  184             dir[0] = '/';
  185             dir[1] = '\0';
  186         } else
  187             (void)strlcpy(dir, word, file - word + 1);
  188         file++;
  189     }
  190     if (dir[0] == '~') {
  191         char *p;
  192 
  193         if ((p = globulize(dir)) == NULL)
  194             return (CC_ERROR);
  195         (void)strlcpy(dir, p, sizeof(dir));
  196         free(p);
  197     }
  198 
  199     if ((dd = opendir(dir)) == NULL)
  200         return (CC_ERROR);
  201 
  202     words = ftp_sl_init();
  203     len = strlen(file);
  204 
  205     for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
  206         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  207             continue;
  208 
  209 #if defined(DIRENT_MISSING_D_NAMLEN)
  210         if (len > strlen(dp->d_name))
  211             continue;
  212 #else
  213         if (len > dp->d_namlen)
  214             continue;
  215 #endif
  216         if (strncmp(file, dp->d_name, len) == 0) {
  217             char *tcp;
  218 
  219             tcp = ftp_strdup(dp->d_name);
  220             ftp_sl_add(words, tcp);
  221         }
  222     }
  223     closedir(dd);
  224 
  225     rv = complete_ambiguous(file, list, words);
  226     if (rv == CC_REFRESH) {
  227         struct stat sb;
  228         char path[MAXPATHLEN];
  229 
  230         (void)strlcpy(path, dir,        sizeof(path));
  231         (void)strlcat(path, "/",        sizeof(path));
  232         (void)strlcat(path, words->sl_str[0],   sizeof(path));
  233 
  234         if (stat(path, &sb) >= 0) {
  235             char suffix[2] = " ";
  236 
  237             if (S_ISDIR(sb.st_mode))
  238                 suffix[0] = '/';
  239             if (el_insertstr(el, suffix) == -1)
  240                 rv = CC_ERROR;
  241         }
  242     }
  243     sl_free(words, 1);
  244     return (rv);
  245 }
  246 /*
  247  * Complete an option
  248  */
  249 static unsigned char
  250 complete_option(char *word, int list)
  251 {
  252     struct option *o;
  253     StringList *words;
  254     size_t wordlen;
  255     unsigned char rv;
  256 
  257     words = ftp_sl_init();
  258     wordlen = strlen(word);
  259 
  260     for (o = optiontab; o->name != NULL; o++) {
  261         if (wordlen > strlen(o->name))
  262             continue;
  263         if (strncmp(word, o->name, wordlen) == 0)
  264             ftp_sl_add(words, ftp_strdup(o->name));
  265     }
  266 
  267     rv = complete_ambiguous(word, list, words);
  268     if (rv == CC_REFRESH) {
  269         if (el_insertstr(el, " ") == -1)
  270             rv = CC_ERROR;
  271     }
  272     sl_free(words, 1);
  273     return (rv);
  274 }
  275 
  276 /*
  277  * Complete a remote file
  278  */
  279 static unsigned char
  280 complete_remote(char *word, int list)
  281 {
  282     static StringList *dirlist;
  283     static char  lastdir[MAXPATHLEN];
  284     StringList  *words;
  285     char         dir[MAXPATHLEN];
  286     char        *file, *cp;
  287     size_t       i;
  288     unsigned char    rv;
  289     char         cmdbuf[MAX_C_NAME];
  290     char        *dummyargv[3] = { NULL, NULL, NULL };
  291 
  292     (void)strlcpy(cmdbuf, "complete", sizeof(cmdbuf));
  293     dummyargv[0] = cmdbuf;
  294     dummyargv[1] = dir;
  295 
  296     if ((file = strrchr(word, '/')) == NULL) {
  297         dir[0] = '\0';
  298         file = word;
  299     } else {
  300         cp = file;
  301         while (*cp == '/' && cp > word)
  302             cp--;
  303         (void)strlcpy(dir, word, cp - word + 2);
  304         file++;
  305     }
  306 
  307     if (dirchange || dirlist == NULL ||
  308         strcmp(dir, lastdir) != 0) {        /* dir not cached */
  309         const char *emesg;
  310 
  311         if (dirlist != NULL)
  312             sl_free(dirlist, 1);
  313         dirlist = ftp_sl_init();
  314 
  315         mflag = 1;
  316         emesg = NULL;
  317         while ((cp = remglob(dummyargv, 0, &emesg)) != NULL) {
  318             char *tcp;
  319 
  320             if (!mflag)
  321                 continue;
  322             if (*cp == '\0') {
  323                 mflag = 0;
  324                 continue;
  325             }
  326             tcp = strrchr(cp, '/');
  327             if (tcp)
  328                 tcp++;
  329             else
  330                 tcp = cp;
  331             tcp = ftp_strdup(tcp);
  332             ftp_sl_add(dirlist, tcp);
  333         }
  334         if (emesg != NULL) {
  335             fprintf(ttyout, "\n%s\n", emesg);
  336             return (CC_REDISPLAY);
  337         }
  338         (void)strlcpy(lastdir, dir, sizeof(lastdir));
  339         dirchange = 0;
  340     }
  341 
  342     words = ftp_sl_init();
  343     for (i = 0; i < dirlist->sl_cur; i++) {
  344         cp = dirlist->sl_str[i];
  345         if (strlen(file) > strlen(cp))
  346             continue;
  347         if (strncmp(file, cp, strlen(file)) == 0)
  348             ftp_sl_add(words, cp);
  349     }
  350     rv = complete_ambiguous(file, list, words);
  351     sl_free(words, 0);
  352     return (rv);
  353 }
  354 
  355 /*
  356  * Generic complete routine
  357  */
  358 unsigned char
  359 complete(EditLine *cel, int ch)
  360 {
  361     static char word[FTPBUFLEN];
  362     static size_t lastc_argc, lastc_argo;
  363 
  364     struct cmd *c;
  365     const LineInfo *lf;
  366     int dolist, cmpltype;
  367     size_t celems, len;
  368 
  369     lf = el_line(cel);
  370     len = lf->lastchar - lf->buffer;
  371     if (len >= sizeof(line))
  372         return (CC_ERROR);
  373     (void)strlcpy(line, lf->buffer, len + 1);
  374     cursor_pos = line + (lf->cursor - lf->buffer);
  375     lastc_argc = cursor_argc;   /* remember last cursor pos */
  376     lastc_argo = cursor_argo;
  377     makeargv();         /* build argc/argv of current line */
  378 
  379     if (cursor_argo >= sizeof(word))
  380         return (CC_ERROR);
  381 
  382     dolist = 0;
  383             /* if cursor and word is same, list alternatives */
  384     if (lastc_argc == cursor_argc && lastc_argo == cursor_argo
  385         && strncmp(word, margv[cursor_argc] ? margv[cursor_argc] : "",
  386             cursor_argo) == 0)
  387         dolist = 1;
  388     else if (cursor_argc < (size_t)margc)
  389         (void)strlcpy(word, margv[cursor_argc], cursor_argo + 1);
  390     word[cursor_argo] = '\0';
  391 
  392     if (cursor_argc == 0)
  393         return (complete_command(word, dolist));
  394 
  395     c = getcmd(margv[0]);
  396     if (c == (struct cmd *)-1 || c == 0)
  397         return (CC_ERROR);
  398     celems = strlen(c->c_complete);
  399 
  400         /* check for 'continuation' completes (which are uppercase) */
  401     if ((cursor_argc > celems) && (celems > 0)
  402         && isupper((unsigned char) c->c_complete[celems-1]))
  403         cursor_argc = celems;
  404 
  405     if (cursor_argc > celems)
  406         return (CC_ERROR);
  407 
  408     cmpltype = c->c_complete[cursor_argc - 1];
  409     switch (cmpltype) {
  410         case 'c':           /* command complete */
  411         case 'C':
  412             return (complete_command(word, dolist));
  413         case 'l':           /* local complete */
  414         case 'L':
  415             return (complete_local(word, dolist));
  416         case 'n':           /* no complete */
  417         case 'N':           /* no complete */
  418             return (CC_ERROR);
  419         case 'o':           /* local complete */
  420         case 'O':
  421             return (complete_option(word, dolist));
  422         case 'r':           /* remote complete */
  423         case 'R':
  424             if (connected != -1) {
  425                 fputs("\nMust be logged in to complete.\n",
  426                     ttyout);
  427                 return (CC_REDISPLAY);
  428             }
  429             return (complete_remote(word, dolist));
  430         default:
  431             errx(1, "complete: unknown complete type `%c'",
  432                 cmpltype);
  433             return (CC_ERROR);
  434     }
  435     /* NOTREACHED */
  436 }
  437 
  438 #endif /* !NO_EDITCOMPLETE */