1 /* $NetBSD: expand.c,v 1.17 2009/10/13 12:11:19 christos Exp $ */
4 * Copyright (c) 1991 Carnegie Mellon University
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation.
13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 * Carnegie Mellon requests users of this software to return to
19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
20 * School of Computer Science
21 * Carnegie Mellon University
22 * Pittsburgh PA 15213-3890
24 * any improvements or extensions that they make and grant Carnegie the rights
25 * to redistribute these changes.
28 * expand - expand wildcard filename specifications
31 * int expand(spec, buffer, bufsize);
32 * char *spec, **buffer;
35 * Expand takes a file specification, and expands it into filenames
36 * by resolving the characters '*', '?', '[', ']', '{', '}' and '~'
37 * in the same manner as the shell. You provide "buffer", which is
38 * an array of char *'s, and you tell how big it is in bufsize.
39 * Expand will compute the corresponding filenames, and will fill up
40 * the entries of buffer with pointers to malloc'd strings.
42 * The value returned by expand is the number of filenames found. If
43 * this value is -1, then malloc failed to allocate a string. If the
44 * value is bufsize + 1, then too many names were found and you can try
45 * again with a bigger buffer.
47 * This routine was basically created from the csh sh.glob.c file with
48 * the following intended differences:
50 * Filenames are not sorted.
51 * All expanded filenames returned exist.
53 **********************************************************************
55 * 13-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
56 * Replaced a stat() with lstat() and changed glob() to only call
57 * matchdir() for directories.
59 * 20-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
60 * Created from csh glob() function and 4.1 expand() function.
62 **********************************************************************
64 #include <sys/param.h>
80 static char pathbuf
[MAXPATHLEN
];
81 static char *path
, *pathp
, *lastpathp
;
83 static const char globchars
[] = "{[*?";/* meta characters */
84 static char *entp
; /* current dir entry pointer */
86 static char **BUFFER
; /* pointer to the buffer */
87 static int BUFSIZE
; /* maximum number in buffer */
88 static int bufcnt
; /* current number in buffer */
90 #define fixit(a) (a[0] ? a : ".")
92 int expand(char *, char **, int);
93 static void glob(char *);
94 static void matchdir(char *);
95 static int execbrc(char *, char *);
96 static int match(char *, char *);
97 static int amatch(char *, char *);
98 static void addone(char *, const char *);
99 static int addpath(char);
100 static int gethdir(char *, size_t);
103 expand(char *spec
, char **buffer
, int bufsize
)
105 pathp
= path
= pathbuf
;
107 lastpathp
= &path
[MAXPATHLEN
- 2];
111 if (setjmp(sjbuf
) == 0)
120 char *spathp
, *oldcs
;
125 if (*cs
== '~' && pathp
== path
) {
128 for (cs
++; isalnum((unsigned char)*cs
) || *cs
== '_' || *cs
== '-';)
131 if (!*cs
|| *cs
== '/') {
132 if (pathp
!= path
+ 1) {
134 if (gethdir(path
+ 1, sizeof path
- 1))
136 strncpy(path
, path
+ 1, sizeof path
- 1);
138 strncpy(path
, (char *) getenv("HOME"), sizeof path
- 1);
139 path
[sizeof path
- 1] = '\0';
140 pathp
= path
+ strlen(path
);
143 while (*cs
== 0 || strchr(globchars
, *cs
) == 0) {
145 if (lstat(fixit(path
), &stb
) >= 0)
153 while (cs
> as
&& *cs
!= '/')
162 /* this should not be an lstat */
163 if (stat(fixit(path
), &stb
) >= 0 && S_ISDIR(stb
.st_mode
))
172 matchdir(char *pattern
)
181 dirp
= opendir(fixit(path
));
184 while ((dp
= readdir(dirp
)) != NULL
) {
185 #if defined(HAS_POSIX_DIR) && !defined(__SVR4) && !defined(__CYGWIN__)
186 if (dp
->d_fileno
== 0)
192 if (match(dp
->d_name
, pattern
))
193 addone(path
, dp
->d_name
);
200 execbrc(char *p
, char *s
)
202 char restbuf
[MAXPATHLEN
+ 1];
205 char *lm
, savec
, *spathp
;
207 for (lm
= restbuf
; *p
!= '{'; *lm
++ = *p
++)
209 for (pe
= ++p
; *pe
; pe
++)
220 for (pe
++; *pe
&& *pe
!= ']'; pe
++)
229 for (pl
= pm
= p
; pm
<= pe
; pm
++)
230 switch (*pm
& 0177) {
246 snprintf(lm
, sizeof(restbuf
) - (lm
- restbuf
),
254 } else if (amatch(s
, restbuf
))
260 for (pm
++; *pm
&& *pm
!= ']'; pm
++)
270 match(char *s
, char *p
)
275 if (*s
== '.' && *p
!= '.')
285 amatch(char *s
, char *p
)
297 return (execbrc(p
- 1, s
- 1));
301 while ((cc
= *p
++) != 0) {
308 if (lc
<= scc
&& scc
<= *p
++)
310 } else if (scc
== (lc
= cc
))
348 if (stat(fixit(path
), &stb
) >= 0 &&
349 (stb
.st_mode
& S_IFMT
) == S_IFDIR
) {
364 addone(char *s1
, const char *s2
)
368 if (bufcnt
>= BUFSIZE
) {
369 bufcnt
= BUFSIZE
+ 1;
372 ep
= malloc(strlen(s1
) + strlen(s2
) + 1);
377 BUFFER
[bufcnt
++] = ep
;
380 while ((*ep
++ = *s2
++) != '\0')
387 if (pathp
>= lastpathp
)
395 gethdir(char *home
, size_t homelen
)
397 struct passwd
*pp
= getpwnam(home
);
401 strncpy(home
, pp
->pw_dir
, homelen
- 1);
402 home
[homelen
- 1] = '\0';