home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / tcpip / wu-ftpd-.000 / wu-ftpd- / wu-ftpd-2.4 / src / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-01  |  11.3 KB  |  695 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. #define    QUOTE 0200
  59. #define    TRIM 0177
  60. #define    eq(a,b)        (strcmp(a, b)==0)
  61. #define    GAVSIZ        (NCARGS/6)
  62. #define    isdir(d)    ((d.st_mode & S_IFMT) == S_IFDIR)
  63.  
  64. static    char **gargv;        /* Pointer to the (stack) arglist */
  65. static    int gargc;        /* Number args in gargv */
  66. static    int gnleft;
  67. static    short gflag;
  68. static    int tglob();
  69. char    **ftpglob();
  70. char    *globerr;
  71. char    *home;
  72. extern    int errno;
  73. char    *strspl();
  74. static    char *strend();
  75. char    **copyblk();
  76.  
  77. static void acollect(), addpath(), collect(), expand(), Gcat();
  78. static void ginit(), matchdir(), rscan(), sort();
  79. static int amatch(), execbrc(), match();
  80.  
  81. static    int globcnt;
  82.  
  83. char    *globchars = "`{[*?";
  84.  
  85. static    char *gpath, *gpathp, *lastgpathp;
  86. static    int globbed;
  87. static    char *entp;
  88. static    char **sortbas;
  89.  
  90. char **
  91. ftpglob(v)
  92.     register char *v;
  93. {
  94.     char agpath[BUFSIZ];
  95.     char *agargv[GAVSIZ];
  96.     char *vv[2];
  97.     vv[0] = v;
  98.     vv[1] = 0;
  99.     gflag = 0;
  100.     rscan(vv, tglob);
  101.     if (gflag == 0) {
  102.         vv[0] = strspl(v, "");
  103.         return (copyblk(vv));
  104.     }
  105.  
  106.     globerr = 0;
  107.     gpath = agpath; gpathp = gpath; *gpathp = 0;
  108.     lastgpathp = &gpath[sizeof agpath - 2];
  109.     ginit(agargv); globcnt = 0;
  110.     collect(v);
  111.     if (globcnt == 0 && (gflag&1)) {
  112.         blkfree(gargv), gargv = 0;
  113.         return (0);
  114.     } else
  115.         return (gargv = copyblk(gargv));
  116. }
  117.  
  118. static void
  119. ginit(agargv)
  120.     char **agargv;
  121. {
  122.  
  123.     agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
  124.     gnleft = NCARGS - 4;
  125. }
  126.  
  127. static void
  128. collect(as)
  129.     register char *as;
  130. {
  131.     if (eq(as, "{") || eq(as, "{}")) {
  132.         Gcat(as, "");
  133.         sort();
  134.     } else
  135.         acollect(as);
  136. }
  137.  
  138. static void
  139. acollect(as)
  140.     register char *as;
  141. {
  142.     register int ogargc = gargc;
  143.  
  144.     gpathp = gpath; *gpathp = 0; globbed = 0;
  145.     expand(as);
  146.     if (gargc != ogargc)
  147.         sort();
  148. }
  149.  
  150. static void
  151. sort()
  152. {
  153.     register char **p1, **p2, *c;
  154.     char **Gvp = &gargv[gargc];
  155.  
  156.     p1 = sortbas;
  157.     while (p1 < Gvp-1) {
  158.         p2 = p1;
  159.         while (++p2 < Gvp)
  160.             if (strcmp(*p1, *p2) > 0)
  161.                 c = *p1, *p1 = *p2, *p2 = c;
  162.         p1++;
  163.     }
  164.     sortbas = Gvp;
  165. }
  166.  
  167. static void
  168. expand(as)
  169.     char *as;
  170. {
  171.     register char *cs;
  172.     register char *sgpathp, *oldcs;
  173.     struct stat stb;
  174.  
  175.     sgpathp = gpathp;
  176.     cs = as;
  177.     if (*cs == '~' && gpathp == gpath) {
  178.         addpath('~');
  179.         for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
  180.             addpath(*cs++);
  181.         if (!*cs || *cs == '/') {
  182.             if (gpathp != gpath + 1) {
  183.                 *gpathp = 0;
  184.                 if (gethdir(gpath + 1))
  185.                     globerr = "Unknown user name after ~";
  186.                 (void) strcpy(gpath, gpath + 1);
  187.             } else
  188.                 (void) strcpy(gpath, home);
  189.             gpathp = strend(gpath);
  190.         }
  191.     }
  192.     while (!any(*cs, globchars)) {
  193.         if (*cs == 0) {
  194.             if (!globbed)
  195.                 Gcat(gpath, "");
  196.             else if (stat(gpath, &stb) >= 0) {
  197.                 Gcat(gpath, "");
  198.                 globcnt++;
  199.             }
  200.             goto endit;
  201.         }
  202.         addpath(*cs++);
  203.     }
  204.     oldcs = cs;
  205.     while (cs > as && *cs != '/')
  206.         cs--, gpathp--;
  207.     if (*cs == '/')
  208.         cs++, gpathp++;
  209.     *gpathp = 0;
  210.     if (*oldcs == '{') {
  211.         (void) execbrc(cs, ((char *)0));
  212.         return;
  213.     }
  214.     matchdir(cs);
  215. endit:
  216.     gpathp = sgpathp;
  217.     *gpathp = 0;
  218. }
  219.  
  220. static void
  221. matchdir(pattern)
  222.     char *pattern;
  223. {
  224.     struct stat stb;
  225.  
  226. #ifdef HAVE_DIRENT
  227.     register struct dirent *dp;
  228. #else
  229.     register struct direct *dp;
  230. #endif
  231.  
  232.     DIR *dirp;
  233.  
  234.     dirp = opendir(*gpath == '\0' ? "." : gpath);
  235.     if (dirp == NULL) {
  236.         if (globbed)
  237.             return;
  238.         goto patherr2;
  239.     }
  240.     if (fstat(dirp->dd_fd, &stb) < 0)
  241.         goto patherr1;
  242.     if (!isdir(stb)) {
  243.         errno = ENOTDIR;
  244.         goto patherr1;
  245.     }
  246.     while ((dp = readdir(dirp)) != NULL) {
  247.         if (dp->d_ino == 0)
  248.             continue;
  249.         if (match(dp->d_name, pattern)) {
  250.             Gcat(gpath, dp->d_name);
  251.             globcnt++;
  252.         }
  253.     }
  254.     closedir(dirp);
  255.     return;
  256.  
  257. patherr1:
  258.     closedir(dirp);
  259. patherr2:
  260.     globerr = "Bad directory components";
  261. }
  262.  
  263. static int
  264. execbrc(p, s)
  265.     char *p, *s;
  266. {
  267.     char restbuf[BUFSIZ + 2];
  268.     register char *pe, *pm, *pl;
  269.     int brclev = 0;
  270.     char *lm, savec, *sgpathp;
  271.  
  272.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  273.         continue;
  274.     for (pe = ++p; *pe; pe++)
  275.     switch (*pe) {
  276.  
  277.     case '{':
  278.         brclev++;
  279.         continue;
  280.  
  281.     case '}':
  282.         if (brclev == 0)
  283.             goto pend;
  284.         brclev--;
  285.         continue;
  286.  
  287.     case '[':
  288.         for (pe++; *pe && *pe != ']'; pe++)
  289.             continue;
  290.         continue;
  291.     }
  292. pend:
  293.     brclev = 0;
  294.     for (pl = pm = p; pm <= pe; pm++)
  295.     switch (*pm & (QUOTE|TRIM)) {
  296.  
  297.     case '{':
  298.         brclev++;
  299.         continue;
  300.  
  301.     case '}':
  302.         if (brclev) {
  303.             brclev--;
  304.             continue;
  305.         }
  306.         goto doit;
  307.  
  308.     case ','|QUOTE:
  309.     case ',':
  310.         if (brclev)
  311.             continue;
  312. doit:
  313.         savec = *pm;
  314.         *pm = 0;
  315.         (void) strcpy(lm, pl);
  316.         (void) strcat(restbuf, pe + 1);
  317.         *pm = savec;
  318.         if (s == 0) {
  319.             sgpathp = gpathp;
  320.             expand(restbuf);
  321.             gpathp = sgpathp;
  322.             *gpathp = 0;
  323.         } else if (amatch(s, restbuf))
  324.             return (1);
  325.         sort();
  326.         pl = pm + 1;
  327.         if (brclev)
  328.             return (0);
  329.         continue;
  330.  
  331.     case '[':
  332.         for (pm++; *pm && *pm != ']'; pm++)
  333.             continue;
  334.         if (!*pm)
  335.             pm--;
  336.         continue;
  337.     }
  338.     if (brclev)
  339.         goto doit;
  340.     return (0);
  341. }
  342.  
  343. static int
  344. match(s, p)
  345.     char *s, *p;
  346. {
  347.     register int c;
  348.     register char *sentp;
  349.     char sglobbed = globbed;
  350.  
  351.     if (*s == '.' && *p != '.')
  352.         return (0);
  353.     sentp = entp;
  354.     entp = s;
  355.     c = amatch(s, p);
  356.     entp = sentp;
  357.     globbed = sglobbed;
  358.     return (c);
  359. }
  360.  
  361. static int
  362. amatch(s, p)
  363.     register char *s, *p;
  364. {
  365.     register int scc;
  366.     int ok, lc;
  367.     char *sgpathp;
  368.     struct stat stb;
  369.     int c, cc;
  370.  
  371.     globbed = 1;
  372.     for (;;) {
  373.         scc = *s++ & TRIM;
  374.         switch (c = *p++) {
  375.  
  376.         case '{':
  377.             return (execbrc(p - 1, s - 1));
  378.  
  379.         case '[':
  380.             ok = 0;
  381.             lc = 077777;
  382.             while (cc = *p++) {
  383.                 if (cc == ']') {
  384.                     if (ok)
  385.                         break;
  386.                     return (0);
  387.                 }
  388.                 if (cc == '-') {
  389.                     if (lc <= scc && scc <= *p++)
  390.                         ok++;
  391.                 } else
  392.                     if (scc == (lc = cc))
  393.                         ok++;
  394.             }
  395.             if (cc == 0)
  396.                 if (ok)
  397.                     p--;
  398.                 else
  399.                     return 0;
  400.             continue;
  401.  
  402.         case '*':
  403.             if (!*p)
  404.                 return (1);
  405.             if (*p == '/') {
  406.                 p++;
  407.                 goto slash;
  408.             }
  409.             s--;
  410.             do {
  411.                 if (amatch(s, p))
  412.                     return (1);
  413.             } while (*s++);
  414.             return (0);
  415.  
  416.         case 0:
  417.             return (scc == 0);
  418.  
  419.         default:
  420.             if (c != scc)
  421.                 return (0);
  422.             continue;
  423.  
  424.         case '?':
  425.             if (scc == 0)
  426.                 return (0);
  427.             continue;
  428.  
  429.         case '/':
  430.             if (scc)
  431.                 return (0);
  432. slash:
  433.             s = entp;
  434.             sgpathp = gpathp;
  435.             while (*s)
  436.                 addpath(*s++);
  437.             addpath('/');
  438.             if (stat(gpath, &stb) == 0 && isdir(stb))
  439.                 if (*p == 0) {
  440.                     Gcat(gpath, "");
  441.                     globcnt++;
  442.                 } else
  443.                     expand(p);
  444.             gpathp = sgpathp;
  445.             *gpathp = 0;
  446.             return (0);
  447.         }
  448.     }
  449. }
  450.  
  451. static
  452. Gmatch(s, p)
  453.     register char *s, *p;
  454. {
  455.     register int scc;
  456.     int ok, lc;
  457.     int c, cc;
  458.  
  459.     for (;;) {
  460.         scc = *s++ & TRIM;
  461.         switch (c = *p++) {
  462.  
  463.         case '[':
  464.             ok = 0;
  465.             lc = 077777;
  466.             while (cc = *p++) {
  467.                 if (cc == ']') {
  468.                     if (ok)
  469.                         break;
  470.                     return (0);
  471.                 }
  472.                 if (cc == '-') {
  473.                     if (lc <= scc && scc <= *p++)
  474.                         ok++;
  475.                 } else
  476.                     if (scc == (lc = cc))
  477.                         ok++;
  478.             }
  479.             if (cc == 0)
  480.                 if (ok)
  481.                     p--;
  482.                 else
  483.                     return 0;
  484.             continue;
  485.  
  486.         case '*':
  487.             if (!*p)
  488.                 return (1);
  489.             for (s--; *s; s++)
  490.                 if (Gmatch(s, p))
  491.                     return (1);
  492.             return (0);
  493.  
  494.         case 0:
  495.             return (scc == 0);
  496.  
  497.         default:
  498.             if ((c & TRIM) != scc)
  499.                 return (0);
  500.             continue;
  501.  
  502.         case '?':
  503.             if (scc == 0)
  504.                 return (0);
  505.             continue;
  506.  
  507.         }
  508.     }
  509. }
  510.  
  511. static void
  512. Gcat(s1, s2)
  513.     register char *s1, *s2;
  514. {
  515.     register int len = strlen(s1) + strlen(s2) + 1;
  516.  
  517.     if (len >= gnleft || gargc >= GAVSIZ - 1)
  518.         globerr = "Arguments too long";
  519.     else {
  520.         gargc++;
  521.         gnleft -= len;
  522.         gargv[gargc] = 0;
  523.         gargv[gargc - 1] = strspl(s1, s2);
  524.     }
  525. }
  526.  
  527. static void
  528. addpath(c)
  529.     char c;
  530. {
  531.  
  532.     if (gpathp >= lastgpathp)
  533.         globerr = "Pathname too long";
  534.     else {
  535.         *gpathp++ = c;
  536.         *gpathp = 0;
  537.     }
  538. }
  539.  
  540. static void
  541. rscan(t, f)
  542.     register char **t;
  543.     int (*f)();
  544. {
  545.     register char *p, c;
  546.  
  547.     while (p = *t++) {
  548.         if (f == tglob)
  549.             if (*p == '~')
  550.                 gflag |= 2;
  551.             else if (eq(p, "{") || eq(p, "{}"))
  552.                 continue;
  553.         while (c = *p++)
  554.             (*f)(c);
  555.     }
  556. }
  557. /*
  558. static
  559. scan(t, f)
  560.     register char **t;
  561.     int (*f)();
  562. {
  563.     register char *p, c;
  564.  
  565.     while (p = *t++)
  566.         while (c = *p)
  567.             *p++ = (*f)(c);
  568. } */
  569.  
  570. static
  571. tglob(c)
  572.     register char c;
  573. {
  574.  
  575.     if (any(c, globchars))
  576.         gflag |= c == '{' ? 2 : 1;
  577.     return (c);
  578. }
  579. /*
  580. static
  581. trim(c)
  582.     char c;
  583. {
  584.  
  585.     return (c & TRIM);
  586. } */
  587.  
  588.  
  589. letter(c)
  590.     register char c;
  591. {
  592.  
  593.     return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
  594. }
  595.  
  596. digit(c)
  597.     register char c;
  598. {
  599.  
  600.     return (c >= '0' && c <= '9');
  601. }
  602.  
  603. any(c, s)
  604.     register int c;
  605.     register char *s;
  606. {
  607.  
  608.     while (*s)
  609.         if (*s++ == c)
  610.             return(1);
  611.     return(0);
  612. }
  613. blklen(av)
  614.     register char **av;
  615. {
  616.     register int i = 0;
  617.  
  618.     while (*av++)
  619.         i++;
  620.     return (i);
  621. }
  622.  
  623. char **
  624. blkcpy(oav, bv)
  625.     char **oav;
  626.     register char **bv;
  627. {
  628.     register char **av = oav;
  629.  
  630.     while (*av++ = *bv++)
  631.         continue;
  632.     return (oav);
  633. }
  634.  
  635. blkfree(av0)
  636.     char **av0;
  637. {
  638.     register char **av = av0;
  639.  
  640.     while (*av)
  641.         free(*av++);
  642. }
  643.  
  644. char *
  645. strspl(cp, dp)
  646.     register char *cp, *dp;
  647. {
  648.     register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
  649.  
  650.     if (ep == (char *)0)
  651.         fatal("Out of memory");
  652.     (void) strcpy(ep, cp);
  653.     (void) strcat(ep, dp);
  654.     return (ep);
  655. }
  656.  
  657. char **
  658. copyblk(v)
  659.     register char **v;
  660. {
  661.     register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
  662.                         sizeof(char **)));
  663.     if (nv == (char **)0)
  664.         fatal("Out of memory");
  665.  
  666.     return (blkcpy(nv, v));
  667. }
  668.  
  669. static
  670. char *
  671. strend(cp)
  672.     register char *cp;
  673. {
  674.  
  675.     while (*cp)
  676.         cp++;
  677.     return (cp);
  678. }
  679. /*
  680.  * Extract a home directory from the password file
  681.  * The argument points to a buffer where the name of the
  682.  * user whose home directory is sought is currently.
  683.  * We write the home directory of the user back there.
  684.  */
  685. gethdir(home)
  686.     char *home;
  687. {
  688.     register struct passwd *pp = getpwnam(home);
  689.  
  690.     if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
  691.         return (1);
  692.     (void) strcpy(home, pp->pw_dir);
  693.     return (0);
  694. }
  695.