home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume39 / cwish / part02 / chdir.c next >
Encoding:
C/C++ Source or Header  |  1993-09-22  |  9.0 KB  |  311 lines

  1. /*---------------------------------------------------------------------------*
  2.  *
  3.  *                  wish - windowing user friendly shell
  4.  *                 --------------------------------------
  5.  *
  6.  *              (c) Copyright Hellmuth Michaelis 1989 - 1993
  7.  *
  8.  *                  Eggerstedtstr. 28
  9.  *                  22765 Hamburg
  10.  *                  Germany
  11.  *
  12.  *                  Tel:    +49 / 40 / 384298    (private)
  13.  *                  Tel:    +49 / 40 / 55903-170 (at work)
  14.  *                  e-mail: hm@hcshh.hcs.de
  15.  *
  16.  *           All rights are reserved except as explicitly granted
  17.  *                  by written permission of the author.
  18.  *
  19.  *             See the file COPYING, distributed with wish, for
  20.  *                  restriction and warranty information
  21.  *
  22.  *        The wildcard matching routine was written by Rich $alz,
  23.  *     <rsalz@bbn.com> and was released to comp.sources.misc, Volume 17.
  24.  *
  25.  *---------------------------------------------------------------------------*
  26.  *
  27.  *    last edit-date: [Mon Aug 30 12:30:23 1993]
  28.  *
  29.  *    -hm    wildcarding cd
  30.  *    -hm    resolve "~/"
  31.  *
  32.  *----------------------------------------------------------------------------*/
  33.  
  34. #include "wish.h"        /* local includes */
  35.  
  36. static char *cd1(char *string);
  37. static char *wilddir(char *path, char *wildname);
  38.  
  39. /*---------------------------------------------------------------------------*
  40.  *    change directory, string may contain wildcards
  41.  *----------------------------------------------------------------------------*/
  42. int cd(char *string)
  43. {
  44.     char *p;
  45.     
  46.     if(chdir(string) == 0)        /* try out unresolved first */
  47.         return(0);
  48.  
  49.     if((p = cd1(string)) == NULL)    /* try to resolve */
  50.         return(-1);
  51.  
  52.     return(chdir(p));        /* try to change dir */
  53. }
  54.  
  55. /*---------------------------------------------------------------------------*
  56.  *    return resolved path or NULL if failed 
  57.  *----------------------------------------------------------------------------*/
  58. static char *cd1(char *string)
  59. {
  60.     static char left[MAXPATHLEN+1];        /* contains no wildcards */
  61.     char wname[MAXPATHLEN+1];        /* current wildname to try */
  62.  
  63.     register char *sp;            /* ptr into string */
  64.     register char *lp;            /* ptr into left */    
  65.     register char *wp;            /* ptr into wname */
  66.     register char *gp;            /* gp ptr */
  67.  
  68.     left[0] = wname[0] = '\0';
  69.     
  70.     sp = string;
  71.     lp = left;
  72.     
  73.     for(;;)
  74.     {
  75.         wp = wname;
  76.  
  77.         if(*sp == '\0')
  78.             return(left);
  79.  
  80.         if((*sp == '~') && (*(sp+1) == '/'))
  81.         {
  82.             lp = left;        /* $HOME -> left */
  83.             gp = envhome;        /* $HOME ptr */
  84.             while(*gp)        /* copy $HOME -> left */
  85.                 *lp++ = *gp++;    /* new left */
  86.             *lp++ = '/';        /* terminate left */
  87.             sp += 2;        /* advance sp */
  88.             continue;        /* next segment */
  89.         }
  90.             
  91.         while(*sp && (*sp == '/'))    /* check for '/'s */
  92.             *lp++ = *sp++;
  93.  
  94.         while(*sp && (*sp != '/'))    /* segment between '/'s -> wname */
  95.             *wp++ = *sp++;
  96.         
  97.         *lp = *wp = '\0';        /* terminate strings */
  98.  
  99.         if(strpbrk(wname,WILDCHARS)==NULL)    /* check for wildcards */
  100.         {
  101.             wp = wname;            /* wname start */
  102.             while(*wp)            /* cat wname to left */
  103.                 *lp++ = *wp++;
  104.             continue;            /* next segment */
  105.         }
  106.  
  107.         if((gp = wilddir(left, wname)) == NULL)    /* resolve wildcards */
  108.             return(NULL);            /* not found */
  109.  
  110.         lp = left;                /* resolved -> left */
  111.         while(*gp)
  112.             *lp++ = *gp++;            /* new left */
  113.         continue;                /* next segment */
  114.     }
  115. }
  116.             
  117. /*---------------------------------------------------------------------------*
  118.  *    check if "wildname" matches any directory name in directory "path"
  119.  *    return concatenated "path" and matched name from dir "
  120.  *----------------------------------------------------------------------------*/
  121. static char *wilddir(char *path, char *wildname)
  122. {
  123.     register struct direct *dp;        /* dir access */
  124.     register DIR *dirp;            /* dir access */
  125.     struct stat fdbuffer;            /* stat buffer */
  126.     static char wtry[MAXPATHLEN+1];        /* try buffer */
  127.     char rpath[MAXPATHLEN+1];        /* resulting path */
  128.     
  129.     strcpy(rpath, path);            /* path -> result path */
  130.     strcat(rpath, ".");            /* for readdir */
  131.     
  132.     if((dirp = opendir(rpath)) == NULL)
  133.         return(NULL);            /* cannot open directory */
  134.  
  135.     for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
  136.     {
  137.         if(wildmat(dp->d_name, wildname) == TRUE) /* hit ? */
  138.         {
  139.             strcpy(wtry, path);        /* pathname */
  140.             strcat(wtry, dp->d_name);    /* matchname */
  141.             if(stat(wtry, &fdbuffer) < 0)
  142.                 continue;        /* not accessible */
  143.             if(!(S_ISDIR(fdbuffer.st_mode)))/* directory ? */
  144.                 continue;        /* no */
  145.             closedir(dirp);            /* close */
  146.             return(wtry);            /* return result */
  147.         }
  148.     }
  149.     closedir(dirp);        /* close */
  150.     return(NULL);        /* failed */
  151. }
  152.  
  153.  
  154. /*  $Revision: 1.4 $
  155. **
  156. **  Do shell-style pattern matching for ?, \, [], and * characters.
  157. **  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  158. **  could cause a segmentation violation.  It is 8bit clean.
  159. **
  160. **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  161. **  Rich $alz is now <rsalz@bbn.com>.
  162. **  April, 1991:  Replaced mutually-recursive calls with in-line code
  163. **  for the star character.
  164. **
  165. **  Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
  166. **  This can greatly speed up failing wildcard patterns.  For example:
  167. **    pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
  168. **    text 1:     -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
  169. **    text 2:     -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
  170. **  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
  171. **  the ABORT, then it takes 22310 calls to fail.  Ugh.  The following
  172. **  explanation is from Lars:
  173. **  The precondition that must be fulfilled is that DoMatch will consume
  174. **  at least one character in text.  This is true if *p is neither '*' nor
  175. **  '\0'.)  The last return has ABORT instead of FALSE to avoid quadratic
  176. **  behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx".  With
  177. **  FALSE, each star-loop has to run to the end of the text; with ABORT
  178. **  only the last one does.
  179. **
  180. **  Once the control of one instance of DoMatch enters the star-loop, that
  181. **  instance will return either TRUE or ABORT, and any calling instance
  182. **  will therefore return immediately after (without calling recursively
  183. **  again).  In effect, only one star-loop is ever active.  It would be
  184. **  possible to modify the code to maintain this context explicitly,
  185. **  eliminating all recursive calls at the cost of some complication and
  186. **  loss of clarity (and the ABORT stuff seems to be unclear enough by
  187. **  itself).  I think it would be unwise to try to get this into a
  188. **  released version unless you have a good test data base to try it out
  189. **  on.
  190. */
  191.  
  192.     /* What character marks an inverted character class? */
  193. #define NEGATE_CLASS        '!'    /* -hm , was '^' */
  194.     /* Is "*" a common pattern? */
  195. #define OPTIMIZE_JUST_STAR
  196.     /* Do tar(1) matching rules, which ignore a trailing slash? */
  197. #undef MATCH_TAR_PATTERN
  198.  
  199.  
  200. /*
  201. **  Match text and p, return TRUE, FALSE, or ABORT.
  202. */
  203. static int DoMatch(register char *text, register char *p)
  204. {
  205.     register int    dolast;        /* -hm, was "last" */
  206.     register int    matched;
  207.     register int    reverse;
  208.  
  209.     for ( ; *p; text++, p++) {
  210.     if (*text == '\0' && *p != '*')
  211.         return ABORT;
  212.     switch (*p) {
  213.     case '\\':
  214.         /* Literal match with following character. */
  215.         p++;
  216.         /* FALLTHROUGH */
  217.     default:
  218.         if (*text != *p)
  219.         return FALSE;
  220.         continue;
  221.     case '?':
  222.         /* Match anything. */
  223.         continue;
  224.     case '*':
  225.         while (*++p == '*')
  226.         /* Consecutive stars act just like one. */
  227.         continue;
  228.         if (*p == '\0')
  229.         /* Trailing star matches everything. */
  230.         return TRUE;
  231.         while (*text)
  232.         if ((matched = DoMatch(text++, p)) != FALSE)
  233.             return matched;
  234.         return ABORT;
  235.     case '[':
  236.         reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
  237.         if (reverse)
  238.         /* Inverted character class. */
  239.         p++;
  240.         for (dolast = 0400, matched = FALSE; *++p && *p != ']'; dolast = *p)
  241.         /* This next line requires a good C compiler. */
  242.         if (*p == '-' ? *text <= *++p && *text >= dolast : *text == *p)
  243.             matched = TRUE;
  244.         if (matched == reverse)
  245.         return FALSE;
  246.         continue;
  247.     }
  248.     }
  249.  
  250. #ifdef    MATCH_TAR_PATTERN
  251.     if (*text == '/')
  252.     return TRUE;
  253. #endif    /* MATCH_TAR_ATTERN */
  254.     return *text == '\0';
  255. }
  256.  
  257.  
  258. /*
  259. **  User-level routine.  Returns TRUE or FALSE.
  260. */
  261. int wildmat(char *text, char *p)
  262. {
  263. #ifdef    OPTIMIZE_JUST_STAR
  264.     if (p[0] == '*' && p[1] == '\0')
  265.     return TRUE;
  266. #endif    /* OPTIMIZE_JUST_STAR */
  267.     return DoMatch(text, p) == TRUE;
  268. }
  269.  
  270.  
  271.  
  272. #ifdef    TEST
  273. #include <stdio.h>
  274.  
  275. /* Yes, we use gets not fgets.  Sue me. */
  276. extern char    *gets();
  277.  
  278.  
  279. main()
  280. {
  281.     char     p[80];
  282.     char     text[80];
  283.  
  284.     printf("Wildmat tester.  Enter pattern, then strings to test.\n");
  285.     printf("A blank line gets prompts for a new pattern; a blank pattern\n");
  286.     printf("exits the program.\n");
  287.  
  288.     for ( ; ; ) {
  289.     printf("\nEnter pattern:  ");
  290.     (void)fflush(stdout);
  291.     if (gets(p) == NULL || p[0] == '\0')
  292.         break;
  293.     for ( ; ; ) {
  294.         printf("Enter text:  ");
  295.         (void)fflush(stdout);
  296.         if (gets(text) == NULL)
  297.         exit(0);
  298.         if (text[0] == '\0')
  299.         /* Blank line; go back and get a new pattern. */
  300.         break;
  301.         printf("      %s\n", wildmat(text, p) ? "YES" : "NO");
  302.     }
  303.     }
  304.  
  305.     exit(0);
  306.     /* NOTREACHED */
  307. }
  308. #endif    /* TEST */
  309.  
  310. /*---------------------------------- EOF -------------------------------------*/
  311.