home *** CD-ROM | disk | FTP | other *** search
- /* Glob.c */
-
- #include "Sys.h"
-
- #include <ctype.h>
- #include <pwd.h>
- #include <signal.h>
- #include <setjmp.h>
-
- #include "Util.h"
- #include "RCmd.h"
- #include "Glob.h"
- #include "Xfer.h"
- #include "List.h"
- #include "Bookmark.h"
- #include "Main.h"
-
- /* Needed in case we're interrupted during local globbing. */
- jmp_buf gLocalGlobJmp;
-
- extern UserInfo gUserInfo;
- extern Bookmark gRmtInfo;
- extern int gTrace;
-
- int RGlobCmd(int argc, char **argv)
- {
- LineList globFiles;
- LinePtr globFile;
- int i;
-
- MultiLineInit();
- for (i=1; i<argc; i++) {
- InitLineList(&globFiles);
- RemoteGlob(&globFiles, argv[i], kListNoFlags);
-
- for (globFile = globFiles.first; globFile != NULL;
- globFile = globFile->next)
- {
- MultiLinePrintF("%s\n", globFile->line);
- }
- DisposeLineListContents(&globFiles);
- }
- return (0);
- } /* RGlobCmd */
-
-
-
-
- /* This does "tilde-expansion." Examples:
- * ~/pub --> /usr/gleason/pub
- * ~pdietz/junk --> /usr/pdietz/junk
- */
- void ExpandTilde(char *pattern, size_t siz)
- {
- string pat;
- char *cp, *rest, *firstent;
- struct passwd *pw;
-
- if ((pattern[0] == '~') &&
- (isalnum(pattern[1]) || (pattern[1] == '/') || (pattern[1] == '\0'))) {
- STRNCPY(pat, pattern);
- if ((cp = strchr(pat, '/')) != NULL) {
- *cp = 0;
- rest = cp + 1; /* Remember stuff after the ~/ part. */
- } else {
- rest = NULL; /* Was just a ~ or ~username. */
- }
- if (pat[1] == '\0') {
- /* Was just a ~ or ~/rest type. */
- firstent = gUserInfo.home;
- } else {
- /* Was just a ~username or ~username/rest type. */
- pw = getpwnam(pat + 1);
- if (pw != NULL)
- firstent = pw->pw_dir;
- else
- return; /* Bad user -- leave it alone. */
- }
-
- Strncpy(pattern, firstent, siz);
- if (rest != NULL) {
- Strncat(pattern, "/", siz);
- Strncat(pattern, rest, siz);
- }
- }
- } /* ExpandTilde */
-
-
-
- /*ARGSUSED*/
- static
- void LGlobHandler(void)
- {
- alarm(0);
- longjmp(gLocalGlobJmp, 1);
- } /* LGlobHandler */
-
-
-
-
- void LocalGlob(LineListPtr fileList, char *pattern)
- {
- string pattern2;
- string cmd;
- longstring gfile;
- FILE *volatile fp;
- volatile Sig_t si, sp;
- char *cp;
-
- STRNCPY(pattern2, pattern); /* Don't nuke the original. */
-
- /* Pre-process for ~'s. */
- ExpandTilde(pattern2, sizeof(pattern2));
-
- /* Initialize the list. */
- fileList->first = fileList->last = NULL;
-
- if (GLOBCHARSINSTR(pattern2)) {
- /* Do it the easy way and have the shell do the dirty
- * work for us.
- */
- /* May need "-1" flag here. */
- cp = strrchr(gUserInfo.shell, '/');
- if (cp == NULL)
- cp = gUserInfo.shell;
- else
- ++cp;
- if (STREQ(cp, "csh") || STREQ(cp, "tcsh")) {
- /* Don't want to source .cshrc, which could
- * change the directory, so use -f.
- */
- sprintf(cmd, "%s -f -c \"%s -d %s\"", gUserInfo.shell, LS, pattern2);
- } else {
- sprintf(cmd, "%s -c \"%s -d %s\"", gUserInfo.shell, LS, pattern2);
- }
-
- fp = NULL;
- if (setjmp(gLocalGlobJmp) == 0) {
- fp = POpen(cmd, "r", 0);
- if (fp == NULL) {
- DebugMsg("Could not lglob: %s\n", cmd);
- return;
- }
- sp = SIGNAL(SIGPIPE, LGlobHandler);
- si = SIGNAL(SIGINT, LGlobHandler);
- while (FGets(gfile, sizeof(gfile), (FILE *) fp) != NULL) {
- TraceMsg("Lglob [%s]\n", gfile);
- AddLine(fileList, gfile);
- }
- }
- (void) SIGNAL(SIGPIPE, SIG_IGN);
- if (fp != NULL)
- (void) PClose((FILE *) fp);
- (void) SIGNAL(SIGPIPE, sp);
- (void) SIGNAL(SIGINT, si);
- } else {
- /* Or, if there were no globbing characters in 'pattern', then the
- * pattern is really just a single pathname.
- */
- AddLine(fileList, pattern2);
- }
- } /* LocalGlob */
-
-
-
- /* We need to use this because using NLST gives us more stuff than
- * we want back sometimes. For example, say we have:
- *
- * /a (directory)
- * /a/b (directory)
- * /a/b/b1
- * /a/b/b2
- * /a/b/b3
- * /a/c (directory)
- * /a/c/c1
- * /a/c/c2
- * /a/c/c3
- * /a/file
- *
- * If you did an "echo /a/<star>" in a normal unix shell, you would expect
- * to get back /a/b /a/c /a/file. But NLST gives back:
- *
- * /a/b/b1
- * /a/b/b2
- * /a/b/b3
- * /a/c/c1
- * /a/c/c2
- * /a/c/c3
- * /a/file
- *
- * So we use the following routine to convert into the format I expect.
- */
-
- static
- void RemoteGlobCollapse(char *pattern, LineListPtr fileList)
- {
- LinePtr lp, nextLine;
- string patPrefix;
- string cur, prev;
- char *endp, *cp, *dp;
- char *pp;
- int wasGlobChar;
- size_t plen;
-
- /* Copy all characters before the first glob-char. */
- dp = patPrefix;
- endp = dp + sizeof(patPrefix) - 1;
- wasGlobChar = 0;
- for (cp = pattern; dp < endp; ) {
- for (pp=kGlobChars; *pp != '\0'; pp++) {
- if (*pp == *cp) {
- wasGlobChar = 1;
- break;
- }
- }
- if (wasGlobChar)
- break;
- *dp++ = *cp++;
- }
- *dp = '\0';
- plen = (size_t) (dp - patPrefix);
-
- *prev = '\0';
- for (lp=fileList->first; lp != NULL; lp = nextLine) {
- nextLine = lp->next;
- if (strncmp(lp->line, patPrefix, plen) == 0) {
- STRNCPY(cur, lp->line + plen);
- cp = strchr(cur, '/');
- if (cp != NULL)
- *cp = '\0';
- if (STREQ(cur, prev)) {
- nextLine = RemoveLine(fileList, lp);
- } else {
- STRNCPY(prev, cur);
- /* We are playing with a dynamically
- * allocated string, but since the
- * following expression is guaranteed
- * to be the same or shorter, we won't
- * overwrite the bounds.
- */
- sprintf(lp->line, "%s%s", patPrefix, cur);
- }
- }
- }
- } /* RemoteGlobCollapse */
-
-
-
-
- void RemoteGlob(LineListPtr fileList, char *pattern, char *lsFlags)
- {
- char *cp;
- LinePtr lp;
-
- /* Note that we do attempt to use glob characters even if the remote
- * host isn't UNIX. Most non-UNIX remote FTP servers look for UNIX
- * style wildcards.
- */
- if (GLOBCHARSINSTR(pattern)) {
- /* Use NLST, which lists files one per line. */
- ListToMemory(fileList, "NLST", lsFlags, pattern);
- if ((fileList->first != NULL) && (fileList->first == fileList->last)) {
- /* If we have only one item in the list, see if it really was
- * an error message we would recognize.
- */
- cp = strchr(fileList->first->line, ':');
- if ((cp != NULL) && STREQ(cp, ": No such file or directory")) {
- RemoveLine(fileList, fileList->first);
- }
- }
- RemoteGlobCollapse(pattern, fileList);
- if (gTrace == kTracingOn) {
- for (lp=fileList->first; lp != NULL; lp = lp->next)
- TraceMsg("Rglob [%s]\n", lp->line);
- }
- } else {
- /* Or, if there were no globbing characters in 'pattern', then the
- * pattern is really just a filename. So for this case the
- * file list is really just a single file.
- */
- fileList->first = fileList->last = NULL;
- AddLine(fileList, pattern);
- }
- } /* RemoteGlob */
-