home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume35 / ncftp / part03 / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-25  |  9.7 KB  |  645 lines

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