xref: /original-bsd/old/sh/expand.c (revision 7a4e9f34)
1 /*	expand.c	4.1	82/05/07	*/
2 
3 #
4 /*
5  *	UNIX shell
6  *
7  *	S. R. Bourne
8  *	Bell Telephone Laboratories
9  *
10  */
11 
12 #include	"defs.h"
13 #include	<sys/param.h>
14 #include	<sys/stat.h>
15 #include	<dir.h>
16 
17 
18 
19 /* globals (file name generation)
20  *
21  * "*" in params matches r.e ".*"
22  * "?" in params matches r.e. "."
23  * "[...]" in params matches character class
24  * "[...a-z...]" in params matches a through z.
25  *
26  */
27 
28 PROC VOID	addg();
29 
30 
31 INT	expand(as,rflg)
32 	STRING		as;
33 {
34 	INT		count;
35 	DIR		*dirf;
36 	BOOL		dir=0;
37 	STRING		rescan = 0;
38 	REG STRING	s, cs;
39 	ARGPTR		schain = gchain;
40 	struct direct	*dp;
41 	STATBUF		statb;
42 
43 	IF trapnote&SIGSET THEN return(0); FI
44 
45 	s=cs=as;
46 
47 	/* check for meta chars */
48 	BEGIN
49 	   REG BOOL slash; slash=0;
50 	   WHILE !fngchar(*cs)
51 	   DO	IF *cs++==0
52 		THEN	IF rflg ANDF slash THEN break; ELSE return(0) FI
53 		ELIF *cs=='/'
54 		THEN	slash++;
55 		FI
56 	   OD
57 	END
58 
59 	LOOP	IF cs==s
60 		THEN	s=nullstr;
61 			break;
62 		ELIF *--cs == '/'
63 		THEN	*cs=0;
64 			IF s==cs THEN s="/" FI
65 			break;
66 		FI
67 	POOL
68 	IF stat(s,&statb)>=0
69 	    ANDF (statb.st_mode&S_IFMT)==S_IFDIR
70 	    ANDF (dirf=opendir(s))>0
71 	THEN	dir++;
72 	FI
73 	count=0;
74 	IF *cs==0 THEN *cs++=0200 FI
75 	IF dir
76 	THEN	/* check for rescan */
77 		REG STRING rs; rs=cs;
78 
79 		REP	IF *rs=='/' THEN rescan=rs; *rs=0; gchain=0 FI
80 		PER	*rs++ DONE
81 
82 		WHILE (dp = readdir(dirf)) != NULL ANDF (trapnote&SIGSET) == 0
83 		DO	IF (*dp->d_name=='.' ANDF *cs!='.')
84 			THEN	continue;
85 			FI
86 			IF gmatch(dp->d_name, cs)
87 			THEN	addg(s,dp->d_name,rescan); count++;
88 			FI
89 		OD
90 		closedir(dirf);
91 
92 		IF rescan
93 		THEN	REG ARGPTR	rchain;
94 			rchain=gchain; gchain=schain;
95 			IF count
96 			THEN	count=0;
97 				WHILE rchain
98 				DO	count += expand(rchain->argval,1);
99 					rchain=rchain->argnxt;
100 				OD
101 			FI
102 			*rescan='/';
103 		FI
104 	FI
105 
106 	BEGIN
107 	   REG CHAR	c;
108 	   s=as;
109 	   WHILE c = *s
110 	   DO	*s++=(c&STRIP?c:'/') OD
111 	END
112 	return(count);
113 }
114 
115 gmatch(s, p)
116 	REG STRING	s, p;
117 {
118 	REG INT		scc;
119 	CHAR		c;
120 
121 	IF scc = *s++
122 	THEN	IF (scc &= STRIP)==0
123 		THEN	scc=0200;
124 		FI
125 	FI
126 	SWITCH c = *p++ IN
127 
128 	    case '[':
129 		{BOOL ok; INT lc;
130 		ok=0; lc=077777;
131 		WHILE c = *p++
132 		DO	IF c==']'
133 			THEN	return(ok?gmatch(s,p):0);
134 			ELIF c==MINUS
135 			THEN	IF lc<=scc ANDF scc<=(*p++) THEN ok++ FI
136 			ELSE	IF scc==(lc=(c&STRIP)) THEN ok++ FI
137 			FI
138 		OD
139 		return(0);
140 		}
141 
142 	    default:
143 		IF (c&STRIP)!=scc THEN return(0) FI
144 
145 	    case '?':
146 		return(scc?gmatch(s,p):0);
147 
148 	    case '*':
149 		IF *p==0 THEN return(1) FI
150 		--s;
151 		WHILE *s
152 		DO  IF gmatch(s++,p) THEN return(1) FI OD
153 		return(0);
154 
155 	    case 0:
156 		return(scc==0);
157 	ENDSW
158 }
159 
160 LOCAL VOID	addg(as1,as2,as3)
161 	STRING		as1, as2, as3;
162 {
163 	REG STRING	s1, s2;
164 	REG INT		c;
165 
166 	s2 = locstak()+BYTESPERWORD;
167 
168 	s1=as1;
169 	WHILE c = *s1++
170 	DO	IF (c &= STRIP)==0
171 		THEN	*s2++='/';
172 			break;
173 		FI
174 		*s2++=c;
175 	OD
176 	s1=as2;
177 	WHILE *s2 = *s1++ DO s2++ OD
178 	IF s1=as3
179 	THEN	*s2++='/';
180 		WHILE *s2++ = *++s1 DONE
181 	FI
182 	makearg(endstak(s2));
183 }
184 
185 makearg(args)
186 	REG STRING	args;
187 {
188 	args->argnxt=gchain;
189 	gchain=args;
190 }
191 
192