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 */
52static void addg(unsigned char *, unsigned char *, unsigned char *,
53    unsigned char *);
54void makearg(struct argnod *);
55
56int
57expand(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
207static void
208addg(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
277void
278makearg(struct argnod *args)
279{
280	args->argnxt = gchain;
281	gchain = args;
282}
283