2 * Copyright (c) 1983 Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
14 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
15 * Use is subject to license terms.
17 #pragma ident "%Z%%M% %I% %E% SMI"
22 #define GAVSIZ NCARGS / 6
26 static char shchars
[] = "${[*?";
28 int which
; /* bit mask of types to expand */
29 int eargc
; /* expanded arg count */
30 char **eargv
; /* expanded arg vectors */
34 char *tilde
; /* "~user" if not expanding tilde, else "" */
38 int expany
; /* any expansions done? */
44 static int argcmp(const void *arg1
, const void *arg2
);
45 static void addpath(char c
);
46 static void Cat(char *s1
, char *s2
);
47 static void matchdir(char *pattern
);
48 static void expsh(char *s
);
49 static void expstr(char *s
);
50 static int execbrc(char *p
, char *s
);
52 #define sort() qsort((char *)sortbase, &eargv[eargc] - sortbase, \
53 sizeof (*sortbase), argcmp), sortbase = &eargv[eargc]
55 #define MIN(a, b) ((a) < (b) ? (a) : (b))
58 * Take a list of names and expand any macros, etc.
59 * wh = E_VARS if expanding variables.
60 * wh = E_SHELL if expanding shell characters.
61 * wh = E_TILDE if expanding `~'.
62 * or any of these or'ed together.
64 * Major portions of this were snarfed from csh/sh.glob.c.
68 struct namelist
*list
;
71 register struct namelist
*nl
, *prev
;
73 char pathbuf
[LINESIZE
];
74 char *argvbuf
[GAVSIZ
];
77 printf("expand(%x, %d)\nlist = ", list
, wh
);
84 for (nl
= list
; nl
!= NULL
; nl
= nl
->n_next
)
85 for (cp
= nl
->n_name
; *cp
; cp
++)
91 path
= tpathp
= pathp
= pathbuf
;
93 lastpathp
= &path
[sizeof pathbuf
- 2];
96 eargv
= sortbase
= argvbuf
;
100 * Walk the name list and expand names into eargv[];
102 for (nl
= list
; nl
!= NULL
; nl
= nl
->n_next
)
105 * Take expanded list of names from eargv[] and build a new list.
108 for (n
= 0; n
< eargc
; n
++) {
110 nl
->n_name
= eargv
[n
];
119 printf("expanded list = ");
129 register char *cp
, *cp1
;
130 register struct namelist
*tp
;
134 extern char homedir
[];
136 if (s
== NULL
|| *s
== '\0')
139 if ((which
& E_VARS
) && (cp
= index(s
, '$')) != NULL
) {
142 yyerror("no variable name after '$'");
147 if ((tail
= index(cp
, RC
)) == NULL
) {
148 yyerror("unmatched '{'");
151 *tail
++ = savec
= '\0';
153 yyerror("no variable name after '$'");
161 tp
= lookup(cp
, NULL
, 0);
165 for (; tp
!= NULL
; tp
= tp
->n_next
) {
166 (void) snprintf(buf
, sizeof (buf
), "%s%s%s", s
,
172 (void) snprintf(buf
, sizeof (buf
), "%s%s", s
, tail
);
176 if ((which
& ~E_VARS
) == 0 || !strcmp(s
, "{") || !strcmp(s
, "{}")) {
183 if (*cp
== '\0' || *cp
== '/') {
190 if (cp1
>= &buf
[sizeof (buf
)]) {
191 yyerror("User name too long");
195 } while (*cp
&& *cp
!= '/');
197 if (pw
== NULL
|| strcmp(pw
->pw_name
, buf
+1) != 0) {
198 if ((pw
= getpwnam(buf
+1)) == NULL
) {
199 static char unknown_user
[] =
200 ": unknown user name";
204 sizeof (unknown_user
));
205 strcpy(cp1
, unknown_user
);
213 for (cp
= path
; cp
<= lastpathp
+ 1 && (*cp
++ = *cp1
++); )
215 tpathp
= pathp
= cp
- 1;
217 tpathp
= pathp
= path
;
221 if (!(which
& E_SHELL
)) {
233 Cat(s
, ""); /* "nonomatch" is set */
238 argcmp(const void *arg1
, const void *arg2
)
240 char *a1
= *(char **)arg1
;
241 char *a2
= *(char **)arg2
;
243 return (strcmp(a1
, a2
));
247 * If there are any Shell meta characters in the name,
248 * expand into a list, after searching directory
255 register char *spathp
, *oldcp
;
260 while (!any(*cp
, shchars
)) {
262 if (!expany
|| stat(path
, &stb
) >= 0) {
273 while (cp
> s
&& *cp
!= '/')
293 register struct dirent
*dp
;
296 dirp
= opendir(path
);
302 if (fstat(dirp
->dd_fd
, &stb
) < 0)
304 if (!ISDIR(stb
.st_mode
)) {
308 while ((dp
= readdir(dirp
)) != NULL
)
309 if (match(dp
->d_name
, pattern
)) {
311 Cat(path
, dp
->d_name
);
313 if (pathp
+ strlen(dp
->d_name
) - 1 >
315 errno
= ENAMETOOLONG
;
318 strcpy(pathp
, dp
->d_name
);
330 char *strerr
= strerror(errno
);
332 if (path
+ strlen(path
) + strlen(strerr
) + 1 > lastpathp
)
333 strcpy(lastpathp
- strlen(strerr
) - 1, ": ");
336 strcat(path
, strerr
);
345 char restbuf
[LINESIZE
+ 2];
346 register char *pe
, *pm
, *pl
;
348 char *lm
, savec
, *spathp
;
350 for (lm
= restbuf
; *p
!= '{'; *lm
++ = *p
++) {
351 if (lm
>= &restbuf
[sizeof (restbuf
)]) {
352 yyerror("Pathname too long");
356 for (pe
= ++p
; *pe
; pe
++)
370 for (pe
++; *pe
&& *pe
!= ']'; pe
++)
373 yyerror("Missing ']'");
377 if (brclev
|| !*pe
) {
378 yyerror("Missing '}'");
381 for (pl
= pm
= p
; pm
<= pe
; pm
++)
382 switch (*pm
& (QUOTE
|TRIM
)) {
401 if (lm
+ strlen(pl
) + strlen(pe
+ 1) >=
402 &restbuf
[sizeof (restbuf
)]) {
403 yyerror("Pathname too long");
407 strcat(restbuf
, pe
+ 1);
414 } else if (amatch(s
, restbuf
))
421 for (pm
++; *pm
&& *pm
!= ']'; pm
++)
424 yyerror("Missing ']'");
435 register char *sentp
;
436 char sexpany
= expany
;
438 if (*s
== '.' && *p
!= '.')
450 register char *s
, *p
;
464 return (execbrc(p
- 1, s
- 1));
476 if (lc
<= scc
&& scc
<= *p
++)
479 if (scc
== (lc
= cc
))
483 yyerror("Missing ']'");
501 return (scc
== '\0');
504 if ((c
& TRIM
) != scc
)
522 if (stat(path
, &stb
) == 0 && ISDIR(stb
.st_mode
))
539 register char *s
, *p
;
559 if (lc
<= scc
&& scc
<= *p
++)
562 if (scc
== (lc
= cc
))
566 yyerror("Missing ']'");
580 return (scc
== '\0');
583 if ((c
& TRIM
) != scc
)
598 register char *s1
, *s2
;
600 int len
= strlen(s1
) + strlen(s2
) + 1;
604 if (nleft
<= 0 || ++eargc
>= GAVSIZ
)
605 fatal("Arguments too long\n");
607 eargv
[eargc
- 1] = s
= (char *)malloc(len
);
609 fatal("ran out of memory\n");
610 while (*s
++ = *s1
++ & TRIM
)
613 while (*s
++ = *s2
++ & TRIM
)
621 if (pathp
> lastpathp
)
622 yyerror("Pathname too long");
630 * Expand file names beginning with `~' into the
631 * user's home directory path name. Return a pointer in buf to the
632 * part corresponding to `file'.
635 exptilde(buf
, len
, file
)
640 register char *s1
, *s2
, *s3
;
641 extern char homedir
[];
644 if (strlen(file
) + 1 > len
) {
645 error("pathname too long: %s\n", file
);
651 if (*++file
== '\0') {
654 } else if (*file
== '/') {
659 while (*s3
&& *s3
!= '/')
665 if (pw
== NULL
|| strcmp(pw
->pw_name
, file
) != 0) {
666 if ((pw
= getpwnam(file
)) == NULL
) {
667 error("%s: unknown user name\n", file
);
677 for (s1
= buf
; s1
< &buf
[len
] && (*s1
++ = *s2
++); )
682 while (s1
< &buf
[len
] && (*s1
++ = *s3
++))
685 if (s1
== &buf
[len
]) {
686 error("pathname too long: %s\n", file
- 1);