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