Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.sbin / sup / source / expand.c
blob5b258e7570c0d6a7b93ed6ff3ee6e45e293cab1d
1 /* $NetBSD: expand.c,v 1.17 2009/10/13 12:11:19 christos Exp $ */
3 /*
4 * Copyright (c) 1991 Carnegie Mellon University
5 * All Rights Reserved.
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
30 * Usage:
31 * int expand(spec, buffer, bufsize);
32 * char *spec, **buffer;
33 * int bufsize;
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 **********************************************************************
54 * HISTORY
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>
65 #include <sys/stat.h>
66 #ifdef HAS_POSIX_DIR
67 #include <dirent.h>
68 #else
69 #include <sys/dir.h>
70 #endif
71 #include <pwd.h>
72 #include <ctype.h>
73 #include "libc.h"
74 #include <setjmp.h>
75 #include <stdlib.h>
76 #include <unistd.h>
78 static jmp_buf sjbuf;
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);
102 int
103 expand(char *spec, char **buffer, int bufsize)
105 pathp = path = pathbuf;
106 *pathp = 0;
107 lastpathp = &path[MAXPATHLEN - 2];
108 BUFFER = buffer;
109 BUFSIZE = bufsize;
110 bufcnt = 0;
111 if (setjmp(sjbuf) == 0)
112 glob(spec);
113 return (bufcnt);
116 static void
117 glob(char *as)
119 char *cs;
120 char *spathp, *oldcs;
121 struct stat stb;
123 spathp = pathp;
124 cs = as;
125 if (*cs == '~' && pathp == path) {
126 if (addpath('~'))
127 goto endit;
128 for (cs++; isalnum((unsigned char)*cs) || *cs == '_' || *cs == '-';)
129 if (addpath(*cs++))
130 goto endit;
131 if (!*cs || *cs == '/') {
132 if (pathp != path + 1) {
133 *pathp = 0;
134 if (gethdir(path + 1, sizeof path - 1))
135 goto endit;
136 strncpy(path, path + 1, sizeof path - 1);
137 } else
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) {
144 if (*cs == 0) {
145 if (lstat(fixit(path), &stb) >= 0)
146 addone(path, "");
147 goto endit;
149 if (addpath(*cs++))
150 goto endit;
152 oldcs = cs;
153 while (cs > as && *cs != '/')
154 cs--, pathp--;
155 if (*cs == '/')
156 cs++, pathp++;
157 *pathp = 0;
158 if (*oldcs == '{') {
159 execbrc(cs, NULL);
160 return;
162 /* this should not be an lstat */
163 if (stat(fixit(path), &stb) >= 0 && S_ISDIR(stb.st_mode))
164 matchdir(cs);
165 endit:
166 pathp = spathp;
167 *pathp = 0;
168 return;
171 static void
172 matchdir(char *pattern)
174 #ifdef HAS_POSIX_DIR
175 struct dirent *dp;
176 #else
177 struct direct *dp;
178 #endif
179 DIR *dirp;
181 dirp = opendir(fixit(path));
182 if (dirp == NULL)
183 return;
184 while ((dp = readdir(dirp)) != NULL) {
185 #if defined(HAS_POSIX_DIR) && !defined(__SVR4) && !defined(__CYGWIN__)
186 if (dp->d_fileno == 0)
187 continue;
188 #else
189 if (dp->d_ino == 0)
190 continue;
191 #endif
192 if (match(dp->d_name, pattern))
193 addone(path, dp->d_name);
195 closedir(dirp);
196 return;
199 static int
200 execbrc(char *p, char *s)
202 char restbuf[MAXPATHLEN + 1];
203 char *pe, *pm, *pl;
204 int brclev = 0;
205 char *lm, savec, *spathp;
207 for (lm = restbuf; *p != '{'; *lm++ = *p++)
208 continue;
209 for (pe = ++p; *pe; pe++)
210 switch (*pe) {
211 case '{':
212 brclev++;
213 continue;
214 case '}':
215 if (brclev == 0)
216 goto pend;
217 brclev--;
218 continue;
219 case '[':
220 for (pe++; *pe && *pe != ']'; pe++)
221 continue;
222 if (!*pe)
223 break;
224 continue;
226 pend:
227 if (brclev || !*pe)
228 return (0);
229 for (pl = pm = p; pm <= pe; pm++)
230 switch (*pm & 0177) {
231 case '{':
232 brclev++;
233 continue;
234 case '}':
235 if (brclev) {
236 brclev--;
237 continue;
239 goto doit;
240 case ',':
241 if (brclev)
242 continue;
243 doit:
244 savec = *pm;
245 *pm = 0;
246 snprintf(lm, sizeof(restbuf) - (lm - restbuf),
247 "%s%s", pl, pe + 1);
248 *pm = savec;
249 if (s == 0) {
250 spathp = pathp;
251 glob(restbuf);
252 pathp = spathp;
253 *pathp = 0;
254 } else if (amatch(s, restbuf))
255 return (1);
256 pl = pm + 1;
257 continue;
259 case '[':
260 for (pm++; *pm && *pm != ']'; pm++)
261 continue;
262 if (!*pm)
263 break;
264 continue;
266 return (0);
269 static int
270 match(char *s, char *p)
272 int c;
273 char *sentp;
275 if (*s == '.' && *p != '.')
276 return (0);
277 sentp = entp;
278 entp = s;
279 c = amatch(s, p);
280 entp = sentp;
281 return (c);
284 static int
285 amatch(char *s, char *p)
287 int scc;
288 int ok, lc;
289 char *spathp;
290 struct stat stb;
291 int c, cc;
293 for (;;) {
294 scc = *s++ & 0177;
295 switch (c = *p++) {
296 case '{':
297 return (execbrc(p - 1, s - 1));
298 case '[':
299 ok = 0;
300 lc = 077777;
301 while ((cc = *p++) != 0) {
302 if (cc == ']') {
303 if (ok)
304 break;
305 return (0);
307 if (cc == '-') {
308 if (lc <= scc && scc <= *p++)
309 ok++;
310 } else if (scc == (lc = cc))
311 ok++;
313 if (cc == 0)
314 return (0);
315 continue;
316 case '*':
317 if (!*p)
318 return (1);
319 if (*p == '/') {
320 p++;
321 goto slash;
323 for (s--; *s; s++)
324 if (amatch(s, p))
325 return (1);
326 return (0);
327 case 0:
328 return (scc == 0);
329 default:
330 if (c != scc)
331 return (0);
332 continue;
333 case '?':
334 if (scc == 0)
335 return (0);
336 continue;
337 case '/':
338 if (scc)
339 return (0);
340 slash:
341 s = entp;
342 spathp = pathp;
343 while (*s)
344 if (addpath(*s++))
345 goto pathovfl;
346 if (addpath('/'))
347 goto pathovfl;
348 if (stat(fixit(path), &stb) >= 0 &&
349 (stb.st_mode & S_IFMT) == S_IFDIR) {
350 if (*p == 0)
351 addone(path, "");
352 else
353 glob(p);
355 pathovfl:
356 pathp = spathp;
357 *pathp = 0;
358 return (0);
363 static void
364 addone(char *s1, const char *s2)
366 char *ep;
368 if (bufcnt >= BUFSIZE) {
369 bufcnt = BUFSIZE + 1;
370 longjmp(sjbuf, 1);
372 ep = malloc(strlen(s1) + strlen(s2) + 1);
373 if (ep == 0) {
374 bufcnt = -1;
375 longjmp(sjbuf, 1);
377 BUFFER[bufcnt++] = ep;
378 while (*s1)
379 *ep++ = *s1++;
380 while ((*ep++ = *s2++) != '\0')
381 continue;
384 static int
385 addpath(char c)
387 if (pathp >= lastpathp)
388 return (1);
389 *pathp++ = c;
390 *pathp = 0;
391 return (0);
394 static int
395 gethdir(char *home, size_t homelen)
397 struct passwd *pp = getpwnam(home);
399 if (pp == 0)
400 return (1);
401 strncpy(home, pp->pw_dir, homelen - 1);
402 home[homelen - 1] = '\0';
403 return (0);