home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / ncftp-1.9.5.tar.gz / ncftp-1.9.5.tar / ncftp-1.9.5 / glob.c < prev    next >
C/C++ Source or Header  |  1995-10-01  |  10KB  |  656 lines

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