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