1*2bd8f802Smrg /* $NetBSD: expand.c,v 1.19 2023/08/03 08:03:19 mrg Exp $ */
23aab4f7dSthorpej
361f28255Scgd /*
4a5bfdf78Scgd * Copyright (c) 1983, 1993
5a5bfdf78Scgd * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
323b3cf635Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
343aab4f7dSthorpej #if 0
353aab4f7dSthorpej static char sccsid[] = "@(#)expand.c 8.1 (Berkeley) 6/9/93";
363aab4f7dSthorpej #else
37*2bd8f802Smrg __RCSID("$NetBSD: expand.c,v 1.19 2023/08/03 08:03:19 mrg Exp $");
383aab4f7dSthorpej #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd
410026c9e9Smrg #include <sys/types.h>
420026c9e9Smrg
430026c9e9Smrg #include <errno.h>
440026c9e9Smrg #include <pwd.h>
450026c9e9Smrg
4661f28255Scgd #include "defs.h"
4761f28255Scgd
4861f28255Scgd #define GAVSIZ NCARGS / 6
4961f28255Scgd #define LC '{'
5061f28255Scgd #define RC '}'
5161f28255Scgd
5261f28255Scgd static char shchars[] = "${[*?";
5361f28255Scgd
5461f28255Scgd int which; /* bit mask of types to expand */
5561f28255Scgd int eargc; /* expanded arg count */
5661f28255Scgd char **eargv; /* expanded arg vectors */
5761f28255Scgd char *path;
5861f28255Scgd char *pathp;
5961f28255Scgd char *lastpathp;
604538623fSlukem const char *tilde; /* "~user" if not expanding tilde, else "" */
6161f28255Scgd char *tpathp;
6261f28255Scgd int nleft;
6361f28255Scgd
6461f28255Scgd int expany; /* any expansions done? */
6561f28255Scgd char *entp;
6661f28255Scgd char **sortbase;
6761f28255Scgd
6861f28255Scgd #define sort() qsort((char *)sortbase, &eargv[eargc] - sortbase, \
6961f28255Scgd sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]
7061f28255Scgd
714538623fSlukem static void Cat(const char *, const char *);
72a9b4ca62Swiz static void addpath(int);
73a9b4ca62Swiz static int amatch(char *, char *);
74a9b4ca62Swiz static int argcmp(const void *, const void *);
75a9b4ca62Swiz static int execbrc(char *, char *);
76a9b4ca62Swiz static void expsh(char *);
77a9b4ca62Swiz static void expstr(char *);
78a9b4ca62Swiz static int match(char *, char *);
79a9b4ca62Swiz static void matchdir(char *);
80a5bfdf78Scgd
8161f28255Scgd /*
8261f28255Scgd * Take a list of names and expand any macros, etc.
8361f28255Scgd * wh = E_VARS if expanding variables.
8461f28255Scgd * wh = E_SHELL if expanding shell characters.
8561f28255Scgd * wh = E_TILDE if expanding `~'.
8661f28255Scgd * or any of these or'ed together.
8761f28255Scgd *
8861f28255Scgd * Major portions of this were snarfed from csh/sh.glob.c.
8961f28255Scgd */
9061f28255Scgd struct namelist *
expand(struct namelist * list,int wh)91a9b4ca62Swiz expand(struct namelist *list, int wh)
9261f28255Scgd {
933b3cf635Slukem struct namelist *nl, *prev;
943b3cf635Slukem int n;
9561f28255Scgd char pathbuf[BUFSIZ];
9661f28255Scgd char *argvbuf[GAVSIZ];
9761f28255Scgd
9861f28255Scgd if (debug) {
993b3cf635Slukem printf("expand(%lx, %d)\nlist = ", (long)list, wh);
10061f28255Scgd prnames(list);
10161f28255Scgd }
10261f28255Scgd
10361f28255Scgd if (wh == 0) {
1043b3cf635Slukem char *cp;
10561f28255Scgd
10661f28255Scgd for (nl = list; nl != NULL; nl = nl->n_next)
10761f28255Scgd for (cp = nl->n_name; *cp; cp++)
10861f28255Scgd *cp = *cp & TRIM;
10961f28255Scgd return(list);
11061f28255Scgd }
11161f28255Scgd
11261f28255Scgd which = wh;
11361f28255Scgd path = tpathp = pathp = pathbuf;
11461f28255Scgd *pathp = '\0';
11561f28255Scgd lastpathp = &path[sizeof pathbuf - 2];
11661f28255Scgd tilde = "";
11761f28255Scgd eargc = 0;
11861f28255Scgd eargv = sortbase = argvbuf;
11961f28255Scgd *eargv = 0;
12061f28255Scgd nleft = NCARGS - 4;
12161f28255Scgd /*
12261f28255Scgd * Walk the name list and expand names into eargv[];
12361f28255Scgd */
12461f28255Scgd for (nl = list; nl != NULL; nl = nl->n_next)
12561f28255Scgd expstr(nl->n_name);
12661f28255Scgd /*
12761f28255Scgd * Take expanded list of names from eargv[] and build a new list.
12861f28255Scgd */
12961f28255Scgd list = prev = NULL;
13061f28255Scgd for (n = 0; n < eargc; n++) {
13161f28255Scgd nl = makenl(NULL);
13261f28255Scgd nl->n_name = eargv[n];
13361f28255Scgd if (prev == NULL)
13461f28255Scgd list = prev = nl;
13561f28255Scgd else {
13661f28255Scgd prev->n_next = nl;
13761f28255Scgd prev = nl;
13861f28255Scgd }
13961f28255Scgd }
14061f28255Scgd if (debug) {
14161f28255Scgd printf("expanded list = ");
14261f28255Scgd prnames(list);
14361f28255Scgd }
144*2bd8f802Smrg sortbase = NULL;
145*2bd8f802Smrg eargv = NULL;
146*2bd8f802Smrg path = tpathp = pathp = NULL;
147*2bd8f802Smrg lastpathp = NULL;
14861f28255Scgd return(list);
14961f28255Scgd }
15061f28255Scgd
151a5bfdf78Scgd static void
expstr(char * s)152a9b4ca62Swiz expstr(char *s)
15361f28255Scgd {
1543b3cf635Slukem char *cp, *cp1;
1553b3cf635Slukem struct namelist *tp;
15661f28255Scgd char *tail;
1574538623fSlukem char expbuf[BUFSIZ];
15861f28255Scgd int savec, oeargc;
15961f28255Scgd extern char homedir[];
16061f28255Scgd
16161f28255Scgd if (s == NULL || *s == '\0')
16261f28255Scgd return;
16361f28255Scgd
1643b3cf635Slukem if ((which & E_VARS) && (cp = strchr(s, '$')) != NULL) {
16561f28255Scgd *cp++ = '\0';
16661f28255Scgd if (*cp == '\0') {
16761f28255Scgd yyerror("no variable name after '$'");
16861f28255Scgd return;
16961f28255Scgd }
17061f28255Scgd if (*cp == LC) {
17161f28255Scgd cp++;
1723b3cf635Slukem if ((tail = strchr(cp, RC)) == NULL) {
17361f28255Scgd yyerror("unmatched '{'");
17461f28255Scgd return;
17561f28255Scgd }
17661f28255Scgd *tail++ = savec = '\0';
17761f28255Scgd if (*cp == '\0') {
17861f28255Scgd yyerror("no variable name after '$'");
17961f28255Scgd return;
18061f28255Scgd }
18161f28255Scgd } else {
18261f28255Scgd tail = cp + 1;
18361f28255Scgd savec = *tail;
18461f28255Scgd *tail = '\0';
18561f28255Scgd }
186b55c3729Spk tp = lookup(cp, 0, 0);
18761f28255Scgd if (savec != '\0')
18861f28255Scgd *tail = savec;
18961f28255Scgd if (tp != NULL) {
19061f28255Scgd for (; tp != NULL; tp = tp->n_next) {
1914538623fSlukem snprintf(expbuf, sizeof(expbuf), "%s%s%s", s,
192336eeb5fSthorpej tp->n_name, tail);
1934538623fSlukem expstr(expbuf);
19461f28255Scgd }
19561f28255Scgd return;
19661f28255Scgd }
1974538623fSlukem snprintf(expbuf, sizeof(expbuf), "%s%s", s, tail);
1984538623fSlukem expstr(expbuf);
19961f28255Scgd return;
20061f28255Scgd }
20161f28255Scgd if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) {
20261f28255Scgd Cat(s, "");
20361f28255Scgd sort();
20461f28255Scgd return;
20561f28255Scgd }
20661f28255Scgd if (*s == '~') {
20761f28255Scgd cp = ++s;
20861f28255Scgd if (*cp == '\0' || *cp == '/') {
20961f28255Scgd tilde = "~";
21061f28255Scgd cp1 = homedir;
21161f28255Scgd } else {
2124538623fSlukem tilde = cp1 = expbuf;
21361f28255Scgd *cp1++ = '~';
21461f28255Scgd do
21561f28255Scgd *cp1++ = *cp++;
21661f28255Scgd while (*cp && *cp != '/');
21761f28255Scgd *cp1 = '\0';
2184538623fSlukem if (pw == NULL || strcmp(pw->pw_name, expbuf+1) != 0) {
2194538623fSlukem if ((pw = getpwnam(expbuf+1)) == NULL) {
2204538623fSlukem strlcat(expbuf, ": unknown user name",
2214538623fSlukem sizeof(expbuf));
2224538623fSlukem yyerror(expbuf+1);
22361f28255Scgd return;
22461f28255Scgd }
22561f28255Scgd }
22661f28255Scgd cp1 = pw->pw_dir;
22761f28255Scgd s = cp;
22861f28255Scgd }
2293b3cf635Slukem for (cp = path; (*cp++ = *cp1++) != 0; )
23061f28255Scgd ;
23161f28255Scgd tpathp = pathp = cp - 1;
23261f28255Scgd } else {
23361f28255Scgd tpathp = pathp = path;
23461f28255Scgd tilde = "";
23561f28255Scgd }
23661f28255Scgd *pathp = '\0';
23761f28255Scgd if (!(which & E_SHELL)) {
23861f28255Scgd if (which & E_TILDE)
23961f28255Scgd Cat(path, s);
24061f28255Scgd else
24161f28255Scgd Cat(tilde, s);
24261f28255Scgd sort();
24361f28255Scgd return;
24461f28255Scgd }
24561f28255Scgd oeargc = eargc;
24661f28255Scgd expany = 0;
24761f28255Scgd expsh(s);
24861f28255Scgd if (eargc == oeargc)
24961f28255Scgd Cat(s, ""); /* "nonomatch" is set */
25061f28255Scgd sort();
25161f28255Scgd }
25261f28255Scgd
253a5bfdf78Scgd static int
argcmp(const void * a1,const void * a2)254a9b4ca62Swiz argcmp(const void *a1, const void *a2)
25561f28255Scgd {
25661f28255Scgd
2574538623fSlukem return (strcmp(*(const char * const *)a1, *(const char * const *)a2));
25861f28255Scgd }
25961f28255Scgd
26061f28255Scgd /*
26161f28255Scgd * If there are any Shell meta characters in the name,
26261f28255Scgd * expand into a list, after searching directory
26361f28255Scgd */
264a5bfdf78Scgd static void
expsh(char * s)265a9b4ca62Swiz expsh(char *s)
26661f28255Scgd {
2673b3cf635Slukem char *cp;
2683b3cf635Slukem char *spathp, *oldcp;
26961f28255Scgd struct stat stb;
27061f28255Scgd
27161f28255Scgd spathp = pathp;
27261f28255Scgd cp = s;
27361f28255Scgd while (!any(*cp, shchars)) {
27461f28255Scgd if (*cp == '\0') {
27561f28255Scgd if (!expany || stat(path, &stb) >= 0) {
27661f28255Scgd if (which & E_TILDE)
27761f28255Scgd Cat(path, "");
27861f28255Scgd else
27961f28255Scgd Cat(tilde, tpathp);
28061f28255Scgd }
28161f28255Scgd goto endit;
28261f28255Scgd }
28361f28255Scgd addpath(*cp++);
28461f28255Scgd }
28561f28255Scgd oldcp = cp;
28661f28255Scgd while (cp > s && *cp != '/')
28761f28255Scgd cp--, pathp--;
28861f28255Scgd if (*cp == '/')
28961f28255Scgd cp++, pathp++;
29061f28255Scgd *pathp = '\0';
29161f28255Scgd if (*oldcp == '{') {
29261f28255Scgd execbrc(cp, NULL);
29361f28255Scgd return;
29461f28255Scgd }
29561f28255Scgd matchdir(cp);
29661f28255Scgd endit:
29761f28255Scgd pathp = spathp;
29861f28255Scgd *pathp = '\0';
29961f28255Scgd }
30061f28255Scgd
301a5bfdf78Scgd static void
matchdir(char * pattern)302a9b4ca62Swiz matchdir(char *pattern)
30361f28255Scgd {
30461f28255Scgd struct stat stb;
305b751ad2cSchristos struct dirent *dp;
30661f28255Scgd DIR *dirp;
30761f28255Scgd
30861f28255Scgd dirp = opendir(path);
30961f28255Scgd if (dirp == NULL) {
31061f28255Scgd if (expany)
31161f28255Scgd return;
31261f28255Scgd goto patherr2;
31361f28255Scgd }
31461f28255Scgd if (fstat(dirp->dd_fd, &stb) < 0)
31561f28255Scgd goto patherr1;
316004f2550Smycroft if (!S_ISDIR(stb.st_mode)) {
31761f28255Scgd errno = ENOTDIR;
31861f28255Scgd goto patherr1;
31961f28255Scgd }
32061f28255Scgd while ((dp = readdir(dirp)) != NULL)
32161f28255Scgd if (match(dp->d_name, pattern)) {
32261f28255Scgd if (which & E_TILDE)
32361f28255Scgd Cat(path, dp->d_name);
32461f28255Scgd else {
32561f28255Scgd strcpy(pathp, dp->d_name);
32661f28255Scgd Cat(tilde, tpathp);
32761f28255Scgd *pathp = '\0';
32861f28255Scgd }
32961f28255Scgd }
33061f28255Scgd closedir(dirp);
33161f28255Scgd return;
33261f28255Scgd
33361f28255Scgd patherr1:
33461f28255Scgd closedir(dirp);
33561f28255Scgd patherr2:
33661f28255Scgd strcat(path, ": ");
33761f28255Scgd strcat(path, strerror(errno));
33861f28255Scgd yyerror(path);
33961f28255Scgd }
34061f28255Scgd
341a5bfdf78Scgd static int
execbrc(char * p,char * s)342a9b4ca62Swiz execbrc(char *p, char *s)
34361f28255Scgd {
34461f28255Scgd char restbuf[BUFSIZ + 2];
3453b3cf635Slukem char *pe, *pm, *pl;
34661f28255Scgd int brclev = 0;
34761f28255Scgd char *lm, savec, *spathp;
34861f28255Scgd
34961f28255Scgd for (lm = restbuf; *p != '{'; *lm++ = *p++)
35061f28255Scgd continue;
35161f28255Scgd for (pe = ++p; *pe; pe++)
35261f28255Scgd switch (*pe) {
35361f28255Scgd
35461f28255Scgd case '{':
35561f28255Scgd brclev++;
35661f28255Scgd continue;
35761f28255Scgd
35861f28255Scgd case '}':
35961f28255Scgd if (brclev == 0)
36061f28255Scgd goto pend;
36161f28255Scgd brclev--;
36261f28255Scgd continue;
36361f28255Scgd
36461f28255Scgd case '[':
36561f28255Scgd for (pe++; *pe && *pe != ']'; pe++)
36661f28255Scgd continue;
36761f28255Scgd if (!*pe)
36861f28255Scgd yyerror("Missing ']'");
36961f28255Scgd continue;
37061f28255Scgd }
37161f28255Scgd pend:
37261f28255Scgd if (brclev || !*pe) {
37361f28255Scgd yyerror("Missing '}'");
37461f28255Scgd return (0);
37561f28255Scgd }
37661f28255Scgd for (pl = pm = p; pm <= pe; pm++)
37761f28255Scgd switch (*pm & (QUOTE|TRIM)) {
37861f28255Scgd
37961f28255Scgd case '{':
38061f28255Scgd brclev++;
38161f28255Scgd continue;
38261f28255Scgd
38361f28255Scgd case '}':
38461f28255Scgd if (brclev) {
38561f28255Scgd brclev--;
38661f28255Scgd continue;
38761f28255Scgd }
38861f28255Scgd goto doit;
38961f28255Scgd
39061f28255Scgd case ',':
39161f28255Scgd if (brclev)
39261f28255Scgd continue;
39361f28255Scgd doit:
39461f28255Scgd savec = *pm;
39561f28255Scgd *pm = 0;
396e97c220eSitojun strlcpy(lm, pl, sizeof(restbuf) - (lm - restbuf));
397e97c220eSitojun strlcat(restbuf, pe + 1, sizeof(restbuf));
39861f28255Scgd *pm = savec;
39961f28255Scgd if (s == 0) {
40061f28255Scgd spathp = pathp;
40161f28255Scgd expsh(restbuf);
40261f28255Scgd pathp = spathp;
40361f28255Scgd *pathp = 0;
40461f28255Scgd } else if (amatch(s, restbuf))
40561f28255Scgd return (1);
40661f28255Scgd sort();
40761f28255Scgd pl = pm + 1;
40861f28255Scgd continue;
40961f28255Scgd
41061f28255Scgd case '[':
41161f28255Scgd for (pm++; *pm && *pm != ']'; pm++)
41261f28255Scgd continue;
41361f28255Scgd if (!*pm)
41461f28255Scgd yyerror("Missing ']'");
41561f28255Scgd continue;
41661f28255Scgd }
41761f28255Scgd return (0);
41861f28255Scgd }
41961f28255Scgd
420a5bfdf78Scgd static int
match(char * s,char * p)421a9b4ca62Swiz match(char *s, char *p)
42261f28255Scgd {
4233b3cf635Slukem int c;
4243b3cf635Slukem char *sentp;
42561f28255Scgd char sexpany = expany;
42661f28255Scgd
42761f28255Scgd if (*s == '.' && *p != '.')
42861f28255Scgd return (0);
42961f28255Scgd sentp = entp;
43061f28255Scgd entp = s;
43161f28255Scgd c = amatch(s, p);
43261f28255Scgd entp = sentp;
43361f28255Scgd expany = sexpany;
43461f28255Scgd return (c);
43561f28255Scgd }
43661f28255Scgd
437a5bfdf78Scgd static int
amatch(char * s,char * p)438a9b4ca62Swiz amatch(char *s, char *p)
43961f28255Scgd {
4403b3cf635Slukem int scc;
44161f28255Scgd int ok, lc;
44261f28255Scgd char *spathp;
44361f28255Scgd struct stat stb;
44461f28255Scgd int c, cc;
44561f28255Scgd
44661f28255Scgd expany = 1;
44761f28255Scgd for (;;) {
44861f28255Scgd scc = *s++ & TRIM;
44961f28255Scgd switch (c = *p++) {
45061f28255Scgd
45161f28255Scgd case '{':
45261f28255Scgd return (execbrc(p - 1, s - 1));
45361f28255Scgd
45461f28255Scgd case '[':
45561f28255Scgd ok = 0;
45661f28255Scgd lc = 077777;
4573b3cf635Slukem while ((cc = *p++) != 0) {
45861f28255Scgd if (cc == ']') {
45961f28255Scgd if (ok)
46061f28255Scgd break;
46161f28255Scgd return (0);
46261f28255Scgd }
46361f28255Scgd if (cc == '-') {
46461f28255Scgd if (lc <= scc && scc <= *p++)
46561f28255Scgd ok++;
46661f28255Scgd } else
46761f28255Scgd if (scc == (lc = cc))
46861f28255Scgd ok++;
46961f28255Scgd }
47061f28255Scgd if (cc == 0) {
47161f28255Scgd yyerror("Missing ']'");
47261f28255Scgd return (0);
47361f28255Scgd }
47461f28255Scgd continue;
47561f28255Scgd
47661f28255Scgd case '*':
47761f28255Scgd if (!*p)
47861f28255Scgd return (1);
47961f28255Scgd if (*p == '/') {
48061f28255Scgd p++;
48161f28255Scgd goto slash;
48261f28255Scgd }
48361f28255Scgd for (s--; *s; s++)
48461f28255Scgd if (amatch(s, p))
48561f28255Scgd return (1);
48661f28255Scgd return (0);
48761f28255Scgd
48861f28255Scgd case '\0':
48961f28255Scgd return (scc == '\0');
49061f28255Scgd
49161f28255Scgd default:
49261f28255Scgd if ((c & TRIM) != scc)
49361f28255Scgd return (0);
49461f28255Scgd continue;
49561f28255Scgd
49661f28255Scgd case '?':
49761f28255Scgd if (scc == '\0')
49861f28255Scgd return (0);
49961f28255Scgd continue;
50061f28255Scgd
50161f28255Scgd case '/':
50261f28255Scgd if (scc)
50361f28255Scgd return (0);
50461f28255Scgd slash:
50561f28255Scgd s = entp;
50661f28255Scgd spathp = pathp;
50761f28255Scgd while (*s)
50861f28255Scgd addpath(*s++);
50961f28255Scgd addpath('/');
510f670fa10Sross if (stat(path, &stb) == 0 && S_ISDIR(stb.st_mode)) {
51161f28255Scgd if (*p == '\0') {
51261f28255Scgd if (which & E_TILDE)
51361f28255Scgd Cat(path, "");
51461f28255Scgd else
51561f28255Scgd Cat(tilde, tpathp);
51661f28255Scgd } else
51761f28255Scgd expsh(p);
518f670fa10Sross }
51961f28255Scgd pathp = spathp;
52061f28255Scgd *pathp = '\0';
52161f28255Scgd return (0);
52261f28255Scgd }
52361f28255Scgd }
52461f28255Scgd }
52561f28255Scgd
526a5bfdf78Scgd static void
Cat(const char * s1,const char * s2)5274538623fSlukem Cat(const char *s1, const char *s2)
52861f28255Scgd {
52961f28255Scgd int len = strlen(s1) + strlen(s2) + 1;
5303b3cf635Slukem char *s;
53161f28255Scgd
53261f28255Scgd nleft -= len;
53361f28255Scgd if (nleft <= 0 || ++eargc >= GAVSIZ)
53461f28255Scgd yyerror("Arguments too long");
53561f28255Scgd eargv[eargc] = 0;
53661f28255Scgd eargv[eargc - 1] = s = malloc(len);
53761f28255Scgd if (s == NULL)
53861f28255Scgd fatal("ran out of memory\n");
5393b3cf635Slukem while ((*s++ = *s1++ & TRIM) != 0)
54061f28255Scgd ;
54161f28255Scgd s--;
5423b3cf635Slukem while ((*s++ = *s2++ & TRIM) != 0)
54361f28255Scgd ;
54461f28255Scgd }
54561f28255Scgd
546a5bfdf78Scgd static void
addpath(int c)547a9b4ca62Swiz addpath(int c)
54861f28255Scgd {
54961f28255Scgd
55061f28255Scgd if (pathp >= lastpathp)
55161f28255Scgd yyerror("Pathname too long");
55261f28255Scgd else {
55361f28255Scgd *pathp++ = c & TRIM;
55461f28255Scgd *pathp = '\0';
55561f28255Scgd }
55661f28255Scgd }
55761f28255Scgd
55861f28255Scgd /*
55961f28255Scgd * Expand file names beginning with `~' into the
56061f28255Scgd * user's home directory path name. Return a pointer in buf to the
56161f28255Scgd * part corresponding to `file'.
56261f28255Scgd */
56361f28255Scgd char *
exptilde(char * expbuf,char * file)5644538623fSlukem exptilde(char *expbuf, char *file)
56561f28255Scgd {
5663b3cf635Slukem char *s1, *s2, *s3;
56761f28255Scgd extern char homedir[];
56861f28255Scgd
56961f28255Scgd if (*file != '~') {
5704538623fSlukem strcpy(expbuf, file);
5714538623fSlukem return(expbuf);
57261f28255Scgd }
57361f28255Scgd if (*++file == '\0') {
57461f28255Scgd s2 = homedir;
57561f28255Scgd s3 = NULL;
57661f28255Scgd } else if (*file == '/') {
57761f28255Scgd s2 = homedir;
57861f28255Scgd s3 = file;
57961f28255Scgd } else {
58061f28255Scgd s3 = file;
58161f28255Scgd while (*s3 && *s3 != '/')
58261f28255Scgd s3++;
58361f28255Scgd if (*s3 == '/')
58461f28255Scgd *s3 = '\0';
58561f28255Scgd else
58661f28255Scgd s3 = NULL;
58761f28255Scgd if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
58861f28255Scgd if ((pw = getpwnam(file)) == NULL) {
58961f28255Scgd error("%s: unknown user name\n", file);
59061f28255Scgd if (s3 != NULL)
59161f28255Scgd *s3 = '/';
59261f28255Scgd return(NULL);
59361f28255Scgd }
59461f28255Scgd }
59561f28255Scgd if (s3 != NULL)
59661f28255Scgd *s3 = '/';
59761f28255Scgd s2 = pw->pw_dir;
59861f28255Scgd }
5994538623fSlukem for (s1 = expbuf; (*s1++ = *s2++) != 0; )
60061f28255Scgd ;
60161f28255Scgd s2 = --s1;
60261f28255Scgd if (s3 != NULL) {
60361f28255Scgd s2++;
6043b3cf635Slukem while ((*s1++ = *s3++) != 0)
60561f28255Scgd ;
60661f28255Scgd }
60761f28255Scgd return(s2);
60861f28255Scgd }
609