1 /*
2
3 * Copyright (c) 1984, 1985, 1986 AT&T
4 * All Rights Reserved
5
6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE
7 * CODE OF AT&T.
8 * The copyright notice above does not
9 * evidence any actual or intended
10 * publication of such source code.
11
12 */
13 /* @(#)expand.c 1.1 */
14 /*
15 * UNIX shell
16 *
17 * S. R. Bourne
18 * Rewritten by David Korn
19 * AT&T Bell Laboratories
20 *
21 */
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/dir.h>
26 #include "defs.h"
27 #include "brkincr.h"
28 #include "stak.h"
29 #include "sym.h"
30 #include "shtype.h"
31
32 void rm_files();
33 int expand();
34
35 extern STKPTR locstak(),endstak();
36 extern FILE *fdopen();
37 extern char *movstr();
38 extern char *strrchr();
39 extern void trim();
40
41
42 /* globals (file name generation)
43 *
44 * "*" in params matches r.e ".*"
45 * "?" in params matches r.e. "."
46 * "[...]" in params matches character class
47 * "[...a-z...]" in params matches a through z.
48 *
49 */
50
51 static void addg();
52
expand(as,rcnt)53 int expand(as,rcnt)
54 char *as;
55 {
56 int count;
57 #ifdef BSD_4_2
58 DIR *dirf;
59 #else
60 FILE *dirf;
61 #endif /* BSD_4_2 */
62 BOOL nometa=0;
63 BOOL dir=0;
64 char *rescan = 0;
65 char *slashsav = 0;
66 register char *s, *cs;
67 int quote = 0;
68 int slash;
69 int add_slash = 1; /* insert a separator slash */
70 char *sname;
71 ARGPTR schain = gchain;
72 /* this union forces enough space for the NULL byte */
73 union Dirent
74 {
75 struct direct entry;
76 char entrybuf[sizeof(struct direct)+1]; /* room for null byte */
77 };
78 union Dirent dirent;
79 struct direct *entry = &dirent.entry;
80 #ifndef BSD_4_2
81 char dirbuff[BUFSIZ];
82 #endif /* BSD_4_2 */
83 if(trapnote&SIGSET)
84 return(0);
85 s=cs=as;
86 #ifndef BSD_4_2
87 entry->d_name[DIRSIZ]=0; /* to end the string */
88 #endif /* BSD_4_2 */
89 /* check for meta chars */
90 {
91 register int open = 0;
92 slash=0;
93 do
94 {
95 switch(*cs++)
96 {
97 case 0:
98 {
99 nometa = '/';
100 if (rcnt && slash)
101 break;
102 else
103 return(0);
104 }
105
106 case '/':
107 slash++;
108 open = 0;
109 continue;
110
111 case '[':
112 open++;
113 continue;
114
115 case ']':
116 if(open)
117 break;
118 continue;
119
120 case '?':
121 case '*':
122 if(rcnt > slash)
123 continue;
124 cs--;
125 break;
126
127 case ESCAPE:
128 quote++;
129 cs++;
130 default:
131 continue;
132 }
133 break;
134 }
135 while(1);
136 }
137 while(1)
138 {
139 if(cs==s)
140 {
141 s=nullstr;
142 break;
143 }
144 else if(*--cs == '/')
145 {
146 *cs=nometa;
147 if(s==cs)
148 {
149 s= "/";
150 add_slash = 0;
151 }
152 break;
153 }
154 }
155 if(quote && s!=cs)
156 {
157 s = cpystak(s);
158 trim(s);
159 }
160 /* special case where there are no meta-chars left in path */
161 if(nometa)
162 {
163 /* read permission on directories not needed */
164 if(access(s,0)==0)
165 {
166 addg(s,nullstr,NIL,0);
167 return(1);
168 }
169 return(0);
170 }
171 sname = (*s?s:dot);
172 if(ftype(sname,S_IFMT,S_IFDIR)
173 #ifdef BSD_4_2
174 && (dirf=opendir(sname))!=NULL)
175 #else
176 && (dirf=fdopen(open(sname,0),"r"))!=NULL)
177 #endif /* BSD_4_2 */
178 {
179 dir++;
180 #ifndef BSD_4_2
181 setbuf(dirf,dirbuff);
182 #endif
183 }
184 count=0;
185 if(*cs==0)
186 slashsav = cs++;
187 if(dir)
188 /* check for rescan */
189 {
190 register char *rs = cs;
191 do
192 {
193 if(*rs=='/')
194 {
195 rescan=rs;
196 *rs=0;
197 gchain=0;
198 }
199 }
200 while(*rs++);
201 #ifdef BSD_4_2
202 while((entry=readdir(dirf)) && (trapnote&SIGSET)==0)
203 #else
204 while(fread((char*)entry,sizeof(struct direct),1,dirf)==1 && (trapnote&SIGSET)==0)
205 #endif /* BSD_4_2 */
206 {
207 if(entry->d_ino==0 || (*entry->d_name=='.' && *cs!='.'))
208 continue;
209
210 if(gmatch(entry->d_name, cs))
211 {
212 addg(s,entry->d_name,rescan,add_slash);
213 count++;
214 }
215 }
216 #ifdef BSD_4_2
217 closedir(dirf);
218 #else
219 closefd(dirf);
220 #endif /* BSD_4_2 */
221 if(rescan)
222 {
223 register ARGPTR rchain;
224 rchain=gchain; gchain=schain;
225 if(count)
226 {
227 count=0;
228 while(rchain)
229 {
230 count += expand(rchain->argval,slash+1);
231 rchain=rchain->argchn;
232 }
233 }
234 *rescan='/';
235 }
236 }
237 if(slashsav)
238 *slashsav = '/';
239 return(count);
240 }
241
addg(as1,as2,as3,add_slash)242 static void addg(as1,as2,as3,add_slash)
243 char *as1, *as2, *as3;
244 int add_slash;
245 {
246 register char *s1, *s2;
247 register int c;
248 register ARGPTR argp = (ARGPTR)locstak();
249 argp->argflag &= ~(A_MAKE|A_RAW);
250 s2 = argp->argval;
251 s1=as1;
252 /* directory */
253 while(c = *s1)
254 {
255 s1++;
256 if(c == ESCAPE)
257 *s2++ = ESCAPE;
258 *s2++ = c;
259 }
260 if(add_slash && s1 > as1 && *as2)
261 *s2++='/';
262 s1=as2;
263 /* component */
264 while(c = *s1++)
265 {
266 /* escape the ESCAPE characters */
267 if(c == ESCAPE)
268 *s2++ = ESCAPE;
269 *s2++ = c;
270 }
271 /* rescan */
272 if(s1=as3)
273 {
274 *s2++='/';
275 while(*s2++ = *++s1);
276 }
277 if(is_option(MARKDIR))
278 {
279 *s2 = 0;
280 if(ftype(argp->argval,S_IFMT,S_IFDIR))
281 *s2++ = '/';
282 }
283 endstak(s2);
284 argp->argchn= gchain;
285 gchain = argp;
286 }
287
288
289 /*
290 * remove tmp files
291 * template of the form /tmp/sh$$.???
292 */
293
rm_files(template)294 void rm_files(template)
295 register char *template;
296 {
297 register char *cp;
298 ARGPTR schain;
299 cp = strrchr(template,'.');
300 *(cp+1) = 0;
301 f_complete(template,"*");
302 schain = gchain;
303 while(schain)
304 {
305 unlink(schain->argval);
306 schain = schain->argchn;
307 }
308 }
309
310 /*
311 * file name completion
312 * generate the list of files found by adding an suffix to end of name
313 * The number of matches is returned
314 */
315
f_complete(name,suffix)316 f_complete(name,suffix)
317 char *name;
318 register char *suffix;
319 {
320 register char *cp;
321 register char *dp;
322 gchain = NULL;
323 dp = (char*)locstak();
324 cp = movstr(name,dp);
325 if(suffix)
326 cp = movstr(suffix,cp);
327 endstak(cp);
328 return(expand(dp,0));
329 }
330