home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ncftp-2.3.0-base.tgz / ncftp-2.3.0-base.tar / contrib / ncftp / Glob.c < prev    next >
C/C++ Source or Header  |  1995-11-26  |  7KB  |  285 lines

  1. /* Glob.c */
  2.  
  3. #include "Sys.h"
  4.  
  5. #include <ctype.h>
  6. #include <pwd.h>
  7. #include <signal.h>
  8. #include <setjmp.h>
  9.  
  10. #include "Util.h"
  11. #include "RCmd.h"
  12. #include "Glob.h"
  13. #include "Xfer.h"
  14. #include "List.h"
  15. #include "Bookmark.h"
  16. #include "Main.h"
  17.  
  18. /* Needed in case we're interrupted during local globbing. */
  19. jmp_buf gLocalGlobJmp;
  20.  
  21. extern UserInfo gUserInfo;
  22. extern Bookmark gRmtInfo;
  23. extern int gTrace;
  24.  
  25. int RGlobCmd(int argc, char **argv)
  26. {
  27.     LineList globFiles;
  28.     LinePtr globFile;
  29.     int i;
  30.  
  31.     MultiLineInit();    
  32.     for (i=1; i<argc; i++) {
  33.         InitLineList(&globFiles);
  34.         RemoteGlob(&globFiles, argv[i], kListNoFlags);
  35.  
  36.         for (globFile = globFiles.first; globFile != NULL;
  37.             globFile = globFile->next)
  38.         {
  39.             MultiLinePrintF("%s\n", globFile->line);
  40.         }
  41.         DisposeLineListContents(&globFiles);
  42.     }
  43.     return (0);
  44. }    /* RGlobCmd */
  45.  
  46.  
  47.  
  48.  
  49. /* This does "tilde-expansion."  Examples:
  50.  * ~/pub         -->  /usr/gleason/pub
  51.  * ~pdietz/junk  -->  /usr/pdietz/junk
  52.  */
  53. void ExpandTilde(char *pattern, size_t siz)
  54. {
  55.     string pat;
  56.     char *cp, *rest, *firstent;
  57.     struct passwd *pw;
  58.  
  59.     if ((pattern[0] == '~') &&
  60.     (isalnum(pattern[1]) || (pattern[1] == '/') || (pattern[1] == '\0'))) {
  61.         STRNCPY(pat, pattern);
  62.         if ((cp = strchr(pat, '/')) != NULL) {
  63.             *cp = 0;
  64.             rest = cp + 1;    /* Remember stuff after the ~/ part. */
  65.         } else {
  66.             rest = NULL;    /* Was just a ~ or ~username.  */
  67.         }
  68.         if (pat[1] == '\0') {
  69.             /* Was just a ~ or ~/rest type.  */
  70.             firstent = gUserInfo.home;
  71.         } else {
  72.             /* Was just a ~username or ~username/rest type.  */
  73.             pw = getpwnam(pat + 1);
  74.             if (pw != NULL)
  75.                 firstent = pw->pw_dir;
  76.             else
  77.                 return;        /* Bad user -- leave it alone. */
  78.         }
  79.         
  80.         Strncpy(pattern, firstent, siz);
  81.         if (rest != NULL) {
  82.             Strncat(pattern, "/", siz);
  83.             Strncat(pattern, rest, siz);
  84.         }
  85.     }
  86. }    /* ExpandTilde */
  87.  
  88.  
  89.  
  90. /*ARGSUSED*/
  91. static
  92. void LGlobHandler(int sigNum)
  93. {
  94.     alarm(0);
  95.     longjmp(gLocalGlobJmp, 1);
  96. }    /* LGlobHandler */
  97.  
  98.  
  99.  
  100.     
  101. void LocalGlob(LineListPtr fileList, char *pattern)
  102. {
  103.     string pattern2;
  104.     string cmd;
  105.     longstring gfile;
  106.     volatile FILE *fp;
  107.     volatile Sig_t si, sp;
  108.     char *cp;
  109.  
  110.     STRNCPY(pattern2, pattern);    /* Don't nuke the original. */
  111.     
  112.     /* Pre-process for ~'s. */ 
  113.     ExpandTilde(pattern2, sizeof(pattern2));
  114.     
  115.     /* Initialize the list. */
  116.     fileList->first = fileList->last = NULL;
  117.     
  118.     if (GLOBCHARSINSTR(pattern2)) {
  119.         /* Do it the easy way and have the shell do the dirty
  120.          * work for us.
  121.          */
  122.         /* May need "-1" flag here. */
  123.         cp = strrchr(gUserInfo.shell, '/');
  124.         if (cp == NULL)
  125.             cp = gUserInfo.shell;
  126.         else
  127.             ++cp;
  128.         if (STREQ(cp, "csh") || STREQ(cp, "tcsh")) {
  129.             /* Don't want to source .cshrc, which could
  130.              * change the directory, so use -f.
  131.              */
  132.             sprintf(cmd, "%s -f -c \"%s -d %s\"", gUserInfo.shell, LS, pattern2);
  133.         } else {
  134.             sprintf(cmd, "%s -c \"%s -d %s\"", gUserInfo.shell, LS, pattern2);
  135.         }
  136.  
  137.         fp = NULL;
  138.         if (setjmp(gLocalGlobJmp) == 0) {            
  139.             fp = (volatile FILE *) POpen(cmd, "r", 0);
  140.             if (fp == NULL) {
  141.                 DebugMsg("Could not lglob: %s\n", cmd);
  142.                 return;
  143.             }
  144.             sp = SIGNAL(SIGPIPE, LGlobHandler);
  145.             si = SIGNAL(SIGINT, LGlobHandler);
  146.             while (FGets(gfile, sizeof(gfile), (FILE *) fp) != NULL) {
  147.                 TraceMsg("Lglob [%s]\n", gfile);
  148.                 AddLine(fileList, gfile);
  149.             }
  150.         }
  151.         (void) SIGNAL(SIGPIPE, SIG_IGN);
  152.         if (fp != NULL)
  153.             (void) PClose((FILE *) fp);
  154.         (void) SIGNAL(SIGPIPE, sp);
  155.         (void) SIGNAL(SIGINT, si);
  156.     } else {
  157.         /* Or, if there were no globbing characters in 'pattern', then the
  158.          * pattern is really just a single pathname.
  159.          */
  160.         AddLine(fileList, pattern2);
  161.     }
  162. }    /* LocalGlob */
  163.  
  164.  
  165.  
  166. /* We need to use this because using NLST gives us more stuff than
  167.  * we want back sometimes.  For example, say we have:
  168.  *
  169.  * /a        (directory)
  170.  * /a/b        (directory)
  171.  * /a/b/b1
  172.  * /a/b/b2
  173.  * /a/b/b3
  174.  * /a/c        (directory)
  175.  * /a/c/c1
  176.  * /a/c/c2
  177.  * /a/c/c3
  178.  * /a/file
  179.  *
  180.  * If you did an "echo /a/<star>" in a normal unix shell, you would expect
  181.  * to get back /a/b /a/c /a/file.  But NLST gives back:
  182.  *
  183.  * /a/b/b1
  184.  * /a/b/b2
  185.  * /a/b/b3
  186.  * /a/c/c1
  187.  * /a/c/c2
  188.  * /a/c/c3
  189.  * /a/file
  190.  *
  191.  * So we use the following routine to convert into the format I expect.
  192.  */
  193.  
  194. static
  195. void RemoteGlobCollapse(char *pattern, LineListPtr fileList)
  196. {
  197.     LinePtr lp, nextLine;
  198.     string patPrefix;
  199.     string cur, prev;
  200.     char *endp, *cp, *dp;
  201.     char *pp;
  202.     int wasGlobChar;
  203.     size_t plen;
  204.  
  205.     /* Copy all characters before the first glob-char. */
  206.     dp = patPrefix;
  207.     endp = dp + sizeof(patPrefix) - 1;
  208.     wasGlobChar = 0;
  209.     for (cp = pattern; dp < endp; ) {
  210.         for (pp=kGlobChars; *pp != '\0'; pp++) {
  211.             if (*pp == *cp) {
  212.                 wasGlobChar = 1;
  213.                 break;
  214.             }
  215.         }
  216.         if (wasGlobChar)
  217.             break;
  218.         *dp++ = *cp++;
  219.     }
  220.     *dp = '\0';
  221.     plen = (size_t) (dp - patPrefix);
  222.  
  223.     *prev = '\0';
  224.     for (lp=fileList->first; lp != NULL; lp = nextLine) {
  225.         nextLine = lp->next;
  226.         if (strncmp(lp->line, patPrefix, plen) == 0) {
  227.             STRNCPY(cur, lp->line + plen);
  228.             cp = strchr(cur, '/');
  229.             if (cp != NULL)
  230.                 *cp = '\0';
  231.             if (STREQ(cur, prev)) {
  232.                 nextLine = RemoveLine(fileList, lp);
  233.             } else {
  234.                 STRNCPY(prev, cur);
  235.                 /* We are playing with a dynamically
  236.                  * allocated string, but since the
  237.                  * following expression is guaranteed
  238.                  * to be the same or shorter, we won't
  239.                  * overwrite the bounds.
  240.                  */
  241.                 sprintf(lp->line, "%s%s", patPrefix, cur);
  242.             }
  243.         }
  244.     }
  245. }    /* RemoteGlobCollapse */
  246.  
  247.  
  248.  
  249.  
  250. void RemoteGlob(LineListPtr fileList, char *pattern, char *lsFlags)
  251. {
  252.     char *cp;
  253.     LinePtr lp;
  254.  
  255.     /* Note that we do attempt to use glob characters even if the remote
  256.      * host isn't UNIX.  Most non-UNIX remote FTP servers look for UNIX
  257.      * style wildcards.
  258.      */
  259.     if (GLOBCHARSINSTR(pattern)) {
  260.         /* Use NLST, which lists files one per line. */
  261.         ListToMemory(fileList, "NLST", lsFlags, pattern);
  262.         if ((fileList->first != NULL) && (fileList->first == fileList->last)) {
  263.             /* If we have only one item in the list, see if it really was
  264.              * an error message we would recognize.
  265.              */
  266.             cp = strchr(fileList->first->line, ':');
  267.             if ((cp != NULL) && STREQ(cp, ": No such file or directory")) {
  268.                 RemoveLine(fileList, fileList->first);
  269.             }
  270.         }
  271.         RemoteGlobCollapse(pattern, fileList);
  272.         if (gTrace == kTracingOn) {
  273.             for (lp=fileList->first; lp != NULL; lp = lp->next)
  274.                 TraceMsg("Rglob [%s]\n", lp->line);
  275.         }
  276.     } else {
  277.         /* Or, if there were no globbing characters in 'pattern', then the
  278.          * pattern is really just a filename.  So for this case the
  279.          * file list is really just a single file.
  280.          */
  281.         fileList->first = fileList->last = NULL;
  282.         AddLine(fileList, pattern);
  283.     }
  284. }    /* RemoteGlob */
  285.