1 /* 2 3 * Copyright (c) 1984, 1985, 1986 AT&T 4 * All Rights Reserved 5 6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE 7 * CODE OF AT&T. 8 * The copyright notice above does not 9 * evidence any actual or intended 10 * publication of such source code. 11 12 */ 13 /* @(#)expand.c 1.1 */ 14 /* 15 * UNIX shell 16 * 17 * S. R. Bourne 18 * Rewritten by David Korn 19 * AT&T Bell Laboratories 20 * 21 */ 22 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 #include <sys/dir.h> 26 #include "defs.h" 27 #include "brkincr.h" 28 #include "stak.h" 29 #include "sym.h" 30 #include "shtype.h" 31 32 void rm_files(); 33 int expand(); 34 35 extern STKPTR locstak(),endstak(); 36 extern FILE *fdopen(); 37 extern char *movstr(); 38 extern char *strrchr(); 39 extern void trim(); 40 41 42 /* globals (file name generation) 43 * 44 * "*" in params matches r.e ".*" 45 * "?" in params matches r.e. "." 46 * "[...]" in params matches character class 47 * "[...a-z...]" in params matches a through z. 48 * 49 */ 50 51 static void addg(); 52 53 int expand(as,rcnt) 54 char *as; 55 { 56 int count; 57 #ifdef BSD_4_2 58 DIR *dirf; 59 #else 60 FILE *dirf; 61 #endif /* BSD_4_2 */ 62 BOOL nometa=0; 63 BOOL dir=0; 64 char *rescan = 0; 65 char *slashsav = 0; 66 register char *s, *cs; 67 int quote = 0; 68 int slash; 69 int add_slash = 1; /* insert a separator slash */ 70 char *sname; 71 ARGPTR schain = gchain; 72 /* this union forces enough space for the NULL byte */ 73 union Dirent 74 { 75 struct direct entry; 76 char entrybuf[sizeof(struct direct)+1]; /* room for null byte */ 77 }; 78 union Dirent dirent; 79 struct direct *entry = &dirent.entry; 80 #ifndef BSD_4_2 81 char dirbuff[BUFSIZ]; 82 #endif /* BSD_4_2 */ 83 if(trapnote&SIGSET) 84 return(0); 85 s=cs=as; 86 #ifndef BSD_4_2 87 entry->d_name[DIRSIZ]=0; /* to end the string */ 88 #endif /* BSD_4_2 */ 89 /* check for meta chars */ 90 { 91 register int open = 0; 92 slash=0; 93 do 94 { 95 switch(*cs++) 96 { 97 case 0: 98 { 99 nometa = '/'; 100 if (rcnt && slash) 101 break; 102 else 103 return(0); 104 } 105 106 case '/': 107 slash++; 108 open = 0; 109 continue; 110 111 case '[': 112 open++; 113 continue; 114 115 case ']': 116 if(open) 117 break; 118 continue; 119 120 case '?': 121 case '*': 122 if(rcnt > slash) 123 continue; 124 cs--; 125 break; 126 127 case ESCAPE: 128 quote++; 129 cs++; 130 default: 131 continue; 132 } 133 break; 134 } 135 while(1); 136 } 137 while(1) 138 { 139 if(cs==s) 140 { 141 s=nullstr; 142 break; 143 } 144 else if(*--cs == '/') 145 { 146 *cs=nometa; 147 if(s==cs) 148 { 149 s= "/"; 150 add_slash = 0; 151 } 152 break; 153 } 154 } 155 if(quote && s!=cs) 156 { 157 s = cpystak(s); 158 trim(s); 159 } 160 /* special case where there are no meta-chars left in path */ 161 if(nometa) 162 { 163 /* read permission on directories not needed */ 164 if(access(s,0)==0) 165 { 166 addg(s,nullstr,NIL,0); 167 return(1); 168 } 169 return(0); 170 } 171 sname = (*s?s:dot); 172 if(ftype(sname,S_IFMT,S_IFDIR) 173 #ifdef BSD_4_2 174 && (dirf=opendir(sname))!=NULL) 175 #else 176 && (dirf=fdopen(open(sname,0),"r"))!=NULL) 177 #endif /* BSD_4_2 */ 178 { 179 dir++; 180 #ifndef BSD_4_2 181 setbuf(dirf,dirbuff); 182 #endif 183 } 184 count=0; 185 if(*cs==0) 186 slashsav = cs++; 187 if(dir) 188 /* check for rescan */ 189 { 190 register char *rs = cs; 191 do 192 { 193 if(*rs=='/') 194 { 195 rescan=rs; 196 *rs=0; 197 gchain=0; 198 } 199 } 200 while(*rs++); 201 #ifdef BSD_4_2 202 while((entry=readdir(dirf)) && (trapnote&SIGSET)==0) 203 #else 204 while(fread((char*)entry,sizeof(struct direct),1,dirf)==1 && (trapnote&SIGSET)==0) 205 #endif /* BSD_4_2 */ 206 { 207 if(entry->d_ino==0 || (*entry->d_name=='.' && *cs!='.')) 208 continue; 209 210 if(gmatch(entry->d_name, cs)) 211 { 212 addg(s,entry->d_name,rescan,add_slash); 213 count++; 214 } 215 } 216 #ifdef BSD_4_2 217 closedir(dirf); 218 #else 219 closefd(dirf); 220 #endif /* BSD_4_2 */ 221 if(rescan) 222 { 223 register ARGPTR rchain; 224 rchain=gchain; gchain=schain; 225 if(count) 226 { 227 count=0; 228 while(rchain) 229 { 230 count += expand(rchain->argval,slash+1); 231 rchain=rchain->argchn; 232 } 233 } 234 *rescan='/'; 235 } 236 } 237 if(slashsav) 238 *slashsav = '/'; 239 return(count); 240 } 241 242 static void addg(as1,as2,as3,add_slash) 243 char *as1, *as2, *as3; 244 int add_slash; 245 { 246 register char *s1, *s2; 247 register int c; 248 register ARGPTR argp = (ARGPTR)locstak(); 249 argp->argflag &= ~(A_MAKE|A_RAW); 250 s2 = argp->argval; 251 s1=as1; 252 /* directory */ 253 while(c = *s1) 254 { 255 s1++; 256 if(c == ESCAPE) 257 *s2++ = ESCAPE; 258 *s2++ = c; 259 } 260 if(add_slash && s1 > as1 && *as2) 261 *s2++='/'; 262 s1=as2; 263 /* component */ 264 while(c = *s1++) 265 { 266 /* escape the ESCAPE characters */ 267 if(c == ESCAPE) 268 *s2++ = ESCAPE; 269 *s2++ = c; 270 } 271 /* rescan */ 272 if(s1=as3) 273 { 274 *s2++='/'; 275 while(*s2++ = *++s1); 276 } 277 if(is_option(MARKDIR)) 278 { 279 *s2 = 0; 280 if(ftype(argp->argval,S_IFMT,S_IFDIR)) 281 *s2++ = '/'; 282 } 283 endstak(s2); 284 argp->argchn= gchain; 285 gchain = argp; 286 } 287 288 289 /* 290 * remove tmp files 291 * template of the form /tmp/sh$$.??? 292 */ 293 294 void rm_files(template) 295 register char *template; 296 { 297 register char *cp; 298 ARGPTR schain; 299 cp = strrchr(template,'.'); 300 *(cp+1) = 0; 301 f_complete(template,"*"); 302 schain = gchain; 303 while(schain) 304 { 305 unlink(schain->argval); 306 schain = schain->argchn; 307 } 308 } 309 310 /* 311 * file name completion 312 * generate the list of files found by adding an suffix to end of name 313 * The number of matches is returned 314 */ 315 316 f_complete(name,suffix) 317 char *name; 318 register char *suffix; 319 { 320 register char *cp; 321 register char *dp; 322 gchain = NULL; 323 dp = (char*)locstak(); 324 cp = movstr(name,dp); 325 if(suffix) 326 cp = movstr(suffix,cp); 327 endstak(cp); 328 return(expand(dp,0)); 329 } 330