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