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 #pragma ident "%Z%%M% %I% %E% SMI"
31 /*
32 * UNIX shell
33 *
34 */
35
36 #include "defs.h"
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <dirent.h>
40
41
42
43 /*
44 * globals (file name generation)
45 *
46 * "*" in params matches r.e ".*"
47 * "?" in params matches r.e. "."
48 * "[...]" in params matches character class
49 * "[...a-z...]" in params matches a through z.
50 *
51 */
52 static void addg(unsigned char *, unsigned char *, unsigned char *,
53 unsigned char *);
54 void makearg(struct argnod *);
55
56 int
expand(unsigned char * as,int rcnt)57 expand(unsigned char *as, int rcnt)
58 {
59 int count;
60 DIR *dirf;
61 BOOL dir = 0;
62 unsigned char *rescan = 0;
63 unsigned char *slashsav = 0;
64 unsigned char *s, *cs;
65 unsigned char *s2 = 0;
66 struct argnod *schain = gchain;
67 BOOL slash;
68 int len;
69 wchar_t wc;
70
71 if (trapnote & SIGSET)
72 return (0);
73 s = cs = as;
74 /*
75 * check for meta chars
76 */
77 {
78 BOOL open;
79
80 slash = 0;
81 open = 0;
82 do
83 {
84 if ((len = mbtowc(&wc, (char *)cs, MB_LEN_MAX)) <= 0) {
85 len = 1;
86 wc = (unsigned char)*cs;
87 }
88
89 cs += len;
90 switch (wc) {
91 case 0:
92 if (rcnt && slash)
93 break;
94 else
95 return (0);
96
97 case '/':
98 slash++;
99 open = 0;
100 continue;
101
102 case '[':
103 open++;
104 continue;
105
106 case ']':
107 if (open == 0)
108 continue;
109
110 case '?':
111 case '*':
112 if (rcnt > slash)
113 continue;
114 else
115 cs--;
116 break;
117
118 case '\\':
119 cs++;
120 default:
121 continue;
122 }
123 break;
124 } while (TRUE);
125 }
126
127 for (;;) {
128 if (cs == s) {
129 s = (unsigned char *)nullstr;
130 break;
131 } else if (*--cs == '/') {
132 *cs = 0;
133 if (s == cs)
134 s = (unsigned char *)"/";
135 else {
136 /*
137 * push trimmed copy of directory prefix
138 * onto stack
139 */
140 s2 = cpystak(s);
141 trim(s2);
142 s = s2;
143 }
144 break;
145 }
146 }
147
148 if ((dirf = opendir(*s ? (char *)s : (char *)".")) != 0)
149 dir++;
150
151 /* Let s point to original string because it will be trimmed later */
152 if (s2)
153 s = as;
154 count = 0;
155 if (*cs == 0)
156 slashsav = cs++; /* remember where first slash in as is */
157
158 /* check for rescan */
159 if (dir) {
160 unsigned char *rs;
161 struct dirent *e;
162
163 rs = cs;
164 do /* find next / in as */
165 {
166 if (*rs == '/') {
167 rescan = rs;
168 *rs = 0;
169 gchain = 0;
170 }
171 } while (*rs++);
172
173 while ((e = readdir(dirf)) && (trapnote & SIGSET) == 0) {
174 if (e->d_name[0] == '.' && *cs != '.')
175 continue;
176
177 if (gmatch(e->d_name, cs)) {
178 addg(s, (unsigned char *)e->d_name, rescan,
179 slashsav);
180 count++;
181 }
182 }
183 (void) closedir(dirf);
184
185 if (rescan) {
186 struct argnod *rchain;
187
188 rchain = gchain;
189 gchain = schain;
190 if (count) {
191 count = 0;
192 while (rchain) {
193 count += expand(rchain->argval,
194 slash + 1);
195 rchain = rchain->argnxt;
196 }
197 }
198 *rescan = '/';
199 }
200 }
201
202 if (slashsav)
203 *slashsav = '/';
204 return (count);
205 }
206
207 static void
addg(unsigned char * as1,unsigned char * as2,unsigned char * as3,unsigned char * as4)208 addg(unsigned char *as1, unsigned char *as2, unsigned char *as3,
209 unsigned char *as4)
210 {
211 unsigned char *s1, *s2;
212 int c;
213 int len;
214 wchar_t wc;
215
216 s2 = locstak() + BYTESPERWORD;
217 s1 = as1;
218 if (as4) {
219 while (c = *s1++) {
220 if (s2 >= brkend)
221 growstak(s2);
222 *s2++ = c;
223 }
224 /*
225 * Restore first slash before the first metacharacter
226 * if as1 is not "/"
227 */
228 if (as4 + 1 == s1) {
229 if (s2 >= brkend)
230 growstak(s2);
231 *s2++ = '/';
232 }
233 }
234 /* add matched entries, plus extra \\ to escape \\'s */
235 s1 = as2;
236 for (;;) {
237 if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) {
238 len = 1;
239 wc = (unsigned char)*s1;
240 }
241 if (s2 >= brkend)
242 growstak(s2);
243
244 if (wc == 0) {
245 *s2 = *s1++;
246 break;
247 }
248
249 if (wc == '\\') {
250 *s2++ = '\\';
251 if (s2 >= brkend)
252 growstak(s2);
253 *s2++ = '\\';
254 s1++;
255 continue;
256 }
257 if ((s2 + len) >= brkend)
258 growstak(s2 + len);
259 memcpy(s2, s1, len);
260 s2 += len;
261 s1 += len;
262 }
263 if (s1 = as3) {
264 if (s2 >= brkend)
265 growstak(s2);
266 *s2++ = '/';
267 do
268 {
269 if (s2 >= brkend)
270 growstak(s2);
271 }
272 while (*s2++ = *++s1);
273 }
274 makearg((struct argnod *)endstak(s2));
275 }
276
277 void
makearg(struct argnod * args)278 makearg(struct argnod *args)
279 {
280 args->argnxt = gchain;
281 gchain = args;
282 }
283