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