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