1 1.32 nia /* $NetBSD: glob.c,v 1.32 2024/04/24 15:49:03 nia Exp $ */ 2 1.10 cgd 3 1.1 cgd /*- 4 1.8 mycroft * Copyright (c) 1980, 1991, 1993 5 1.8 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.22 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.12 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.10 cgd #if 0 35 1.10 cgd static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93"; 36 1.10 cgd #else 37 1.32 nia __RCSID("$NetBSD: glob.c,v 1.32 2024/04/24 15:49:03 nia Exp $"); 38 1.10 cgd #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #include <sys/param.h> 42 1.18 wiz 43 1.18 wiz #include <errno.h> 44 1.1 cgd #include <glob.h> 45 1.21 wiz #include <stdarg.h> 46 1.27 christos #include <stddef.h> 47 1.1 cgd #include <stdlib.h> 48 1.1 cgd #include <string.h> 49 1.1 cgd #include <unistd.h> 50 1.1 cgd 51 1.1 cgd #include "csh.h" 52 1.1 cgd #include "extern.h" 53 1.1 cgd 54 1.8 mycroft static int noglob; 55 1.18 wiz static int gargsiz, pargsiz; 56 1.1 cgd 57 1.1 cgd /* 58 1.1 cgd * Values for gflag 59 1.1 cgd */ 60 1.18 wiz #define G_NONE 0 /* No globbing needed */ 61 1.18 wiz #define G_GLOB 1 /* string contains *?[] characters */ 62 1.18 wiz #define G_CSH 2 /* string contains ~`{ characters */ 63 1.1 cgd 64 1.18 wiz #define GLOBSPACE 100 /* Alloc increment */ 65 1.1 cgd 66 1.1 cgd #define LBRC '{' 67 1.1 cgd #define RBRC '}' 68 1.1 cgd #define LBRK '[' 69 1.1 cgd #define RBRK ']' 70 1.1 cgd #define EOS '\0' 71 1.1 cgd 72 1.18 wiz Char **gargv = NULL; 73 1.18 wiz Char **pargv = NULL; 74 1.18 wiz long gargc = 0; 75 1.18 wiz long pargc = 0; 76 1.1 cgd 77 1.1 cgd /* 78 1.1 cgd * globbing is now done in two stages. In the first pass we expand 79 1.1 cgd * csh globbing idioms ~`{ and then we proceed doing the normal 80 1.1 cgd * globbing if needed ?*[ 81 1.1 cgd * 82 1.1 cgd * Csh type globbing is handled in globexpand() and the rest is 83 1.1 cgd * handled in glob() which is part of the 4.4BSD libc. 84 1.1 cgd * 85 1.1 cgd */ 86 1.18 wiz static Char *globtilde(Char **, Char *); 87 1.18 wiz static Char *handleone(Char *, Char **, int); 88 1.18 wiz static Char **libglob(Char **); 89 1.18 wiz static Char **globexpand(Char **); 90 1.18 wiz static int globbrace(Char *, Char *, Char ***); 91 1.27 christos static void expbrace(Char ***, Char ***, size_t); 92 1.28 christos static int pmatch(const Char *, const Char *); 93 1.18 wiz static void pword(void); 94 1.18 wiz static void psave(int); 95 1.25 christos static void backeval(Char *, int); 96 1.1 cgd 97 1.1 cgd static Char * 98 1.18 wiz globtilde(Char **nv, Char *s) 99 1.1 cgd { 100 1.18 wiz Char gbuf[MAXPATHLEN], *b, *e, *gstart, *u; 101 1.1 cgd 102 1.1 cgd gstart = gbuf; 103 1.1 cgd *gstart++ = *s++; 104 1.1 cgd u = s; 105 1.8 mycroft for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; 106 1.8 mycroft *s && *s != '/' && *s != ':' && b < e; 107 1.8 mycroft *b++ = *s++) 108 1.8 mycroft continue; 109 1.1 cgd *b = EOS; 110 1.1 cgd if (gethdir(gstart)) { 111 1.1 cgd blkfree(nv); 112 1.1 cgd if (*gstart) 113 1.8 mycroft stderror(ERR_UNKUSER, vis_str(gstart)); 114 1.1 cgd else 115 1.1 cgd stderror(ERR_NOHOME); 116 1.1 cgd } 117 1.1 cgd b = &gstart[Strlen(gstart)]; 118 1.1 cgd while (*s) 119 1.1 cgd *b++ = *s++; 120 1.1 cgd *b = EOS; 121 1.1 cgd --u; 122 1.30 christos free(u); 123 1.1 cgd return (Strsave(gstart)); 124 1.1 cgd } 125 1.1 cgd 126 1.1 cgd static int 127 1.18 wiz globbrace(Char *s, Char *p, Char ***bl) 128 1.1 cgd { 129 1.18 wiz Char gbuf[MAXPATHLEN]; 130 1.18 wiz Char *lm, *pe, *pl, *pm, **nv, **vl; 131 1.18 wiz int i, len, size; 132 1.1 cgd 133 1.18 wiz size = GLOBSPACE; 134 1.32 nia nv = vl = xreallocarray(NULL, sizeof(Char *), (size_t)size); 135 1.1 cgd *vl = NULL; 136 1.1 cgd len = 0; 137 1.1 cgd /* copy part up to the brace */ 138 1.1 cgd for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) 139 1.1 cgd continue; 140 1.1 cgd 141 1.1 cgd /* check for balanced braces */ 142 1.1 cgd for (i = 0, pe = ++p; *pe; pe++) 143 1.1 cgd if (*pe == LBRK) { 144 1.1 cgd /* Ignore everything between [] */ 145 1.1 cgd for (++pe; *pe != RBRK && *pe != EOS; pe++) 146 1.1 cgd continue; 147 1.1 cgd if (*pe == EOS) { 148 1.1 cgd blkfree(nv); 149 1.8 mycroft return (-RBRK); 150 1.1 cgd } 151 1.1 cgd } 152 1.1 cgd else if (*pe == LBRC) 153 1.1 cgd i++; 154 1.1 cgd else if (*pe == RBRC) { 155 1.1 cgd if (i == 0) 156 1.1 cgd break; 157 1.1 cgd i--; 158 1.1 cgd } 159 1.1 cgd 160 1.6 cgd if (i != 0 || *pe == '\0') { 161 1.1 cgd blkfree(nv); 162 1.6 cgd return (-RBRC); 163 1.1 cgd } 164 1.1 cgd 165 1.1 cgd for (i = 0, pl = pm = p; pm <= pe; pm++) 166 1.1 cgd switch (*pm) { 167 1.1 cgd case LBRK: 168 1.1 cgd for (++pm; *pm != RBRK && *pm != EOS; pm++) 169 1.1 cgd continue; 170 1.1 cgd if (*pm == EOS) { 171 1.1 cgd *vl = NULL; 172 1.1 cgd blkfree(nv); 173 1.1 cgd return (-RBRK); 174 1.1 cgd } 175 1.1 cgd break; 176 1.1 cgd case LBRC: 177 1.1 cgd i++; 178 1.1 cgd break; 179 1.1 cgd case RBRC: 180 1.1 cgd if (i) { 181 1.1 cgd i--; 182 1.1 cgd break; 183 1.1 cgd } 184 1.1 cgd /* FALLTHROUGH */ 185 1.1 cgd case ',': 186 1.1 cgd if (i && *pm == ',') 187 1.1 cgd break; 188 1.1 cgd else { 189 1.1 cgd Char savec = *pm; 190 1.1 cgd 191 1.1 cgd *pm = EOS; 192 1.18 wiz (void)Strcpy(lm, pl); 193 1.18 wiz (void)Strcat(gbuf, pe + 1); 194 1.1 cgd *pm = savec; 195 1.1 cgd *vl++ = Strsave(gbuf); 196 1.1 cgd len++; 197 1.1 cgd pl = pm + 1; 198 1.1 cgd if (vl == &nv[size]) { 199 1.1 cgd size += GLOBSPACE; 200 1.32 nia nv = xreallocarray(nv, (size_t)size, sizeof(Char *)); 201 1.1 cgd vl = &nv[size - GLOBSPACE]; 202 1.1 cgd } 203 1.1 cgd } 204 1.1 cgd break; 205 1.8 mycroft default: 206 1.8 mycroft break; 207 1.1 cgd } 208 1.1 cgd *vl = NULL; 209 1.1 cgd *bl = nv; 210 1.1 cgd return (len); 211 1.1 cgd } 212 1.1 cgd 213 1.8 mycroft static void 214 1.27 christos expbrace(Char ***nvp, Char ***elp, size_t size) 215 1.8 mycroft { 216 1.26 christos Char **ex, **nv, *s, **vl; 217 1.8 mycroft 218 1.8 mycroft vl = nv = *nvp; 219 1.8 mycroft if (elp != NULL) 220 1.26 christos ex = *elp; 221 1.8 mycroft else 222 1.26 christos for (ex = vl; *ex; ex++) 223 1.8 mycroft continue; 224 1.8 mycroft 225 1.8 mycroft for (s = *vl; s; s = *++vl) { 226 1.18 wiz Char *b, **bp, **vp; 227 1.8 mycroft 228 1.8 mycroft /* leave {} untouched for find */ 229 1.8 mycroft if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 230 1.8 mycroft continue; 231 1.8 mycroft if ((b = Strchr(s, '{')) != NULL) { 232 1.18 wiz Char **bl; 233 1.18 wiz int len; 234 1.8 mycroft 235 1.8 mycroft if ((len = globbrace(s, b, &bl)) < 0) { 236 1.30 christos free(nv); 237 1.8 mycroft stderror(ERR_MISSING, -len); 238 1.8 mycroft } 239 1.30 christos free(s); 240 1.8 mycroft if (len == 1) { 241 1.8 mycroft *vl-- = *bl; 242 1.30 christos free(bl); 243 1.8 mycroft continue; 244 1.8 mycroft } 245 1.8 mycroft len = blklen(bl); 246 1.26 christos if (&ex[len] >= &nv[size]) { 247 1.27 christos ptrdiff_t l, e; 248 1.8 mycroft 249 1.26 christos l = &ex[len] - &nv[size]; 250 1.27 christos size += (size_t)(GLOBSPACE > l ? GLOBSPACE : l); 251 1.8 mycroft l = vl - nv; 252 1.26 christos e = ex - nv; 253 1.32 nia nv = xreallocarray(nv, size, sizeof(Char *)); 254 1.8 mycroft vl = nv + l; 255 1.26 christos ex = nv + e; 256 1.8 mycroft } 257 1.8 mycroft vp = vl--; 258 1.8 mycroft *vp = *bl; 259 1.8 mycroft len--; 260 1.26 christos for (bp = ex; bp != vp; bp--) 261 1.8 mycroft bp[len] = *bp; 262 1.26 christos ex += len; 263 1.8 mycroft vp++; 264 1.8 mycroft for (bp = bl + 1; *bp; *vp++ = *bp++) 265 1.8 mycroft continue; 266 1.30 christos free(bl); 267 1.8 mycroft } 268 1.8 mycroft 269 1.8 mycroft } 270 1.8 mycroft if (elp != NULL) 271 1.26 christos *elp = ex; 272 1.8 mycroft *nvp = nv; 273 1.8 mycroft } 274 1.8 mycroft 275 1.1 cgd static Char ** 276 1.18 wiz globexpand(Char **v) 277 1.1 cgd { 278 1.26 christos Char **ex, **nv, *s, **vl; 279 1.27 christos size_t size; 280 1.1 cgd 281 1.18 wiz size = GLOBSPACE; 282 1.32 nia nv = vl = xreallocarray(NULL, sizeof(Char *), size); 283 1.1 cgd *vl = NULL; 284 1.1 cgd 285 1.1 cgd /* 286 1.1 cgd * Step 1: expand backquotes. 287 1.1 cgd */ 288 1.8 mycroft while ((s = *v++) != NULL) { 289 1.1 cgd if (Strchr(s, '`')) { 290 1.18 wiz int i; 291 1.1 cgd 292 1.1 cgd (void) dobackp(s, 0); 293 1.1 cgd for (i = 0; i < pargc; i++) { 294 1.1 cgd *vl++ = pargv[i]; 295 1.1 cgd if (vl == &nv[size]) { 296 1.1 cgd size += GLOBSPACE; 297 1.32 nia nv = xreallocarray(nv, size, sizeof(Char *)); 298 1.1 cgd vl = &nv[size - GLOBSPACE]; 299 1.1 cgd } 300 1.1 cgd } 301 1.30 christos free(pargv); 302 1.1 cgd pargv = NULL; 303 1.1 cgd } 304 1.1 cgd else { 305 1.1 cgd *vl++ = Strsave(s); 306 1.1 cgd if (vl == &nv[size]) { 307 1.1 cgd size += GLOBSPACE; 308 1.32 nia nv = xreallocarray(nv, size, sizeof(Char *)); 309 1.1 cgd vl = &nv[size - GLOBSPACE]; 310 1.1 cgd } 311 1.1 cgd } 312 1.1 cgd } 313 1.1 cgd *vl = NULL; 314 1.1 cgd 315 1.1 cgd if (noglob) 316 1.1 cgd return (nv); 317 1.1 cgd 318 1.1 cgd /* 319 1.1 cgd * Step 2: expand braces 320 1.1 cgd */ 321 1.26 christos ex = vl; 322 1.26 christos expbrace(&nv, &ex, size); 323 1.1 cgd 324 1.1 cgd /* 325 1.1 cgd * Step 3: expand ~ 326 1.1 cgd */ 327 1.1 cgd vl = nv; 328 1.1 cgd for (s = *vl; s; s = *++vl) 329 1.1 cgd if (*s == '~') 330 1.1 cgd *vl = globtilde(nv, s); 331 1.1 cgd vl = nv; 332 1.1 cgd return (vl); 333 1.1 cgd } 334 1.1 cgd 335 1.1 cgd static Char * 336 1.18 wiz handleone(Char *str, Char **vl, int action) 337 1.1 cgd { 338 1.18 wiz Char *cp, **vlp; 339 1.1 cgd 340 1.18 wiz vlp = vl; 341 1.1 cgd switch (action) { 342 1.1 cgd case G_ERROR: 343 1.8 mycroft setname(vis_str(str)); 344 1.1 cgd blkfree(vl); 345 1.1 cgd stderror(ERR_NAME | ERR_AMBIG); 346 1.15 mycroft /* NOTREACHED */ 347 1.1 cgd case G_APPEND: 348 1.1 cgd trim(vlp); 349 1.1 cgd str = Strsave(*vlp++); 350 1.1 cgd do { 351 1.1 cgd cp = Strspl(str, STRspace); 352 1.30 christos free(str); 353 1.1 cgd str = Strspl(cp, *vlp); 354 1.30 christos free(cp); 355 1.1 cgd } 356 1.1 cgd while (*++vlp); 357 1.1 cgd blkfree(vl); 358 1.1 cgd break; 359 1.1 cgd case G_IGNORE: 360 1.1 cgd str = Strsave(strip(*vlp)); 361 1.1 cgd blkfree(vl); 362 1.1 cgd break; 363 1.8 mycroft default: 364 1.8 mycroft break; 365 1.1 cgd } 366 1.1 cgd return (str); 367 1.1 cgd } 368 1.1 cgd 369 1.1 cgd static Char ** 370 1.18 wiz libglob(Char **vl) 371 1.1 cgd { 372 1.18 wiz glob_t globv; 373 1.18 wiz char *ptr; 374 1.18 wiz int gflgs, magic, match, nonomatch; 375 1.18 wiz 376 1.18 wiz gflgs = GLOB_NOMAGIC; 377 1.18 wiz magic = 0; 378 1.18 wiz match = 0; 379 1.18 wiz nonomatch = adrof(STRnonomatch) != 0; 380 1.8 mycroft 381 1.8 mycroft if (!vl || !vl[0]) 382 1.8 mycroft return (vl); 383 1.1 cgd 384 1.1 cgd globv.gl_offs = 0; 385 1.1 cgd globv.gl_pathv = 0; 386 1.1 cgd globv.gl_pathc = 0; 387 1.8 mycroft 388 1.8 mycroft if (nonomatch) 389 1.8 mycroft gflgs |= GLOB_NOCHECK; 390 1.8 mycroft 391 1.1 cgd do { 392 1.1 cgd ptr = short2qstr(*vl); 393 1.1 cgd switch (glob(ptr, gflgs, 0, &globv)) { 394 1.13 kleink case GLOB_ABORTED: 395 1.8 mycroft setname(vis_str(*vl)); 396 1.1 cgd stderror(ERR_NAME | ERR_GLOB); 397 1.1 cgd /* NOTREACHED */ 398 1.1 cgd case GLOB_NOSPACE: 399 1.1 cgd stderror(ERR_NOMEM); 400 1.1 cgd /* NOTREACHED */ 401 1.1 cgd default: 402 1.1 cgd break; 403 1.1 cgd } 404 1.8 mycroft if (globv.gl_flags & GLOB_MAGCHAR) { 405 1.8 mycroft match |= (globv.gl_matchc != 0); 406 1.8 mycroft magic = 1; 407 1.8 mycroft } 408 1.1 cgd gflgs |= GLOB_APPEND; 409 1.1 cgd } 410 1.1 cgd while (*++vl); 411 1.8 mycroft vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 412 1.8 mycroft NULL : blk2short(globv.gl_pathv); 413 1.1 cgd globfree(&globv); 414 1.1 cgd return (vl); 415 1.1 cgd } 416 1.1 cgd 417 1.18 wiz Char * 418 1.18 wiz globone(Char *str, int action) 419 1.1 cgd { 420 1.18 wiz Char *v[2], **vl, **vo; 421 1.18 wiz int gflg; 422 1.1 cgd 423 1.1 cgd noglob = adrof(STRnoglob) != 0; 424 1.1 cgd gflag = 0; 425 1.1 cgd v[0] = str; 426 1.1 cgd v[1] = 0; 427 1.1 cgd tglob(v); 428 1.8 mycroft gflg = gflag; 429 1.8 mycroft if (gflg == G_NONE) 430 1.1 cgd return (strip(Strsave(str))); 431 1.1 cgd 432 1.8 mycroft if (gflg & G_CSH) { 433 1.1 cgd /* 434 1.1 cgd * Expand back-quote, tilde and brace 435 1.1 cgd */ 436 1.1 cgd vo = globexpand(v); 437 1.8 mycroft if (noglob || (gflg & G_GLOB) == 0) { 438 1.1 cgd if (vo[0] == NULL) { 439 1.30 christos free(vo); 440 1.1 cgd return (Strsave(STRNULL)); 441 1.1 cgd } 442 1.1 cgd if (vo[1] != NULL) 443 1.1 cgd return (handleone(str, vo, action)); 444 1.1 cgd else { 445 1.1 cgd str = strip(vo[0]); 446 1.30 christos free(vo); 447 1.1 cgd return (str); 448 1.1 cgd } 449 1.1 cgd } 450 1.1 cgd } 451 1.8 mycroft else if (noglob || (gflg & G_GLOB) == 0) 452 1.1 cgd return (strip(Strsave(str))); 453 1.1 cgd else 454 1.1 cgd vo = v; 455 1.1 cgd 456 1.1 cgd vl = libglob(vo); 457 1.8 mycroft if ((gflg & G_CSH) && vl != vo) 458 1.1 cgd blkfree(vo); 459 1.1 cgd if (vl == NULL) { 460 1.8 mycroft setname(vis_str(str)); 461 1.1 cgd stderror(ERR_NAME | ERR_NOMATCH); 462 1.1 cgd } 463 1.1 cgd if (vl[0] == NULL) { 464 1.30 christos free(vl); 465 1.1 cgd return (Strsave(STRNULL)); 466 1.1 cgd } 467 1.1 cgd if (vl[1] != NULL) 468 1.1 cgd return (handleone(str, vl, action)); 469 1.1 cgd else { 470 1.1 cgd str = strip(*vl); 471 1.30 christos free(vl); 472 1.1 cgd return (str); 473 1.1 cgd } 474 1.1 cgd } 475 1.1 cgd 476 1.1 cgd Char ** 477 1.18 wiz globall(Char **v) 478 1.1 cgd { 479 1.18 wiz Char **vl, **vo; 480 1.18 wiz int gflg; 481 1.1 cgd 482 1.18 wiz gflg = gflag; 483 1.1 cgd if (!v || !v[0]) { 484 1.1 cgd gargv = saveblk(v); 485 1.1 cgd gargc = blklen(gargv); 486 1.1 cgd return (gargv); 487 1.1 cgd } 488 1.1 cgd 489 1.1 cgd noglob = adrof(STRnoglob) != 0; 490 1.1 cgd 491 1.8 mycroft if (gflg & G_CSH) 492 1.1 cgd /* 493 1.1 cgd * Expand back-quote, tilde and brace 494 1.1 cgd */ 495 1.1 cgd vl = vo = globexpand(v); 496 1.1 cgd else 497 1.1 cgd vl = vo = saveblk(v); 498 1.1 cgd 499 1.9 mycroft if (!noglob && (gflg & G_GLOB)) { 500 1.1 cgd vl = libglob(vo); 501 1.8 mycroft if ((gflg & G_CSH) && vl != vo) 502 1.1 cgd blkfree(vo); 503 1.1 cgd } 504 1.8 mycroft else 505 1.8 mycroft trim(vl); 506 1.1 cgd 507 1.1 cgd gargc = vl ? blklen(vl) : 0; 508 1.1 cgd return (gargv = vl); 509 1.1 cgd } 510 1.1 cgd 511 1.1 cgd void 512 1.18 wiz ginit(void) 513 1.1 cgd { 514 1.1 cgd gargsiz = GLOBSPACE; 515 1.32 nia gargv = xreallocarray(NULL, sizeof(Char *), (size_t)gargsiz); 516 1.1 cgd gargv[0] = 0; 517 1.1 cgd gargc = 0; 518 1.1 cgd } 519 1.1 cgd 520 1.1 cgd void 521 1.18 wiz rscan(Char **t, void (*f)(int)) 522 1.1 cgd { 523 1.11 tls Char *p; 524 1.1 cgd 525 1.8 mycroft while ((p = *t++) != NULL) 526 1.1 cgd while (*p) 527 1.1 cgd (*f) (*p++); 528 1.1 cgd } 529 1.1 cgd 530 1.1 cgd void 531 1.18 wiz trim(Char **t) 532 1.1 cgd { 533 1.11 tls Char *p; 534 1.1 cgd 535 1.8 mycroft while ((p = *t++) != NULL) 536 1.1 cgd while (*p) 537 1.1 cgd *p++ &= TRIM; 538 1.1 cgd } 539 1.1 cgd 540 1.1 cgd void 541 1.18 wiz tglob(Char **t) 542 1.1 cgd { 543 1.11 tls Char *p, c; 544 1.1 cgd 545 1.8 mycroft while ((p = *t++) != NULL) { 546 1.1 cgd if (*p == '~' || *p == '=') 547 1.1 cgd gflag |= G_CSH; 548 1.1 cgd else if (*p == '{' && 549 1.8 mycroft (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 550 1.1 cgd continue; 551 1.8 mycroft while ((c = *p++) != '\0') { 552 1.8 mycroft /* 553 1.8 mycroft * eat everything inside the matching backquotes 554 1.8 mycroft */ 555 1.8 mycroft if (c == '`') { 556 1.8 mycroft gflag |= G_CSH; 557 1.8 mycroft while (*p && *p != '`') 558 1.8 mycroft if (*p++ == '\\') { 559 1.8 mycroft if (*p) /* Quoted chars */ 560 1.8 mycroft p++; 561 1.8 mycroft else 562 1.8 mycroft break; 563 1.8 mycroft } 564 1.8 mycroft if (*p) /* The matching ` */ 565 1.8 mycroft p++; 566 1.8 mycroft else 567 1.8 mycroft break; 568 1.8 mycroft } 569 1.8 mycroft else if (c == '{') 570 1.8 mycroft gflag |= G_CSH; 571 1.8 mycroft else if (isglob(c)) 572 1.8 mycroft gflag |= G_GLOB; 573 1.8 mycroft } 574 1.1 cgd } 575 1.1 cgd } 576 1.1 cgd 577 1.1 cgd /* 578 1.1 cgd * Command substitute cp. If literal, then this is a substitution from a 579 1.1 cgd * << redirection, and so we should not crunch blanks and tabs, separating 580 1.1 cgd * words only at newlines. 581 1.1 cgd */ 582 1.18 wiz Char ** 583 1.25 christos dobackp(Char *cp, int literal) 584 1.1 cgd { 585 1.18 wiz Char word[MAXPATHLEN], *ep, *lp, *rp; 586 1.1 cgd 587 1.1 cgd if (pargv) { 588 1.8 mycroft #ifdef notdef 589 1.1 cgd abort(); 590 1.8 mycroft #endif 591 1.1 cgd blkfree(pargv); 592 1.1 cgd } 593 1.1 cgd pargsiz = GLOBSPACE; 594 1.32 nia pargv = xreallocarray(NULL, sizeof(Char *), (size_t)pargsiz); 595 1.1 cgd pargv[0] = NULL; 596 1.1 cgd pargcp = pargs = word; 597 1.1 cgd pargc = 0; 598 1.1 cgd pnleft = MAXPATHLEN - 4; 599 1.1 cgd for (;;) { 600 1.1 cgd for (lp = cp; *lp != '`'; lp++) { 601 1.1 cgd if (*lp == 0) { 602 1.1 cgd if (pargcp != pargs) 603 1.1 cgd pword(); 604 1.1 cgd return (pargv); 605 1.1 cgd } 606 1.1 cgd psave(*lp); 607 1.1 cgd } 608 1.1 cgd lp++; 609 1.1 cgd for (rp = lp; *rp && *rp != '`'; rp++) 610 1.1 cgd if (*rp == '\\') { 611 1.1 cgd rp++; 612 1.1 cgd if (!*rp) 613 1.1 cgd goto oops; 614 1.1 cgd } 615 1.15 mycroft if (!*rp) { 616 1.15 mycroft oops: 617 1.15 mycroft stderror(ERR_UNMATCHED, '`'); 618 1.15 mycroft } 619 1.1 cgd ep = Strsave(lp); 620 1.1 cgd ep[rp - lp] = 0; 621 1.1 cgd backeval(ep, literal); 622 1.1 cgd cp = rp + 1; 623 1.1 cgd } 624 1.1 cgd } 625 1.1 cgd 626 1.1 cgd static void 627 1.25 christos backeval(Char *cp, int literal) 628 1.1 cgd { 629 1.1 cgd struct command faket; 630 1.18 wiz char tibuf[BUFSIZE]; 631 1.18 wiz Char ibuf[BUFSIZE], *fakecom[2], *ip; 632 1.27 christos int pvec[2], c, quoted; 633 1.27 christos ssize_t icnt; 634 1.25 christos int hadnl; 635 1.1 cgd 636 1.1 cgd hadnl = 0; 637 1.1 cgd icnt = 0; 638 1.1 cgd quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 639 1.1 cgd faket.t_dtyp = NODE_COMMAND; 640 1.1 cgd faket.t_dflg = 0; 641 1.1 cgd faket.t_dlef = 0; 642 1.1 cgd faket.t_drit = 0; 643 1.1 cgd faket.t_dspr = 0; 644 1.1 cgd faket.t_dcom = fakecom; 645 1.1 cgd fakecom[0] = STRfakecom1; 646 1.1 cgd fakecom[1] = 0; 647 1.1 cgd 648 1.1 cgd /* 649 1.1 cgd * We do the psave job to temporarily change the current job so that the 650 1.1 cgd * following fork is considered a separate job. This is so that when 651 1.1 cgd * backquotes are used in a builtin function that calls glob the "current 652 1.1 cgd * job" is not corrupted. We only need one level of pushed jobs as long as 653 1.1 cgd * we are sure to fork here. 654 1.1 cgd */ 655 1.1 cgd psavejob(); 656 1.1 cgd 657 1.1 cgd /* 658 1.1 cgd * It would be nicer if we could integrate this redirection more with the 659 1.1 cgd * routines in sh.sem.c by doing a fake execute on a builtin function that 660 1.1 cgd * was piped out. 661 1.1 cgd */ 662 1.1 cgd mypipe(pvec); 663 1.1 cgd if (pfork(&faket, -1) == 0) { 664 1.19 lukem struct wordent fparaml; 665 1.1 cgd struct command *t; 666 1.1 cgd 667 1.18 wiz (void)close(pvec[0]); 668 1.18 wiz (void)dmove(pvec[1], 1); 669 1.18 wiz (void)dmove(SHERR, 2); 670 1.1 cgd initdesc(); 671 1.1 cgd /* 672 1.1 cgd * Bugfix for nested backquotes by Michael Greim <greim (at) sbsvax.UUCP>, 673 1.1 cgd * posted to comp.bugs.4bsd 12 Sep. 1989. 674 1.1 cgd */ 675 1.1 cgd if (pargv) /* mg, 21.dec.88 */ 676 1.1 cgd blkfree(pargv), pargv = 0, pargsiz = 0; 677 1.1 cgd /* mg, 21.dec.88 */ 678 1.1 cgd arginp = cp; 679 1.20 christos for (arginp = cp; *cp; cp++) { 680 1.20 christos *cp &= TRIM; 681 1.20 christos if (*cp == '\n' || *cp == '\r') 682 1.20 christos *cp = ';'; 683 1.20 christos } 684 1.8 mycroft 685 1.8 mycroft /* 686 1.8 mycroft * In the child ``forget'' everything about current aliases or 687 1.8 mycroft * eval vectors. 688 1.8 mycroft */ 689 1.8 mycroft alvec = NULL; 690 1.8 mycroft evalvec = NULL; 691 1.8 mycroft alvecp = NULL; 692 1.8 mycroft evalp = NULL; 693 1.19 lukem (void) lex(&fparaml); 694 1.16 mycroft if (seterr) 695 1.1 cgd stderror(ERR_OLD); 696 1.19 lukem alias(&fparaml); 697 1.19 lukem t = syntax(fparaml.next, &fparaml, 0); 698 1.16 mycroft if (seterr) 699 1.1 cgd stderror(ERR_OLD); 700 1.1 cgd if (t) 701 1.1 cgd t->t_dflg |= F_NOFORK; 702 1.18 wiz (void)signal(SIGTSTP, SIG_IGN); 703 1.18 wiz (void)signal(SIGTTIN, SIG_IGN); 704 1.18 wiz (void)signal(SIGTTOU, SIG_IGN); 705 1.1 cgd execute(t, -1, NULL, NULL); 706 1.1 cgd exitstat(); 707 1.1 cgd } 708 1.30 christos free(cp); 709 1.18 wiz (void)close(pvec[1]); 710 1.1 cgd c = 0; 711 1.1 cgd ip = NULL; 712 1.1 cgd do { 713 1.18 wiz int cnt; 714 1.18 wiz 715 1.18 wiz cnt = 0; 716 1.1 cgd 717 1.1 cgd for (;;) { 718 1.1 cgd if (icnt == 0) { 719 1.18 wiz int i; 720 1.1 cgd 721 1.1 cgd ip = ibuf; 722 1.1 cgd do 723 1.17 christos icnt = read(pvec[0], tibuf, BUFSIZE); 724 1.1 cgd while (icnt == -1 && errno == EINTR); 725 1.1 cgd if (icnt <= 0) { 726 1.1 cgd c = -1; 727 1.1 cgd break; 728 1.1 cgd } 729 1.1 cgd for (i = 0; i < icnt; i++) 730 1.1 cgd ip[i] = (unsigned char) tibuf[i]; 731 1.1 cgd } 732 1.1 cgd if (hadnl) 733 1.1 cgd break; 734 1.1 cgd --icnt; 735 1.1 cgd c = (*ip++ & TRIM); 736 1.1 cgd if (c == 0) 737 1.1 cgd break; 738 1.1 cgd if (c == '\n') { 739 1.1 cgd /* 740 1.1 cgd * Continue around the loop one more time, so that we can eat 741 1.1 cgd * the last newline without terminating this word. 742 1.1 cgd */ 743 1.1 cgd hadnl = 1; 744 1.1 cgd continue; 745 1.1 cgd } 746 1.1 cgd if (!quoted && (c == ' ' || c == '\t')) 747 1.1 cgd break; 748 1.1 cgd cnt++; 749 1.1 cgd psave(c | quoted); 750 1.1 cgd } 751 1.1 cgd /* 752 1.1 cgd * Unless at end-of-file, we will form a new word here if there were 753 1.1 cgd * characters in the word, or in any case when we take text literally. 754 1.1 cgd * If we didn't make empty words here when literal was set then we 755 1.1 cgd * would lose blank lines. 756 1.1 cgd */ 757 1.1 cgd if (c != -1 && (cnt || literal)) 758 1.1 cgd pword(); 759 1.1 cgd hadnl = 0; 760 1.1 cgd } while (c >= 0); 761 1.18 wiz (void)close(pvec[0]); 762 1.1 cgd pwait(); 763 1.1 cgd prestjob(); 764 1.1 cgd } 765 1.1 cgd 766 1.1 cgd static void 767 1.18 wiz psave(int c) 768 1.1 cgd { 769 1.16 mycroft if (--pnleft <= 0) 770 1.1 cgd stderror(ERR_WTOOLONG); 771 1.27 christos *pargcp++ = (Char)c; 772 1.1 cgd } 773 1.1 cgd 774 1.1 cgd static void 775 1.18 wiz pword(void) 776 1.1 cgd { 777 1.1 cgd psave(0); 778 1.1 cgd if (pargc == pargsiz - 1) { 779 1.1 cgd pargsiz += GLOBSPACE; 780 1.32 nia pargv = xreallocarray(pargv, (size_t)pargsiz, sizeof(Char *)); 781 1.1 cgd } 782 1.1 cgd pargv[pargc++] = Strsave(pargs); 783 1.1 cgd pargv[pargc] = NULL; 784 1.1 cgd pargcp = pargs; 785 1.1 cgd pnleft = MAXPATHLEN - 4; 786 1.1 cgd } 787 1.1 cgd 788 1.8 mycroft int 789 1.18 wiz Gmatch(Char *string, Char *pattern) 790 1.8 mycroft { 791 1.8 mycroft Char **blk, **p; 792 1.18 wiz int gpol, gres; 793 1.18 wiz 794 1.18 wiz gpol = 1; 795 1.18 wiz gres = 0; 796 1.8 mycroft 797 1.8 mycroft if (*pattern == '^') { 798 1.8 mycroft gpol = 0; 799 1.8 mycroft pattern++; 800 1.8 mycroft } 801 1.8 mycroft 802 1.32 nia blk = xreallocarray(NULL, GLOBSPACE, sizeof(Char *)); 803 1.8 mycroft blk[0] = Strsave(pattern); 804 1.8 mycroft blk[1] = NULL; 805 1.8 mycroft 806 1.8 mycroft expbrace(&blk, NULL, GLOBSPACE); 807 1.8 mycroft 808 1.8 mycroft for (p = blk; *p; p++) 809 1.8 mycroft gres |= pmatch(string, *p); 810 1.8 mycroft 811 1.8 mycroft blkfree(blk); 812 1.8 mycroft return(gres == gpol); 813 1.8 mycroft } 814 1.8 mycroft 815 1.8 mycroft static int 816 1.28 christos pmatch(const Char *name, const Char *pat) 817 1.1 cgd { 818 1.18 wiz int match, negate_range; 819 1.28 christos Char patc, namec, c; 820 1.28 christos const Char *nameNext, *nameStart, *nameEnd, *patNext; 821 1.1 cgd 822 1.28 christos nameNext = nameStart = name; 823 1.28 christos patNext = pat; 824 1.28 christos nameEnd = NULL; 825 1.28 christos 826 1.28 christos for (;;) { 827 1.28 christos namec = *name & TRIM; 828 1.28 christos if (namec == 0) 829 1.28 christos nameEnd = name; 830 1.28 christos patc = *pat; 831 1.28 christos switch (patc) { 832 1.1 cgd case 0: 833 1.28 christos if (namec == 0) 834 1.28 christos return 1; 835 1.28 christos break; 836 1.1 cgd case '?': 837 1.28 christos if (namec == 0) 838 1.28 christos break; 839 1.28 christos pat++; 840 1.28 christos name++; 841 1.28 christos continue; 842 1.1 cgd case '*': 843 1.28 christos while ((pat[1] & TRIM) == '*') 844 1.28 christos pat++; 845 1.28 christos patNext = pat; 846 1.28 christos nameNext = name + 1; 847 1.28 christos pat++; 848 1.28 christos continue; 849 1.1 cgd case '[': 850 1.1 cgd match = 0; 851 1.28 christos if (namec == 0) 852 1.28 christos break; 853 1.28 christos pat++; 854 1.28 christos name++; 855 1.28 christos if ((negate_range = (*pat == '^')) != 0) 856 1.28 christos pat++; 857 1.28 christos while ((c = *pat++) != ']') { 858 1.28 christos c &= TRIM; 859 1.28 christos if (*pat == '-') { 860 1.28 christos if (c <= namec && namec <= (pat[1] & TRIM)) 861 1.28 christos match = 1; 862 1.28 christos pat += 2; 863 1.28 christos } else if (c == namec) 864 1.28 christos match = 1; 865 1.28 christos else if (c == 0) 866 1.28 christos stderror(ERR_NAME | ERR_MISSING, ']'); 867 1.1 cgd } 868 1.8 mycroft if (match == negate_range) 869 1.28 christos break; 870 1.28 christos continue; 871 1.1 cgd default: 872 1.28 christos if ((patc & TRIM) != namec) 873 1.28 christos break; 874 1.28 christos pat++; 875 1.28 christos name++; 876 1.28 christos continue; 877 1.28 christos } 878 1.28 christos if (nameNext != nameStart && (nameEnd == NULL || nameNext <= nameEnd)) { 879 1.28 christos pat = patNext; 880 1.28 christos name = nameNext; 881 1.28 christos continue; 882 1.1 cgd } 883 1.28 christos return 0; 884 1.1 cgd } 885 1.1 cgd } 886 1.1 cgd 887 1.1 cgd void 888 1.18 wiz Gcat(Char *s1, Char *s2) 889 1.1 cgd { 890 1.11 tls Char *p, *q; 891 1.27 christos ptrdiff_t n; 892 1.1 cgd 893 1.8 mycroft for (p = s1; *p++;) 894 1.8 mycroft continue; 895 1.8 mycroft for (q = s2; *q++;) 896 1.8 mycroft continue; 897 1.1 cgd n = (p - s1) + (q - s2) - 1; 898 1.1 cgd if (++gargc >= gargsiz) { 899 1.1 cgd gargsiz += GLOBSPACE; 900 1.32 nia gargv = xreallocarray(gargv, (size_t)gargsiz, sizeof(Char *)); 901 1.1 cgd } 902 1.1 cgd gargv[gargc] = 0; 903 1.32 nia p = gargv[gargc - 1] = xreallocarray(NULL, (size_t)n, sizeof(Char)); 904 1.8 mycroft for (q = s1; (*p++ = *q++) != '\0';) 905 1.8 mycroft continue; 906 1.8 mycroft for (p--, q = s2; (*p++ = *q++) != '\0';) 907 1.8 mycroft continue; 908 1.1 cgd } 909 1.1 cgd 910 1.1 cgd #ifdef FILEC 911 1.1 cgd int 912 1.30 christos sortscmp(const void *va, const void *vb) 913 1.1 cgd { 914 1.1 cgd #if defined(NLS) && !defined(NOSTRCOLL) 915 1.18 wiz char buf[2048]; 916 1.1 cgd #endif 917 1.30 christos const Char * const *a = va; 918 1.30 christos const Char * const *b = vb; 919 1.1 cgd 920 1.1 cgd if (!a) /* check for NULL */ 921 1.1 cgd return (b ? 1 : 0); 922 1.1 cgd if (!b) 923 1.30 christos return -1; 924 1.1 cgd 925 1.30 christos if (!*a) /* check for NULL */ 926 1.30 christos return *b ? 1 : 0; 927 1.30 christos if (!*b) 928 1.1 cgd return (-1); 929 1.1 cgd 930 1.1 cgd #if defined(NLS) && !defined(NOSTRCOLL) 931 1.30 christos (void)strcpy(buf, short2str(*a)); 932 1.30 christos return (int)strcoll(buf, short2str(*b)); 933 1.1 cgd #else 934 1.30 christos return (int)Strcmp(*a, *b); 935 1.1 cgd #endif 936 1.1 cgd } 937 1.1 cgd #endif /* FILEC */ 938