home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / rdist / expand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-25  |  12.4 KB  |  670 lines

  1. /*
  2.  * Copyright (c) 1983, 1993
  3.  *    The Regents of the University of California.  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. /* from: static char sccsid[] = "@(#)expand.c    8.1 (Berkeley) 6/9/93"; */
  36. static char *rcsid = "$Id: expand.c,v 1.1 1994/07/25 12:50:40 florian Exp florian $";
  37. #endif /* not lint */
  38.  
  39. #include "defs.h"
  40.  
  41. #define    GAVSIZ    NCARGS / 6
  42. #define LC '{'
  43. #define RC '}'
  44.  
  45. static char    shchars[] = "${[*?";
  46.  
  47. int    which;        /* bit mask of types to expand */
  48. int    eargc;        /* expanded arg count */
  49. char    **eargv;    /* expanded arg vectors */
  50. char    *path;
  51. char    *pathp;
  52. char    *lastpathp;
  53. char    *tilde;        /* "~user" if not expanding tilde, else "" */
  54. char    *tpathp;
  55. int    nleft;
  56.  
  57. int    expany;        /* any expansions done? */
  58. char    *entp;
  59. char    **sortbase;
  60.  
  61. #define sort()    qsort((char *)sortbase, &eargv[eargc] - sortbase, \
  62.               sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]
  63.  
  64. static void    Cat __P((char *, char *));
  65. static void    addpath __P((int));
  66. static int    amatch __P((char *, char *));
  67. static int    argcmp __P((const void *, const void *));
  68. static int    execbrc __P((char *, char *));
  69. static void    expsh __P((char *));
  70. static void    expstr __P((char *));
  71. static int    match __P((char *, char *));
  72. static void    matchdir __P((char *));
  73. static int    smatch __P((char *, char *));
  74.  
  75. /*
  76.  * Take a list of names and expand any macros, etc.
  77.  * wh = E_VARS if expanding variables.
  78.  * wh = E_SHELL if expanding shell characters.
  79.  * wh = E_TILDE if expanding `~'.
  80.  * or any of these or'ed together.
  81.  *
  82.  * Major portions of this were snarfed from csh/sh.glob.c.
  83.  */
  84. struct namelist *
  85. expand(list, wh)
  86.     struct namelist *list;
  87.     int wh;
  88. {
  89.     register struct namelist *nl, *prev;
  90.     register int n;
  91.     char pathbuf[BUFSIZ];
  92.     char *argvbuf[GAVSIZ];
  93.  
  94.     if (debug) {
  95.         printf("expand(%x, %d)\nlist = ", list, wh);
  96.         prnames(list);
  97.     }
  98.  
  99.     if (wh == 0) {
  100.         register char *cp;
  101.  
  102.         for (nl = list; nl != NULL; nl = nl->n_next)
  103.             for (cp = nl->n_name; *cp; cp++)
  104.                 *cp = *cp & TRIM;
  105.         return(list);
  106.     }
  107.  
  108.     which = wh;
  109.     path = tpathp = pathp = pathbuf;
  110.     *pathp = '\0';
  111.     lastpathp = &path[sizeof pathbuf - 2];
  112.     tilde = "";
  113.     eargc = 0;
  114.     eargv = sortbase = argvbuf;
  115.     *eargv = 0;
  116.     nleft = NCARGS - 4;
  117.     /*
  118.      * Walk the name list and expand names into eargv[];
  119.      */
  120.     for (nl = list; nl != NULL; nl = nl->n_next)
  121.         expstr(nl->n_name);
  122.     /*
  123.      * Take expanded list of names from eargv[] and build a new list.
  124.      */
  125.     list = prev = NULL;
  126.     for (n = 0; n < eargc; n++) {
  127.         nl = makenl(NULL);
  128.         nl->n_name = eargv[n];
  129.         if (prev == NULL)
  130.             list = prev = nl;
  131.         else {
  132.             prev->n_next = nl;
  133.             prev = nl;
  134.         }
  135.     }
  136.     if (debug) {
  137.         printf("expanded list = ");
  138.         prnames(list);
  139.     }
  140.     return(list);
  141. }
  142.  
  143. struct namelist *lookup(char *name, int action, struct namelist *value);
  144.  
  145. static void
  146. expstr(s)
  147.     char *s;
  148. {
  149.     register char *cp, *cp1;
  150.     register struct namelist *tp;
  151.     char *tail;
  152.     char buf[BUFSIZ];
  153.     int savec, oeargc;
  154.     extern char homedir[];
  155.  
  156.     if (s == NULL || *s == '\0')
  157.         return;
  158.  
  159.     if ((which & E_VARS) && (cp = index(s, '$')) != NULL) {
  160.         *cp++ = '\0';
  161.         if (*cp == '\0') {
  162.             yyerror("no variable name after '$'");
  163.             return;
  164.         }
  165.         if (*cp == LC) {
  166.             cp++;
  167.             if ((tail = index(cp, RC)) == NULL) {
  168.                 yyerror("unmatched '{'");
  169.                 return;
  170.             }
  171.             *tail++ = savec = '\0';
  172.             if (*cp == '\0') {
  173.                 yyerror("no variable name after '$'");
  174.                 return;
  175.             }
  176.         } else {
  177.             tail = cp + 1;
  178.             savec = *tail;
  179.             *tail = '\0';
  180.         }
  181.         tp = lookup(cp, 0, NULL);
  182.         if (savec != '\0')
  183.             *tail = savec;
  184.         if (tp != NULL) {
  185.             for (; tp != NULL; tp = tp->n_next) {
  186.                 sprintf(buf, "%s%s%s", s, tp->n_name, tail);
  187.                 expstr(buf);
  188.             }
  189.             return;
  190.         }
  191.         sprintf(buf, "%s%s", s, tail);
  192.         expstr(buf);
  193.         return;
  194.     }
  195.     if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) {
  196.         Cat(s, "");
  197.         sort();
  198.         return;
  199.     }
  200.     if (*s == '~') {
  201.         cp = ++s;
  202.         if (*cp == '\0' || *cp == '/') {
  203.             tilde = "~";
  204.             cp1 = homedir;
  205.         } else {
  206.             tilde = cp1 = buf;
  207.             *cp1++ = '~';
  208.             do
  209.                 *cp1++ = *cp++;
  210.             while (*cp && *cp != '/');
  211.             *cp1 = '\0';
  212.             if (pw == NULL || strcmp(pw->pw_name, buf+1) != 0) {
  213.                 if ((pw = getpwnam(buf+1)) == NULL) {
  214.                     strcat(buf, ": unknown user name");
  215.                     yyerror(buf+1);
  216.                     return;
  217.                 }
  218.             }
  219.             cp1 = pw->pw_dir;
  220.             s = cp;
  221.         }
  222.         for (cp = path; *cp++ = *cp1++; )
  223.             ;
  224.         tpathp = pathp = cp - 1;
  225.     } else {
  226.         tpathp = pathp = path;
  227.         tilde = "";
  228.     }
  229.     *pathp = '\0';
  230.     if (!(which & E_SHELL)) {
  231.         if (which & E_TILDE)
  232.             Cat(path, s);
  233.         else
  234.             Cat(tilde, s);
  235.         sort();
  236.         return;
  237.     }
  238.     oeargc = eargc;
  239.     expany = 0;
  240.     expsh(s);
  241.     if (eargc == oeargc)
  242.         Cat(s, "");        /* "nonomatch" is set */
  243.     sort();
  244. }
  245.  
  246. static int
  247. argcmp(a1, a2)
  248.     const void *a1, *a2;
  249. {
  250.  
  251.     return (strcmp(*(char **)a1, *(char **)a2));
  252. }
  253.  
  254. /*
  255.  * If there are any Shell meta characters in the name,
  256.  * expand into a list, after searching directory
  257.  */
  258. static void
  259. expsh(s)
  260.     char *s;
  261. {
  262.     register char *cp;
  263.     register char *spathp, *oldcp;
  264.     struct stat stb;
  265.  
  266.     spathp = pathp;
  267.     cp = s;
  268.     while (!any(*cp, shchars)) {
  269.         if (*cp == '\0') {
  270.             if (!expany || stat(path, &stb) >= 0) {
  271.                 if (which & E_TILDE)
  272.                     Cat(path, "");
  273.                 else
  274.                     Cat(tilde, tpathp);
  275.             }
  276.             goto endit;
  277.         }
  278.         addpath(*cp++);
  279.     }
  280.     oldcp = cp;
  281.     while (cp > s && *cp != '/')
  282.         cp--, pathp--;
  283.     if (*cp == '/')
  284.         cp++, pathp++;
  285.     *pathp = '\0';
  286.     if (*oldcp == '{') {
  287.         execbrc(cp, NULL);
  288.         return;
  289.     }
  290.     matchdir(cp);
  291. endit:
  292.     pathp = spathp;
  293.     *pathp = '\0';
  294. }
  295.  
  296. static void
  297. matchdir(pattern)
  298.     char *pattern;
  299. {
  300.     struct stat stb;
  301.     register struct direct *dp;
  302.     DIR *dirp;
  303.  
  304.     dirp = opendir(path);
  305.     if (dirp == NULL) {
  306.         if (expany)
  307.             return;
  308.         goto patherr2;
  309.     }
  310.     if (fstat(dirp->dd_fd, &stb) < 0)
  311.         goto patherr1;
  312.     if (!ISDIR(stb.st_mode)) {
  313.         errno = ENOTDIR;
  314.         goto patherr1;
  315.     }
  316.     while ((dp = readdir(dirp)) != NULL)
  317.         if (match(dp->d_name, pattern)) {
  318.             if (which & E_TILDE)
  319.                 Cat(path, dp->d_name);
  320.             else {
  321.                 strcpy(pathp, dp->d_name);
  322.                 Cat(tilde, tpathp);
  323.                 *pathp = '\0';
  324.             }
  325.         }
  326.     closedir(dirp);
  327.     return;
  328.  
  329. patherr1:
  330.     closedir(dirp);
  331. patherr2:
  332.     strcat(path, ": ");
  333.     strcat(path, strerror(errno));
  334.     yyerror(path);
  335. }
  336.  
  337. static int
  338. execbrc(p, s)
  339.     char *p, *s;
  340. {
  341.     char restbuf[BUFSIZ + 2];
  342.     register char *pe, *pm, *pl;
  343.     int brclev = 0;
  344.     char *lm, savec, *spathp;
  345.  
  346.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  347.         continue;
  348.     for (pe = ++p; *pe; pe++)
  349.         switch (*pe) {
  350.  
  351.         case '{':
  352.             brclev++;
  353.             continue;
  354.  
  355.         case '}':
  356.             if (brclev == 0)
  357.                 goto pend;
  358.             brclev--;
  359.             continue;
  360.  
  361.         case '[':
  362.             for (pe++; *pe && *pe != ']'; pe++)
  363.                 continue;
  364.             if (!*pe)
  365.                 yyerror("Missing ']'");
  366.             continue;
  367.         }
  368. pend:
  369.     if (brclev || !*pe) {
  370.         yyerror("Missing '}'");
  371.         return (0);
  372.     }
  373.     for (pl = pm = p; pm <= pe; pm++)
  374.         switch (*pm & (QUOTE|TRIM)) {
  375.  
  376.         case '{':
  377.             brclev++;
  378.             continue;
  379.  
  380.         case '}':
  381.             if (brclev) {
  382.                 brclev--;
  383.                 continue;
  384.             }
  385.             goto doit;
  386.  
  387.         case ',':
  388.             if (brclev)
  389.                 continue;
  390. doit:
  391.             savec = *pm;
  392.             *pm = 0;
  393.             strcpy(lm, pl);
  394.             strcat(restbuf, pe + 1);
  395.             *pm = savec;
  396.             if (s == 0) {
  397.                 spathp = pathp;
  398.                 expsh(restbuf);
  399.                 pathp = spathp;
  400.                 *pathp = 0;
  401.             } else if (amatch(s, restbuf))
  402.                 return (1);
  403.             sort();
  404.             pl = pm + 1;
  405.             continue;
  406.  
  407.         case '[':
  408.             for (pm++; *pm && *pm != ']'; pm++)
  409.                 continue;
  410.             if (!*pm)
  411.                 yyerror("Missing ']'");
  412.             continue;
  413.         }
  414.     return (0);
  415. }
  416.  
  417. static int
  418. match(s, p)
  419.     char *s, *p;
  420. {
  421.     register int c;
  422.     register char *sentp;
  423.     char sexpany = expany;
  424.  
  425.     if (*s == '.' && *p != '.')
  426.         return (0);
  427.     sentp = entp;
  428.     entp = s;
  429.     c = amatch(s, p);
  430.     entp = sentp;
  431.     expany = sexpany;
  432.     return (c);
  433. }
  434.  
  435. static int
  436. amatch(s, p)
  437.     register char *s, *p;
  438. {
  439.     register int scc;
  440.     int ok, lc;
  441.     char *spathp;
  442.     struct stat stb;
  443.     int c, cc;
  444.  
  445.     expany = 1;
  446.     for (;;) {
  447.         scc = *s++ & TRIM;
  448.         switch (c = *p++) {
  449.  
  450.         case '{':
  451.             return (execbrc(p - 1, s - 1));
  452.  
  453.         case '[':
  454.             ok = 0;
  455.             lc = 077777;
  456.             while (cc = *p++) {
  457.                 if (cc == ']') {
  458.                     if (ok)
  459.                         break;
  460.                     return (0);
  461.                 }
  462.                 if (cc == '-') {
  463.                     if (lc <= scc && scc <= *p++)
  464.                         ok++;
  465.                 } else
  466.                     if (scc == (lc = cc))
  467.                         ok++;
  468.             }
  469.             if (cc == 0) {
  470.                 yyerror("Missing ']'");
  471.                 return (0);
  472.             }
  473.             continue;
  474.  
  475.         case '*':
  476.             if (!*p)
  477.                 return (1);
  478.             if (*p == '/') {
  479.                 p++;
  480.                 goto slash;
  481.             }
  482.             for (s--; *s; s++)
  483.                 if (amatch(s, p))
  484.                     return (1);
  485.             return (0);
  486.  
  487.         case '\0':
  488.             return (scc == '\0');
  489.  
  490.         default:
  491.             if ((c & TRIM) != scc)
  492.                 return (0);
  493.             continue;
  494.  
  495.         case '?':
  496.             if (scc == '\0')
  497.                 return (0);
  498.             continue;
  499.  
  500.         case '/':
  501.             if (scc)
  502.                 return (0);
  503. slash:
  504.             s = entp;
  505.             spathp = pathp;
  506.             while (*s)
  507.                 addpath(*s++);
  508.             addpath('/');
  509.             if (stat(path, &stb) == 0 && ISDIR(stb.st_mode))
  510.                 if (*p == '\0') {
  511.                     if (which & E_TILDE)
  512.                         Cat(path, "");
  513.                     else
  514.                         Cat(tilde, tpathp);
  515.                 } else
  516.                     expsh(p);
  517.             pathp = spathp;
  518.             *pathp = '\0';
  519.             return (0);
  520.         }
  521.     }
  522. }
  523.  
  524. static int
  525. smatch(s, p)
  526.     register char *s, *p;
  527. {
  528.     register int scc;
  529.     int ok, lc;
  530.     int c, cc;
  531.  
  532.     for (;;) {
  533.         scc = *s++ & TRIM;
  534.         switch (c = *p++) {
  535.  
  536.         case '[':
  537.             ok = 0;
  538.             lc = 077777;
  539.             while (cc = *p++) {
  540.                 if (cc == ']') {
  541.                     if (ok)
  542.                         break;
  543.                     return (0);
  544.                 }
  545.                 if (cc == '-') {
  546.                     if (lc <= scc && scc <= *p++)
  547.                         ok++;
  548.                 } else
  549.                     if (scc == (lc = cc))
  550.                         ok++;
  551.             }
  552.             if (cc == 0) {
  553.                 yyerror("Missing ']'");
  554.                 return (0);
  555.             }
  556.             continue;
  557.  
  558.         case '*':
  559.             if (!*p)
  560.                 return (1);
  561.             for (s--; *s; s++)
  562.                 if (smatch(s, p))
  563.                     return (1);
  564.             return (0);
  565.  
  566.         case '\0':
  567.             return (scc == '\0');
  568.  
  569.         default:
  570.             if ((c & TRIM) != scc)
  571.                 return (0);
  572.             continue;
  573.  
  574.         case '?':
  575.             if (scc == 0)
  576.                 return (0);
  577.             continue;
  578.  
  579.         }
  580.     }
  581. }
  582.  
  583. static void
  584. Cat(s1, s2)
  585.     register char *s1, *s2;
  586. {
  587.     int len = strlen(s1) + strlen(s2) + 1;
  588.     register char *s;
  589.  
  590.     nleft -= len;
  591.     if (nleft <= 0 || ++eargc >= GAVSIZ)
  592.         yyerror("Arguments too long");
  593.     eargv[eargc] = 0;
  594.     eargv[eargc - 1] = s = malloc(len);
  595.     if (s == NULL)
  596.         fatal("ran out of memory\n");
  597.     while (*s++ = *s1++ & TRIM)
  598.         ;
  599.     s--;
  600.     while (*s++ = *s2++ & TRIM)
  601.         ;
  602. }
  603.  
  604. static void
  605. addpath(c)
  606.     int c;
  607. {
  608.  
  609.     if (pathp >= lastpathp)
  610.         yyerror("Pathname too long");
  611.     else {
  612.         *pathp++ = c & TRIM;
  613.         *pathp = '\0';
  614.     }
  615. }
  616.  
  617. /*
  618.  * Expand file names beginning with `~' into the
  619.  * user's home directory path name. Return a pointer in buf to the
  620.  * part corresponding to `file'.
  621.  */
  622. char *
  623. exptilde(buf, file)
  624.     char buf[];
  625.     register char *file;
  626. {
  627.     register char *s1, *s2, *s3;
  628.     extern char homedir[];
  629.  
  630.     if (*file != '~') {
  631.         strcpy(buf, file);
  632.         return(buf);
  633.     }
  634.     if (*++file == '\0') {
  635.         s2 = homedir;
  636.         s3 = NULL;
  637.     } else if (*file == '/') {
  638.         s2 = homedir;
  639.         s3 = file;
  640.     } else {
  641.         s3 = file;
  642.         while (*s3 && *s3 != '/')
  643.             s3++;
  644.         if (*s3 == '/')
  645.             *s3 = '\0';
  646.         else
  647.             s3 = NULL;
  648.         if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
  649.             if ((pw = getpwnam(file)) == NULL) {
  650.                 error("%s: unknown user name\n", file);
  651.                 if (s3 != NULL)
  652.                     *s3 = '/';
  653.                 return(NULL);
  654.             }
  655.         }
  656.         if (s3 != NULL)
  657.             *s3 = '/';
  658.         s2 = pw->pw_dir;
  659.     }
  660.     for (s1 = buf; *s1++ = *s2++; )
  661.         ;
  662.     s2 = --s1;
  663.     if (s3 != NULL) {
  664.         s2++;
  665.         while (*s1++ = *s3++)
  666.             ;
  667.     }
  668.     return(s2);
  669. }
  670.