home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / tcp / Networking / TCP / Server / wu-ftpd / src / glob.c < prev    next >
C/C++ Source or Header  |  1994-08-05  |  12KB  |  715 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)glob.c    5.9 (Berkeley) 2/25/91";
  36. #endif /* not lint */
  37.  
  38. /*
  39.  * C-shell glob for random programs.
  40.  */
  41.  
  42. #include "config.h"
  43.  
  44. #include <sys/param.h>
  45. #include <sys/stat.h>
  46.  
  47. #ifdef HAVE_DIRENT
  48. #include <dirent.h>
  49. #else
  50. #include <sys/dir.h>
  51. #endif
  52.  
  53. #include <pwd.h>
  54. #include <errno.h>
  55. #include <stdio.h>
  56. #include <string.h>
  57.  
  58. #ifdef AMIGA
  59. #include <proto/usergroup.h>
  60. #endif
  61.  
  62. #define    QUOTE 0200
  63. #define    TRIM 0177
  64. #define    eq(a,b)        (strcmp(a, b)==0)
  65. #define    GAVSIZ        (NCARGS/6)
  66. #define    isdir(d)    ((d.st_mode & S_IFMT) == S_IFDIR)
  67.  
  68. static    char **gargv;        /* Pointer to the (stack) arglist */
  69. static    int gargc;        /* Number args in gargv */
  70. static    int gnleft;
  71. static    short gflag;
  72. static    int tglob();
  73. char    **ftpglob();
  74. char    *globerr;
  75. char    *home;
  76. extern    int errno;
  77. char    *strspl();
  78. static    char *strend();
  79. char    **copyblk();
  80.  
  81. static void acollect(), addpath(), collect(), expand(), Gcat();
  82. static void ginit(), matchdir(), rscan(), sort();
  83. static int amatch(), execbrc(), match();
  84.  
  85. static    int globcnt;
  86.  
  87. char    *globchars = "`{[*?";
  88.  
  89. static    char *gpath, *gpathp, *lastgpathp;
  90. static    int globbed;
  91. static    char *entp;
  92. static    char **sortbas;
  93.  
  94. char **
  95. ftpglob(v)
  96.     register char *v;
  97. {
  98.     char agpath[BUFSIZ];
  99.     char *agargv[GAVSIZ];
  100.     char *vv[2];
  101.     vv[0] = v;
  102.     vv[1] = 0;
  103.     gflag = 0;
  104.     rscan(vv, tglob);
  105.     if (gflag == 0) {
  106.         vv[0] = strspl(v, "");
  107.         return (copyblk(vv));
  108.     }
  109.  
  110.     globerr = 0;
  111.     gpath = agpath; gpathp = gpath; *gpathp = 0;
  112.     lastgpathp = &gpath[sizeof agpath - 2];
  113.     ginit(agargv); globcnt = 0;
  114.     collect(v);
  115.     if (globcnt == 0 && (gflag&1)) {
  116.         blkfree(gargv), gargv = 0;
  117.         return (0);
  118.     } else
  119.         return (gargv = copyblk(gargv));
  120. }
  121.  
  122. static void
  123. ginit(agargv)
  124.     char **agargv;
  125. {
  126.  
  127.     agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
  128.     gnleft = NCARGS - 4;
  129. }
  130.  
  131. static void
  132. collect(as)
  133.     register char *as;
  134. {
  135.     if (eq(as, "{") || eq(as, "{}")) {
  136.         Gcat(as, "");
  137.         sort();
  138.     } else
  139.         acollect(as);
  140. }
  141.  
  142. static void
  143. acollect(as)
  144.     register char *as;
  145. {
  146.     register int ogargc = gargc;
  147.  
  148.     gpathp = gpath; *gpathp = 0; globbed = 0;
  149.     expand(as);
  150.     if (gargc != ogargc)
  151.         sort();
  152. }
  153.  
  154. static void
  155. sort()
  156. {
  157.     register char **p1, **p2, *c;
  158.     char **Gvp = &gargv[gargc];
  159.  
  160.     p1 = sortbas;
  161.     while (p1 < Gvp-1) {
  162.         p2 = p1;
  163.         while (++p2 < Gvp)
  164.             if (strcmp(*p1, *p2) > 0)
  165.                 c = *p1, *p1 = *p2, *p2 = c;
  166.         p1++;
  167.     }
  168.     sortbas = Gvp;
  169. }
  170.  
  171. static void
  172. expand(as)
  173.     char *as;
  174. {
  175.     register char *cs;
  176.     register char *sgpathp, *oldcs;
  177.     struct stat stb;
  178.  
  179.     sgpathp = gpathp;
  180.     cs = as;
  181.     if (*cs == '~' && gpathp == gpath) {
  182.         addpath('~');
  183.         for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
  184.             addpath(*cs++);
  185.         if (!*cs || *cs == '/') {
  186.             if (gpathp != gpath + 1) {
  187.                 *gpathp = 0;
  188.                 if (gethdir(gpath + 1))
  189.                     globerr = "Unknown user name after ~";
  190.                 (void) strcpy(gpath, gpath + 1);
  191.             } else
  192.                 (void) strcpy(gpath, home);
  193.             gpathp = strend(gpath);
  194.         }
  195.     }
  196.     while (!any(*cs, globchars)) {
  197.         if (*cs == 0) {
  198.             if (!globbed)
  199.                 Gcat(gpath, "");
  200.             else if (stat(gpath, &stb) >= 0) {
  201.                 Gcat(gpath, "");
  202.                 globcnt++;
  203.             }
  204.             goto endit;
  205.         }
  206.         addpath(*cs++);
  207.     }
  208.     oldcs = cs;
  209.     while (cs > as && *cs != '/')
  210.         cs--, gpathp--;
  211.     if (*cs == '/')
  212.         cs++, gpathp++;
  213.     *gpathp = 0;
  214.     if (*oldcs == '{') {
  215.         (void) execbrc(cs, ((char *)0));
  216.         return;
  217.     }
  218.     matchdir(cs);
  219. endit:
  220.     gpathp = sgpathp;
  221.     *gpathp = 0;
  222. }
  223.  
  224. static void
  225. matchdir(pattern)
  226.     char *pattern;
  227. {
  228. #ifndef AMIGA
  229.     struct stat stb;
  230. #endif
  231.  
  232. #ifdef HAVE_DIRENT
  233.     register struct dirent *dp;
  234. #else
  235.     register struct direct *dp;
  236. #endif
  237.  
  238.     DIR *dirp;
  239.  
  240. #ifdef AMIGA
  241.     dirp = opendir(gpath);
  242. #else
  243.     dirp = opendir(*gpath == '\0' ? "." : gpath);
  244. #endif
  245.     if (dirp == NULL) {
  246.         if (globbed)
  247.             return;
  248.         goto patherr2;
  249.     }
  250. #ifndef AMIGA
  251.     if (fstat(dirp->dd_fd, &stb) < 0)
  252.         goto patherr1;
  253.     if (!isdir(stb)) {
  254.         errno = ENOTDIR;
  255.         goto patherr1;
  256.     }
  257. #else
  258.         /* fstat() is broken for directories under SAS/C,
  259.          * so we use the SAS specific getfa() call
  260.          */
  261.         if (getfa(gpath) != 1) {
  262.                 errno = ENOTDIR;
  263.                 goto patherr1;
  264.         }
  265. #endif
  266.     while ((dp = readdir(dirp)) != NULL) {
  267.         if (dp->d_ino == 0)
  268.             continue;
  269.         if (match(dp->d_name, pattern)) {
  270.             Gcat(gpath, dp->d_name);
  271.             globcnt++;
  272.         }
  273.     }
  274.     closedir(dirp);
  275.     return;
  276.  
  277. patherr1:
  278.     closedir(dirp);
  279. patherr2:
  280.     globerr = "Bad directory components";
  281. }
  282.  
  283. static int
  284. execbrc(p, s)
  285.     char *p, *s;
  286. {
  287.     char restbuf[BUFSIZ + 2];
  288.     register char *pe, *pm, *pl;
  289.     int brclev = 0;
  290.     char *lm, savec, *sgpathp;
  291.  
  292.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  293.         continue;
  294.     for (pe = ++p; *pe; pe++)
  295.     switch (*pe) {
  296.  
  297.     case '{':
  298.         brclev++;
  299.         continue;
  300.  
  301.     case '}':
  302.         if (brclev == 0)
  303.             goto pend;
  304.         brclev--;
  305.         continue;
  306.  
  307.     case '[':
  308.         for (pe++; *pe && *pe != ']'; pe++)
  309.             continue;
  310.         continue;
  311.     }
  312. pend:
  313.     brclev = 0;
  314.     for (pl = pm = p; pm <= pe; pm++)
  315.     switch (*pm & (QUOTE|TRIM)) {
  316.  
  317.     case '{':
  318.         brclev++;
  319.         continue;
  320.  
  321.     case '}':
  322.         if (brclev) {
  323.             brclev--;
  324.             continue;
  325.         }
  326.         goto doit;
  327.  
  328.     case ','|QUOTE:
  329.     case ',':
  330.         if (brclev)
  331.             continue;
  332. doit:
  333.         savec = *pm;
  334.         *pm = 0;
  335.         (void) strcpy(lm, pl);
  336.         (void) strcat(restbuf, pe + 1);
  337.         *pm = savec;
  338.         if (s == 0) {
  339.             sgpathp = gpathp;
  340.             expand(restbuf);
  341.             gpathp = sgpathp;
  342.             *gpathp = 0;
  343.         } else if (amatch(s, restbuf))
  344.             return (1);
  345.         sort();
  346.         pl = pm + 1;
  347.         if (brclev)
  348.             return (0);
  349.         continue;
  350.  
  351.     case '[':
  352.         for (pm++; *pm && *pm != ']'; pm++)
  353.             continue;
  354.         if (!*pm)
  355.             pm--;
  356.         continue;
  357.     }
  358.     if (brclev)
  359.         goto doit;
  360.     return (0);
  361. }
  362.  
  363. static int
  364. match(s, p)
  365.     char *s, *p;
  366. {
  367.     register int c;
  368.     register char *sentp;
  369.     char sglobbed = globbed;
  370.  
  371.     if (*s == '.' && *p != '.')
  372.         return (0);
  373.     sentp = entp;
  374.     entp = s;
  375.     c = amatch(s, p);
  376.     entp = sentp;
  377.     globbed = sglobbed;
  378.     return (c);
  379. }
  380.  
  381. static int
  382. amatch(s, p)
  383.     register char *s, *p;
  384. {
  385.     register int scc;
  386.     int ok, lc;
  387.     char *sgpathp;
  388.     struct stat stb;
  389.     int c, cc;
  390.  
  391.     globbed = 1;
  392.     for (;;) {
  393.         scc = *s++ & TRIM;
  394.         switch (c = *p++) {
  395.  
  396.         case '{':
  397.             return (execbrc(p - 1, s - 1));
  398.  
  399.         case '[':
  400.             ok = 0;
  401.             lc = 077777;
  402.             while (cc = *p++) {
  403.                 if (cc == ']') {
  404.                     if (ok)
  405.                         break;
  406.                     return (0);
  407.                 }
  408.                 if (cc == '-') {
  409.                     if (lc <= scc && scc <= *p++)
  410.                         ok++;
  411.                 } else
  412.                     if (scc == (lc = cc))
  413.                         ok++;
  414.             }
  415.             if (cc == 0)
  416.                 if (ok)
  417.                     p--;
  418.                 else
  419.                     return 0;
  420.             continue;
  421.  
  422.         case '*':
  423.             if (!*p)
  424.                 return (1);
  425.             if (*p == '/') {
  426.                 p++;
  427.                 goto slash;
  428.             }
  429.             s--;
  430.             do {
  431.                 if (amatch(s, p))
  432.                     return (1);
  433.             } while (*s++);
  434.             return (0);
  435.  
  436.         case 0:
  437.             return (scc == 0);
  438.  
  439.         default:
  440.             if (c != scc)
  441.                 return (0);
  442.             continue;
  443.  
  444.         case '?':
  445.             if (scc == 0)
  446.                 return (0);
  447.             continue;
  448.  
  449.         case '/':
  450.             if (scc)
  451.                 return (0);
  452. slash:
  453.             s = entp;
  454.             sgpathp = gpathp;
  455.             while (*s)
  456.                 addpath(*s++);
  457.             addpath('/');
  458.             if (stat(gpath, &stb) == 0 && isdir(stb))
  459.                 if (*p == 0) {
  460.                     Gcat(gpath, "");
  461.                     globcnt++;
  462.                 } else
  463.                     expand(p);
  464.             gpathp = sgpathp;
  465.             *gpathp = 0;
  466.             return (0);
  467.         }
  468.     }
  469. }
  470.  
  471. static
  472. Gmatch(s, p)
  473.     register char *s, *p;
  474. {
  475.     register int scc;
  476.     int ok, lc;
  477.     int c, cc;
  478.  
  479.     for (;;) {
  480.         scc = *s++ & TRIM;
  481.         switch (c = *p++) {
  482.  
  483.         case '[':
  484.             ok = 0;
  485.             lc = 077777;
  486.             while (cc = *p++) {
  487.                 if (cc == ']') {
  488.                     if (ok)
  489.                         break;
  490.                     return (0);
  491.                 }
  492.                 if (cc == '-') {
  493.                     if (lc <= scc && scc <= *p++)
  494.                         ok++;
  495.                 } else
  496.                     if (scc == (lc = cc))
  497.                         ok++;
  498.             }
  499.             if (cc == 0)
  500.                 if (ok)
  501.                     p--;
  502.                 else
  503.                     return 0;
  504.             continue;
  505.  
  506.         case '*':
  507.             if (!*p)
  508.                 return (1);
  509.             for (s--; *s; s++)
  510.                 if (Gmatch(s, p))
  511.                     return (1);
  512.             return (0);
  513.  
  514.         case 0:
  515.             return (scc == 0);
  516.  
  517.         default:
  518.             if ((c & TRIM) != scc)
  519.                 return (0);
  520.             continue;
  521.  
  522.         case '?':
  523.             if (scc == 0)
  524.                 return (0);
  525.             continue;
  526.  
  527.         }
  528.     }
  529. }
  530.  
  531. static void
  532. Gcat(s1, s2)
  533.     register char *s1, *s2;
  534. {
  535.     register int len = strlen(s1) + strlen(s2) + 1;
  536.  
  537.     if (len >= gnleft || gargc >= GAVSIZ - 1)
  538.         globerr = "Arguments too long";
  539.     else {
  540.         gargc++;
  541.         gnleft -= len;
  542.         gargv[gargc] = 0;
  543.         gargv[gargc - 1] = strspl(s1, s2);
  544.     }
  545. }
  546.  
  547. static void
  548. addpath(c)
  549.     char c;
  550. {
  551.  
  552.     if (gpathp >= lastgpathp)
  553.         globerr = "Pathname too long";
  554.     else {
  555.         *gpathp++ = c;
  556.         *gpathp = 0;
  557.     }
  558. }
  559.  
  560. static void
  561. rscan(t, f)
  562.     register char **t;
  563.     int (*f)();
  564. {
  565.     register char *p, c;
  566.  
  567.     while (p = *t++) {
  568.         if (f == tglob)
  569.             if (*p == '~')
  570.                 gflag |= 2;
  571.             else if (eq(p, "{") || eq(p, "{}"))
  572.                 continue;
  573.         while (c = *p++)
  574.             (*f)(c);
  575.     }
  576. }
  577. /*
  578. static
  579. scan(t, f)
  580.     register char **t;
  581.     int (*f)();
  582. {
  583.     register char *p, c;
  584.  
  585.     while (p = *t++)
  586.         while (c = *p)
  587.             *p++ = (*f)(c);
  588. } */
  589.  
  590. static
  591. tglob(c)
  592.     register char c;
  593. {
  594.  
  595.     if (any(c, globchars))
  596.         gflag |= c == '{' ? 2 : 1;
  597.     return (c);
  598. }
  599. /*
  600. static
  601. trim(c)
  602.     char c;
  603. {
  604.  
  605.     return (c & TRIM);
  606. } */
  607.  
  608.  
  609. letter(c)
  610.     register char c;
  611. {
  612.  
  613.     return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
  614. }
  615.  
  616. digit(c)
  617.     register char c;
  618. {
  619.  
  620.     return (c >= '0' && c <= '9');
  621. }
  622.  
  623. any(c, s)
  624.     register int c;
  625.     register char *s;
  626. {
  627.  
  628.     while (*s)
  629.         if (*s++ == c)
  630.             return(1);
  631.     return(0);
  632. }
  633. blklen(av)
  634.     register char **av;
  635. {
  636.     register int i = 0;
  637.  
  638.     while (*av++)
  639.         i++;
  640.     return (i);
  641. }
  642.  
  643. char **
  644. blkcpy(oav, bv)
  645.     char **oav;
  646.     register char **bv;
  647. {
  648.     register char **av = oav;
  649.  
  650.     while (*av++ = *bv++)
  651.         continue;
  652.     return (oav);
  653. }
  654.  
  655. blkfree(av0)
  656.     char **av0;
  657. {
  658.     register char **av = av0;
  659.  
  660.     while (*av)
  661.         free(*av++);
  662. }
  663.  
  664. char *
  665. strspl(cp, dp)
  666.     register char *cp, *dp;
  667. {
  668.     register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
  669.  
  670.     if (ep == (char *)0)
  671.         fatal("Out of memory");
  672.     (void) strcpy(ep, cp);
  673.     (void) strcat(ep, dp);
  674.     return (ep);
  675. }
  676.  
  677. char **
  678. copyblk(v)
  679.     register char **v;
  680. {
  681.     register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
  682.                         sizeof(char **)));
  683.     if (nv == (char **)0)
  684.         fatal("Out of memory");
  685.  
  686.     return (blkcpy(nv, v));
  687. }
  688.  
  689. static
  690. char *
  691. strend(cp)
  692.     register char *cp;
  693. {
  694.  
  695.     while (*cp)
  696.         cp++;
  697.     return (cp);
  698. }
  699. /*
  700.  * Extract a home directory from the password file
  701.  * The argument points to a buffer where the name of the
  702.  * user whose home directory is sought is currently.
  703.  * We write the home directory of the user back there.
  704.  */
  705. gethdir(home)
  706.     char *home;
  707. {
  708.     register struct passwd *pp = getpwnam(home);
  709.  
  710.     if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
  711.         return (1);
  712.     (void) strcpy(home, pp->pw_dir);
  713.     return (0);
  714. }
  715.