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,v < prev    next >
Encoding:
Text File  |  1994-07-25  |  12.5 KB  |  692 lines

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