xref: /original-bsd/old/sh/expand.c (revision fb7939e6)
1 /*	expand.c	4.4	83/07/01	*/
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	<sys/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)) != NULL
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 		IF setjmp(INTbuf) == 0 THEN trapjmp[INTR] = 1; FI
83 		WHILE (trapnote&SIGSET) == 0 ANDF (dp = readdir(dirf)) != NULL
84 		DO	IF (*dp->d_name=='.' ANDF *cs!='.')
85 			THEN	continue;
86 			FI
87 			IF gmatch(dp->d_name, cs)
88 			THEN	addg(s,dp->d_name,rescan); count++;
89 			FI
90 		OD
91 		closedir(dirf); trapjmp[INTR] = 0;
92 
93 		IF rescan
94 		THEN	REG ARGPTR	rchain;
95 			rchain=gchain; gchain=schain;
96 			IF count
97 			THEN	count=0;
98 				WHILE rchain
99 				DO	count += expand(rchain->argval,1);
100 					rchain=rchain->argnxt;
101 				OD
102 			FI
103 			*rescan='/';
104 		FI
105 	FI
106 
107 	BEGIN
108 	   REG CHAR	c;
109 	   s=as;
110 	   WHILE c = *s
111 	   DO	*s++=(c&STRIP?c:'/') OD
112 	END
113 	return(count);
114 }
115 
116 gmatch(s, p)
117 	REG STRING	s, p;
118 {
119 	REG INT		scc;
120 	CHAR		c;
121 
122 	IF scc = *s++
123 	THEN	IF (scc &= STRIP)==0
124 		THEN	scc=0200;
125 		FI
126 	FI
127 	SWITCH c = *p++ IN
128 
129 	    case '[':
130 		{BOOL ok; INT lc;
131 		ok=0; lc=077777;
132 		WHILE c = *p++
133 		DO	IF c==']'
134 			THEN	return(ok?gmatch(s,p):0);
135 			ELIF c==MINUS
136 			THEN	IF lc<=scc ANDF scc<=(*p++) THEN ok++ FI
137 			ELSE	IF scc==(lc=(c&STRIP)) THEN ok++ FI
138 			FI
139 		OD
140 		return(0);
141 		}
142 
143 	    default:
144 		IF (c&STRIP)!=scc THEN return(0) FI
145 
146 	    case '?':
147 		return(scc?gmatch(s,p):0);
148 
149 	    case '*':
150 		IF *p==0 THEN return(1) FI
151 		--s;
152 		WHILE *s
153 		DO  IF gmatch(s++,p) THEN return(1) FI OD
154 		return(0);
155 
156 	    case 0:
157 		return(scc==0);
158 	ENDSW
159 }
160 
161 LOCAL VOID	addg(as1,as2,as3)
162 	STRING		as1, as2, as3;
163 {
164 	REG STRING	s1, s2;
165 	REG INT		c;
166 
167 	s2 = locstak()+BYTESPERWORD;
168 
169 	s1=as1;
170 	WHILE c = *s1++
171 	DO	IF (c &= STRIP)==0
172 		THEN	*s2++='/';
173 			break;
174 		FI
175 		*s2++=c;
176 	OD
177 	s1=as2;
178 	WHILE *s2 = *s1++ DO s2++ OD
179 	IF s1=as3
180 	THEN	*s2++='/';
181 		WHILE *s2++ = *++s1 DONE
182 	FI
183 	makearg(endstak(s2));
184 }
185 
186 makearg(args)
187 	REG STRING	args;
188 {
189 	args->argnxt=gchain;
190 	gchain=args;
191 }
192 
193