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 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 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 277 makearg(struct argnod *args) 278 { 279 args->argnxt = gchain; 280 gchain = args; 281 } 282