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