home *** CD-ROM | disk | FTP | other *** search
- /*---------------------------------------------------------------------------*
- *
- * wish - windowing user friendly shell
- * --------------------------------------
- *
- * (c) Copyright Hellmuth Michaelis 1989 - 1993
- *
- * Eggerstedtstr. 28
- * 22765 Hamburg
- * Germany
- *
- * Tel: +49 / 40 / 384298 (private)
- * Tel: +49 / 40 / 55903-170 (at work)
- * e-mail: hm@hcshh.hcs.de
- *
- * All rights are reserved except as explicitly granted
- * by written permission of the author.
- *
- * See the file COPYING, distributed with wish, for
- * restriction and warranty information
- *
- * The wildcard matching routine was written by Rich $alz,
- * <rsalz@bbn.com> and was released to comp.sources.misc, Volume 17.
- *
- *---------------------------------------------------------------------------*
- *
- * last edit-date: [Mon Aug 30 12:30:23 1993]
- *
- * -hm wildcarding cd
- * -hm resolve "~/"
- *
- *----------------------------------------------------------------------------*/
-
- #include "wish.h" /* local includes */
-
- static char *cd1(char *string);
- static char *wilddir(char *path, char *wildname);
-
- /*---------------------------------------------------------------------------*
- * change directory, string may contain wildcards
- *----------------------------------------------------------------------------*/
- int cd(char *string)
- {
- char *p;
-
- if(chdir(string) == 0) /* try out unresolved first */
- return(0);
-
- if((p = cd1(string)) == NULL) /* try to resolve */
- return(-1);
-
- return(chdir(p)); /* try to change dir */
- }
-
- /*---------------------------------------------------------------------------*
- * return resolved path or NULL if failed
- *----------------------------------------------------------------------------*/
- static char *cd1(char *string)
- {
- static char left[MAXPATHLEN+1]; /* contains no wildcards */
- char wname[MAXPATHLEN+1]; /* current wildname to try */
-
- register char *sp; /* ptr into string */
- register char *lp; /* ptr into left */
- register char *wp; /* ptr into wname */
- register char *gp; /* gp ptr */
-
- left[0] = wname[0] = '\0';
-
- sp = string;
- lp = left;
-
- for(;;)
- {
- wp = wname;
-
- if(*sp == '\0')
- return(left);
-
- if((*sp == '~') && (*(sp+1) == '/'))
- {
- lp = left; /* $HOME -> left */
- gp = envhome; /* $HOME ptr */
- while(*gp) /* copy $HOME -> left */
- *lp++ = *gp++; /* new left */
- *lp++ = '/'; /* terminate left */
- sp += 2; /* advance sp */
- continue; /* next segment */
- }
-
- while(*sp && (*sp == '/')) /* check for '/'s */
- *lp++ = *sp++;
-
- while(*sp && (*sp != '/')) /* segment between '/'s -> wname */
- *wp++ = *sp++;
-
- *lp = *wp = '\0'; /* terminate strings */
-
- if(strpbrk(wname,WILDCHARS)==NULL) /* check for wildcards */
- {
- wp = wname; /* wname start */
- while(*wp) /* cat wname to left */
- *lp++ = *wp++;
- continue; /* next segment */
- }
-
- if((gp = wilddir(left, wname)) == NULL) /* resolve wildcards */
- return(NULL); /* not found */
-
- lp = left; /* resolved -> left */
- while(*gp)
- *lp++ = *gp++; /* new left */
- continue; /* next segment */
- }
- }
-
- /*---------------------------------------------------------------------------*
- * check if "wildname" matches any directory name in directory "path"
- * return concatenated "path" and matched name from dir "
- *----------------------------------------------------------------------------*/
- static char *wilddir(char *path, char *wildname)
- {
- register struct direct *dp; /* dir access */
- register DIR *dirp; /* dir access */
- struct stat fdbuffer; /* stat buffer */
- static char wtry[MAXPATHLEN+1]; /* try buffer */
- char rpath[MAXPATHLEN+1]; /* resulting path */
-
- strcpy(rpath, path); /* path -> result path */
- strcat(rpath, "."); /* for readdir */
-
- if((dirp = opendir(rpath)) == NULL)
- return(NULL); /* cannot open directory */
-
- for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
- {
- if(wildmat(dp->d_name, wildname) == TRUE) /* hit ? */
- {
- strcpy(wtry, path); /* pathname */
- strcat(wtry, dp->d_name); /* matchname */
- if(stat(wtry, &fdbuffer) < 0)
- continue; /* not accessible */
- if(!(S_ISDIR(fdbuffer.st_mode)))/* directory ? */
- continue; /* no */
- closedir(dirp); /* close */
- return(wtry); /* return result */
- }
- }
- closedir(dirp); /* close */
- return(NULL); /* failed */
- }
-
-
- /* $Revision: 1.4 $
- **
- ** Do shell-style pattern matching for ?, \, [], and * characters.
- ** Might not be robust in face of malformed patterns; e.g., "foo[a-"
- ** could cause a segmentation violation. It is 8bit clean.
- **
- ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
- ** Rich $alz is now <rsalz@bbn.com>.
- ** April, 1991: Replaced mutually-recursive calls with in-line code
- ** for the star character.
- **
- ** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
- ** This can greatly speed up failing wildcard patterns. For example:
- ** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
- ** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
- ** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
- ** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without
- ** the ABORT, then it takes 22310 calls to fail. Ugh. The following
- ** explanation is from Lars:
- ** The precondition that must be fulfilled is that DoMatch will consume
- ** at least one character in text. This is true if *p is neither '*' nor
- ** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic
- ** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With
- ** FALSE, each star-loop has to run to the end of the text; with ABORT
- ** only the last one does.
- **
- ** Once the control of one instance of DoMatch enters the star-loop, that
- ** instance will return either TRUE or ABORT, and any calling instance
- ** will therefore return immediately after (without calling recursively
- ** again). In effect, only one star-loop is ever active. It would be
- ** possible to modify the code to maintain this context explicitly,
- ** eliminating all recursive calls at the cost of some complication and
- ** loss of clarity (and the ABORT stuff seems to be unclear enough by
- ** itself). I think it would be unwise to try to get this into a
- ** released version unless you have a good test data base to try it out
- ** on.
- */
-
- /* What character marks an inverted character class? */
- #define NEGATE_CLASS '!' /* -hm , was '^' */
- /* Is "*" a common pattern? */
- #define OPTIMIZE_JUST_STAR
- /* Do tar(1) matching rules, which ignore a trailing slash? */
- #undef MATCH_TAR_PATTERN
-
-
- /*
- ** Match text and p, return TRUE, FALSE, or ABORT.
- */
- static int DoMatch(register char *text, register char *p)
- {
- register int dolast; /* -hm, was "last" */
- register int matched;
- register int reverse;
-
- for ( ; *p; text++, p++) {
- if (*text == '\0' && *p != '*')
- return ABORT;
- switch (*p) {
- case '\\':
- /* Literal match with following character. */
- p++;
- /* FALLTHROUGH */
- default:
- if (*text != *p)
- return FALSE;
- continue;
- case '?':
- /* Match anything. */
- continue;
- case '*':
- while (*++p == '*')
- /* Consecutive stars act just like one. */
- continue;
- if (*p == '\0')
- /* Trailing star matches everything. */
- return TRUE;
- while (*text)
- if ((matched = DoMatch(text++, p)) != FALSE)
- return matched;
- return ABORT;
- case '[':
- reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
- if (reverse)
- /* Inverted character class. */
- p++;
- for (dolast = 0400, matched = FALSE; *++p && *p != ']'; dolast = *p)
- /* This next line requires a good C compiler. */
- if (*p == '-' ? *text <= *++p && *text >= dolast : *text == *p)
- matched = TRUE;
- if (matched == reverse)
- return FALSE;
- continue;
- }
- }
-
- #ifdef MATCH_TAR_PATTERN
- if (*text == '/')
- return TRUE;
- #endif /* MATCH_TAR_ATTERN */
- return *text == '\0';
- }
-
-
- /*
- ** User-level routine. Returns TRUE or FALSE.
- */
- int wildmat(char *text, char *p)
- {
- #ifdef OPTIMIZE_JUST_STAR
- if (p[0] == '*' && p[1] == '\0')
- return TRUE;
- #endif /* OPTIMIZE_JUST_STAR */
- return DoMatch(text, p) == TRUE;
- }
-
-
-
- #ifdef TEST
- #include <stdio.h>
-
- /* Yes, we use gets not fgets. Sue me. */
- extern char *gets();
-
-
- main()
- {
- char p[80];
- char text[80];
-
- printf("Wildmat tester. Enter pattern, then strings to test.\n");
- printf("A blank line gets prompts for a new pattern; a blank pattern\n");
- printf("exits the program.\n");
-
- for ( ; ; ) {
- printf("\nEnter pattern: ");
- (void)fflush(stdout);
- if (gets(p) == NULL || p[0] == '\0')
- break;
- for ( ; ; ) {
- printf("Enter text: ");
- (void)fflush(stdout);
- if (gets(text) == NULL)
- exit(0);
- if (text[0] == '\0')
- /* Blank line; go back and get a new pattern. */
- break;
- printf(" %s\n", wildmat(text, p) ? "YES" : "NO");
- }
- }
-
- exit(0);
- /* NOTREACHED */
- }
- #endif /* TEST */
-
- /*---------------------------------- EOF -------------------------------------*/
-