xref: /original-bsd/local/toolchest/ksh/sh/expand.c (revision abd50c55)
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 
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 
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 
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 
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