1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1995 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * UNIX shell
32 *
33 */
34
35 #include "defs.h"
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <dirent.h>
39
40
41
42 /*
43 * globals (file name generation)
44 *
45 * "*" in params matches r.e ".*"
46 * "?" in params matches r.e. "."
47 * "[...]" in params matches character class
48 * "[...a-z...]" in params matches a through z.
49 *
50 */
51 static void addg(unsigned char *, unsigned char *, unsigned char *,
52 unsigned char *);
53 void makearg(struct argnod *);
54
55 int
expand(unsigned char * as,int rcnt)56 expand(unsigned char *as, int rcnt)
57 {
58 int count;
59 DIR *dirf;
60 BOOL dir = 0;
61 unsigned char *rescan = 0;
62 unsigned char *slashsav = 0;
63 unsigned char *s, *cs;
64 unsigned char *s2 = 0;
65 struct argnod *schain = gchain;
66 BOOL slash;
67 int len;
68 wchar_t wc;
69
70 if (trapnote & SIGSET)
71 return (0);
72 s = cs = as;
73 /*
74 * check for meta chars
75 */
76 {
77 BOOL open;
78
79 slash = 0;
80 open = 0;
81 do
82 {
83 if ((len = mbtowc(&wc, (char *)cs, MB_LEN_MAX)) <= 0) {
84 len = 1;
85 wc = (unsigned char)*cs;
86 }
87
88 cs += len;
89 switch (wc) {
90 case 0:
91 if (rcnt && slash)
92 break;
93 else
94 return (0);
95
96 case '/':
97 slash++;
98 open = 0;
99 continue;
100
101 case '[':
102 open++;
103 continue;
104
105 case ']':
106 if (open == 0)
107 continue;
108
109 case '?':
110 case '*':
111 if (rcnt > slash)
112 continue;
113 else
114 cs--;
115 break;
116
117 case '\\':
118 cs++;
119 default:
120 continue;
121 }
122 break;
123 } while (TRUE);
124 }
125
126 for (;;) {
127 if (cs == s) {
128 s = (unsigned char *)nullstr;
129 break;
130 } else if (*--cs == '/') {
131 *cs = 0;
132 if (s == cs)
133 s = (unsigned char *)"/";
134 else {
135 /*
136 * push trimmed copy of directory prefix
137 * onto stack
138 */
139 s2 = cpystak(s);
140 trim(s2);
141 s = s2;
142 }
143 break;
144 }
145 }
146
147 if ((dirf = opendir(*s ? (char *)s : (char *)".")) != 0)
148 dir++;
149
150 /* Let s point to original string because it will be trimmed later */
151 if (s2)
152 s = as;
153 count = 0;
154 if (*cs == 0)
155 slashsav = cs++; /* remember where first slash in as is */
156
157 /* check for rescan */
158 if (dir) {
159 unsigned char *rs;
160 struct dirent *e;
161
162 rs = cs;
163 do /* find next / in as */
164 {
165 if (*rs == '/') {
166 rescan = rs;
167 *rs = 0;
168 gchain = 0;
169 }
170 } while (*rs++);
171
172 while ((e = readdir(dirf)) && (trapnote & SIGSET) == 0) {
173 if (e->d_name[0] == '.' && *cs != '.')
174 continue;
175
176 if (gmatch(e->d_name, cs)) {
177 addg(s, (unsigned char *)e->d_name, rescan,
178 slashsav);
179 count++;
180 }
181 }
182 (void) closedir(dirf);
183
184 if (rescan) {
185 struct argnod *rchain;
186
187 rchain = gchain;
188 gchain = schain;
189 if (count) {
190 count = 0;
191 while (rchain) {
192 count += expand(rchain->argval,
193 slash + 1);
194 rchain = rchain->argnxt;
195 }
196 }
197 *rescan = '/';
198 }
199 }
200
201 if (slashsav)
202 *slashsav = '/';
203 return (count);
204 }
205
206 static void
addg(unsigned char * as1,unsigned char * as2,unsigned char * as3,unsigned char * as4)207 addg(unsigned char *as1, unsigned char *as2, unsigned char *as3,
208 unsigned char *as4)
209 {
210 unsigned char *s1, *s2;
211 int c;
212 int len;
213 wchar_t wc;
214
215 s2 = locstak() + BYTESPERWORD;
216 s1 = as1;
217 if (as4) {
218 while (c = *s1++) {
219 if (s2 >= brkend)
220 growstak(s2);
221 *s2++ = c;
222 }
223 /*
224 * Restore first slash before the first metacharacter
225 * if as1 is not "/"
226 */
227 if (as4 + 1 == s1) {
228 if (s2 >= brkend)
229 growstak(s2);
230 *s2++ = '/';
231 }
232 }
233 /* add matched entries, plus extra \\ to escape \\'s */
234 s1 = as2;
235 for (;;) {
236 if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) {
237 len = 1;
238 wc = (unsigned char)*s1;
239 }
240 if (s2 >= brkend)
241 growstak(s2);
242
243 if (wc == 0) {
244 *s2 = *s1++;
245 break;
246 }
247
248 if (wc == '\\') {
249 *s2++ = '\\';
250 if (s2 >= brkend)
251 growstak(s2);
252 *s2++ = '\\';
253 s1++;
254 continue;
255 }
256 if ((s2 + len) >= brkend)
257 growstak(s2 + len);
258 memcpy(s2, s1, len);
259 s2 += len;
260 s1 += len;
261 }
262 if (s1 = as3) {
263 if (s2 >= brkend)
264 growstak(s2);
265 *s2++ = '/';
266 do
267 {
268 if (s2 >= brkend)
269 growstak(s2);
270 }
271 while (*s2++ = *++s1);
272 }
273 makearg((struct argnod *)endstak(s2));
274 }
275
276 void
makearg(struct argnod * args)277 makearg(struct argnod *args)
278 {
279 args->argnxt = gchain;
280 gchain = args;
281 }
282