159243Sobrien/* 259243Sobrien * sh.glob.c: Regular expression expansion 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "tc.h" 34100616Smp#include "tw.h" 3559243Sobrien 3659243Sobrien#include "glob.h" 3759243Sobrien 3859243Sobrien/* 3959243Sobrien * Values for gflag 4059243Sobrien */ 4159243Sobrien#define G_NONE 0 /* No globbing needed */ 4259243Sobrien#define G_GLOB 1 /* string contains *?[] characters */ 4359243Sobrien#define G_CSH 2 /* string contains ~`{ characters */ 4459243Sobrien 4559243Sobrien#define GLOBSPACE 100 /* Alloc increment */ 4659243Sobrien 4759243Sobrien 4859243Sobrien#define LBRC '{' 4959243Sobrien#define RBRC '}' 5059243Sobrien#define LBRK '[' 5159243Sobrien#define RBRK ']' 5259243Sobrien#define EOS '\0' 5359243Sobrien 5459243Sobrien/* 5559243Sobrien * globbing is now done in two stages. In the first pass we expand 5659243Sobrien * csh globbing idioms ~`{ and then we proceed doing the normal 5759243Sobrien * globbing if needed ?*[ 5859243Sobrien * 5959243Sobrien * Csh type globbing is handled in globexpand() and the rest is 6059243Sobrien * handled in glob() which is part of the 4.4BSD libc. 6159243Sobrien * 6259243Sobrien */ 63167465Smpstatic Char *globtilde (Char *); 64167465Smpstatic Char *handleone (Char *, Char **, int); 65167465Smpstatic Char **libglob (Char **); 66167465Smpstatic Char **globexpand (Char **, int); 67167465Smpstatic int globbrace (const Char *, Char ***); 68167465Smpstatic void expbrace (Char ***, Char ***, int); 69167465Smpstatic void pword (struct blk_buf *, struct Strbuf *); 70167465Smpstatic void backeval (struct blk_buf *, struct Strbuf *, Char *, 71167465Smp int); 7259243Sobrienstatic Char * 73167465Smpglobtilde(Char *s) 7459243Sobrien{ 75167465Smp Char *name, *u, *home, *res; 7659243Sobrien 7759243Sobrien u = s; 78167465Smp for (s++; *s && *s != '/' && *s != ':'; s++) 7959243Sobrien continue; 80167465Smp name = Strnsave(u + 1, s - (u + 1)); 81167465Smp cleanup_push(name, xfree); 82167465Smp home = gethdir(name); 83167465Smp if (home == NULL) { 84167465Smp if (adrof(STRnonomatch)) { 85167465Smp cleanup_until(name); 86167465Smp return u; 87167465Smp } 88167465Smp if (*name) 89167465Smp stderror(ERR_UNKUSER, short2str(name)); 9059243Sobrien else 9159243Sobrien stderror(ERR_NOHOME); 9259243Sobrien } 93167465Smp cleanup_until(name); 94167465Smp if (home[0] == '/' && home[1] == '\0' && s[0] == '/') 95167465Smp res = Strsave(s); 96167465Smp else 97167465Smp res = Strspl(home, s); 98167465Smp xfree(home); 99167465Smp xfree(u); 100167465Smp return res; 10159243Sobrien} 10259243Sobrien 103167465Smp/* Returns a newly allocated string, old or NULL */ 10459243SobrienChar * 105167465Smpglobequal(Char *old) 10659243Sobrien{ 10759243Sobrien int dig; 108167465Smp const Char *dir; 109167465Smp Char *b; 11059243Sobrien 11159243Sobrien /* 11259243Sobrien * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names 11359243Sobrien * in stack. PWP: let =foobar pass through (for X windows) 11459243Sobrien */ 11559243Sobrien if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) { 11659243Sobrien /* =- */ 117167465Smp const Char *olddir = varval (STRowd); 118167465Smp 119167465Smp if (olddir && *olddir && 120167465Smp !dcwd->di_next->di_name && !dcwd->di_prev->di_name) 121167465Smp return Strspl(olddir, &old[2]); 12259243Sobrien dig = -1; 12359243Sobrien b = &old[2]; 12459243Sobrien } 12559243Sobrien else if (Isdigit(old[1])) { 12659243Sobrien /* =<number> */ 12759243Sobrien dig = old[1] - '0'; 12859243Sobrien for (b = &old[2]; Isdigit(*b); b++) 12959243Sobrien dig = dig * 10 + (*b - '0'); 13059243Sobrien if (*b != '\0' && *b != '/') 13159243Sobrien /* =<number>foobar */ 13259243Sobrien return old; 13359243Sobrien } 13459243Sobrien else 13559243Sobrien /* =foobar */ 13659243Sobrien return old; 13759243Sobrien 138167465Smp dir = getstakd(dig); 139167465Smp if (dir == NULL) 14059243Sobrien return NULL; 141167465Smp return Strspl(dir, b); 14259243Sobrien} 14359243Sobrien 14459243Sobrienstatic int 145167465Smpglobbrace(const Char *s, Char ***bl) 14659243Sobrien{ 147167465Smp struct Strbuf gbuf = Strbuf_INIT; 148167465Smp struct blk_buf bb = BLK_BUF_INIT; 149167465Smp int i; 150167465Smp const Char *p, *pm, *pe, *pl; 151167465Smp size_t prefix_len; 15259243Sobrien 15359243Sobrien /* copy part up to the brace */ 154167465Smp for (p = s; *p != LBRC; p++) 155167465Smp ; 156167465Smp prefix_len = p - s; 15759243Sobrien 15859243Sobrien /* check for balanced braces */ 15959243Sobrien for (i = 0, pe = ++p; *pe; pe++) 16059243Sobrien if (*pe == LBRK) { 16159243Sobrien /* Ignore everything between [] */ 16259243Sobrien for (++pe; *pe != RBRK && *pe != EOS; pe++) 16359243Sobrien continue; 164167465Smp if (*pe == EOS) 16559243Sobrien return (-RBRK); 16659243Sobrien } 16759243Sobrien else if (*pe == LBRC) 16859243Sobrien i++; 16959243Sobrien else if (*pe == RBRC) { 17059243Sobrien if (i == 0) 17159243Sobrien break; 17259243Sobrien i--; 17359243Sobrien } 17459243Sobrien 175167465Smp if (i != 0 || *pe == '\0') 17659243Sobrien return (-RBRC); 17759243Sobrien 178167465Smp Strbuf_appendn(&gbuf, s, prefix_len); 179167465Smp 18059243Sobrien for (i = 0, pl = pm = p; pm <= pe; pm++) 18159243Sobrien switch (*pm) { 18259243Sobrien case LBRK: 18359243Sobrien for (++pm; *pm != RBRK && *pm != EOS; pm++) 18459243Sobrien continue; 18559243Sobrien if (*pm == EOS) { 186167465Smp bb_cleanup(&bb); 187167465Smp xfree(gbuf.s); 18859243Sobrien return (-RBRK); 18959243Sobrien } 19059243Sobrien break; 19159243Sobrien case LBRC: 19259243Sobrien i++; 19359243Sobrien break; 19459243Sobrien case RBRC: 19559243Sobrien if (i) { 19659243Sobrien i--; 19759243Sobrien break; 19859243Sobrien } 19959243Sobrien /* FALLTHROUGH */ 20059243Sobrien case ',': 20159243Sobrien if (i && *pm == ',') 20259243Sobrien break; 20359243Sobrien else { 204167465Smp gbuf.len = prefix_len; 205167465Smp Strbuf_appendn(&gbuf, pl, pm - pl); 206167465Smp Strbuf_append(&gbuf, pe + 1); 207167465Smp Strbuf_terminate(&gbuf); 208167465Smp bb_append(&bb, Strsave(gbuf.s)); 20959243Sobrien pl = pm + 1; 21059243Sobrien } 21159243Sobrien break; 21259243Sobrien default: 21359243Sobrien break; 21459243Sobrien } 215167465Smp *bl = bb_finish(&bb); 216167465Smp xfree(gbuf.s); 217167465Smp return bb.len; 21859243Sobrien} 21959243Sobrien 22059243Sobrien 22159243Sobrienstatic void 222167465Smpexpbrace(Char ***nvp, Char ***elp, int size) 22359243Sobrien{ 22459243Sobrien Char **vl, **el, **nv, *s; 22559243Sobrien 22659243Sobrien vl = nv = *nvp; 22759243Sobrien if (elp != NULL) 22859243Sobrien el = *elp; 22959243Sobrien else 230167465Smp el = vl + blklen(vl); 23159243Sobrien 23259243Sobrien for (s = *vl; s; s = *++vl) { 23359243Sobrien Char **vp, **bp; 23459243Sobrien 23559243Sobrien /* leave {} untouched for find */ 23659243Sobrien if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 23759243Sobrien continue; 238167465Smp if (Strchr(s, '{') != NULL) { 239167465Smp Char **bl = NULL; 24059243Sobrien int len; 24159243Sobrien 242167465Smp if ((len = globbrace(s, &bl)) < 0) 24359243Sobrien stderror(ERR_MISSING, -len); 244167465Smp xfree(s); 24559243Sobrien if (len == 1) { 24659243Sobrien *vl-- = *bl; 247167465Smp xfree(bl); 24859243Sobrien continue; 24959243Sobrien } 25059243Sobrien if (&el[len] >= &nv[size]) { 251167465Smp size_t l, e; 252167465Smp l = &el[len] - &nv[size]; 25359243Sobrien size += GLOBSPACE > l ? GLOBSPACE : l; 254167465Smp l = vl - nv; 255167465Smp e = el - nv; 256167465Smp nv = xrealloc(nv, size * sizeof(Char *)); 257167465Smp *nvp = nv; /* To keep cleanups working */ 25859243Sobrien vl = nv + l; 25959243Sobrien el = nv + e; 26059243Sobrien } 26159243Sobrien /* nv vl el bl 26259243Sobrien * | | | | 26359243Sobrien * -.--..-- x-- 26459243Sobrien * | len 26559243Sobrien * vp 26659243Sobrien */ 26759243Sobrien vp = vl--; 26859243Sobrien *vp = *bl; 26959243Sobrien len--; 27059243Sobrien for (bp = el; bp != vp; bp--) 27159243Sobrien bp[len] = *bp; 27259243Sobrien el += len; 27359243Sobrien /* nv vl el bl 27459243Sobrien * | | | | 27559243Sobrien * -.-x --- -- 27659243Sobrien * |len 27759243Sobrien * vp 27859243Sobrien */ 27959243Sobrien vp++; 28059243Sobrien for (bp = bl + 1; *bp; *vp++ = *bp++) 28159243Sobrien continue; 282167465Smp xfree(bl); 28359243Sobrien } 28459243Sobrien 28559243Sobrien } 28659243Sobrien if (elp != NULL) 28759243Sobrien *elp = el; 28859243Sobrien} 28959243Sobrien 29059243Sobrienstatic Char ** 291167465Smpglobexpand(Char **v, int noglob) 29259243Sobrien{ 29359243Sobrien Char *s; 294167465Smp Char ***fnv, **vl, **el; 29559243Sobrien int size = GLOBSPACE; 29659243Sobrien 29759243Sobrien 298167465Smp fnv = xmalloc(sizeof(Char ***)); 299167465Smp *fnv = vl = xmalloc(sizeof(Char *) * size); 30059243Sobrien *vl = NULL; 301167465Smp cleanup_push(fnv, blk_indirect_cleanup); 30259243Sobrien 30359243Sobrien /* 30459243Sobrien * Step 1: expand backquotes. 30559243Sobrien */ 306354195Sbrooks while ((s = *v++) != NULL) { 30759243Sobrien if (Strchr(s, '`')) { 30859243Sobrien int i; 309167465Smp Char **expanded; 31059243Sobrien 311167465Smp expanded = dobackp(s, 0); 312167465Smp for (i = 0; expanded[i] != NULL; i++) { 313167465Smp *vl++ = expanded[i]; 314167465Smp if (vl == &(*fnv)[size]) { 31559243Sobrien size += GLOBSPACE; 316167465Smp *fnv = xrealloc(*fnv, size * sizeof(Char *)); 317167465Smp vl = &(*fnv)[size - GLOBSPACE]; 31859243Sobrien } 31959243Sobrien } 320167465Smp xfree(expanded); 32159243Sobrien } 32259243Sobrien else { 32359243Sobrien *vl++ = Strsave(s); 324167465Smp if (vl == &(*fnv)[size]) { 32559243Sobrien size += GLOBSPACE; 326167465Smp *fnv = xrealloc(*fnv, size * sizeof(Char *)); 327167465Smp vl = &(*fnv)[size - GLOBSPACE]; 32859243Sobrien } 32959243Sobrien } 330167465Smp *vl = NULL; 33159243Sobrien } 33259243Sobrien 33359243Sobrien if (noglob) 334167465Smp goto done; 33559243Sobrien 33659243Sobrien /* 33759243Sobrien * Step 2: expand braces 33859243Sobrien */ 33959243Sobrien el = vl; 340167465Smp expbrace(fnv, &el, size); 34159243Sobrien 34259243Sobrien 34359243Sobrien /* 34459243Sobrien * Step 3: expand ~ = 34559243Sobrien */ 346167465Smp vl = *fnv; 34759243Sobrien for (s = *vl; s; s = *++vl) 34859243Sobrien switch (*s) { 349167465Smp Char *ns; 35059243Sobrien case '~': 351167465Smp *vl = globtilde(s); 35259243Sobrien break; 35359243Sobrien case '=': 354167465Smp if ((ns = globequal(s)) == NULL) { 355167465Smp if (!adrof(STRnonomatch)) 356167465Smp stderror(ERR_DEEP); /* Error */ 35759243Sobrien } 35859243Sobrien if (ns && ns != s) { 35959243Sobrien /* Expansion succeeded */ 360167465Smp xfree(s); 361167465Smp *vl = ns; 36259243Sobrien } 36359243Sobrien break; 36459243Sobrien default: 36559243Sobrien break; 36659243Sobrien } 367167465Smp vl = *fnv; 36859243Sobrien 36959243Sobrien /* 37059243Sobrien * Step 4: expand .. if the variable symlinks==expand is set 37159243Sobrien */ 37283098Smp if (symlinks == SYM_EXPAND) { 37359243Sobrien for (s = *vl; s; s = *++vl) { 37483098Smp *vl = dnormalize(s, 1); 375167465Smp xfree(s); 37659243Sobrien } 37783098Smp } 37859243Sobrien 379167465Smp done: 380167465Smp cleanup_ignore(fnv); 381167465Smp cleanup_until(fnv); 382167465Smp vl = *fnv; 383167465Smp xfree(fnv); 384167465Smp return vl; 38559243Sobrien} 38659243Sobrien 38759243Sobrienstatic Char * 388167465Smphandleone(Char *str, Char **vl, int action) 38959243Sobrien{ 390167465Smp size_t chars; 39159243Sobrien Char **t, *p, *strp; 39259243Sobrien 39359243Sobrien switch (action) { 39459243Sobrien case G_ERROR: 39559243Sobrien setname(short2str(str)); 39659243Sobrien blkfree(vl); 39759243Sobrien stderror(ERR_NAME | ERR_AMBIG); 39859243Sobrien break; 39959243Sobrien case G_APPEND: 40059243Sobrien chars = 0; 401167465Smp for (t = vl; (p = *t++) != NULL; chars++) 402167465Smp chars += Strlen(p); 403167465Smp str = xmalloc(chars * sizeof(Char)); 404354195Sbrooks for (t = vl, strp = str; (p = *t++) != NULL; chars++) { 40559243Sobrien while (*p) 40659243Sobrien *strp++ = *p++ & TRIM; 40759243Sobrien *strp++ = ' '; 40859243Sobrien } 40959243Sobrien *--strp = '\0'; 41059243Sobrien blkfree(vl); 41159243Sobrien break; 41259243Sobrien case G_IGNORE: 413167465Smp str = Strsave(strip(*vl)); 41459243Sobrien blkfree(vl); 41559243Sobrien break; 41659243Sobrien default: 41759243Sobrien break; 41859243Sobrien } 41959243Sobrien return (str); 42059243Sobrien} 42159243Sobrien 42259243Sobrienstatic Char ** 423167465Smplibglob(Char **vl) 42459243Sobrien{ 42559243Sobrien int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT; 42659243Sobrien glob_t globv; 42759243Sobrien char *ptr; 42859243Sobrien int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; 42959243Sobrien 430231990Smp if (adrof(STRglobdot)) 431231990Smp gflgs |= GLOB_DOT; 432231990Smp 433231990Smp if (adrof(STRglobstar)) 434231990Smp gflgs |= GLOB_STAR; 435231990Smp 43659243Sobrien if (!vl || !vl[0]) 43759243Sobrien return(vl); 43859243Sobrien 43959243Sobrien globv.gl_offs = 0; 44059243Sobrien globv.gl_pathv = 0; 44159243Sobrien globv.gl_pathc = 0; 44259243Sobrien 44359243Sobrien if (nonomatch) 44459243Sobrien gflgs |= GLOB_NOCHECK; 44559243Sobrien 44659243Sobrien do { 44759243Sobrien ptr = short2qstr(*vl); 44859243Sobrien switch (glob(ptr, gflgs, 0, &globv)) { 44959243Sobrien case GLOB_ABEND: 45059243Sobrien globfree(&globv); 45159243Sobrien setname(ptr); 45259243Sobrien stderror(ERR_NAME | ERR_GLOB); 45359243Sobrien /* NOTREACHED */ 45459243Sobrien case GLOB_NOSPACE: 45559243Sobrien globfree(&globv); 45659243Sobrien stderror(ERR_NOMEM); 45759243Sobrien /* NOTREACHED */ 45859243Sobrien default: 45959243Sobrien break; 46059243Sobrien } 46159243Sobrien if (globv.gl_flags & GLOB_MAGCHAR) { 46259243Sobrien match |= (globv.gl_matchc != 0); 46359243Sobrien magic = 1; 46459243Sobrien } 46559243Sobrien gflgs |= GLOB_APPEND; 46659243Sobrien } 46759243Sobrien while (*++vl); 46859243Sobrien vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 46959243Sobrien NULL : blk2short(globv.gl_pathv); 47059243Sobrien globfree(&globv); 47159243Sobrien return (vl); 47259243Sobrien} 47359243Sobrien 47459243SobrienChar * 475167465Smpglobone(Char *str, int action) 47659243Sobrien{ 47759243Sobrien Char *v[2], **vl, **vo; 478167465Smp int gflg, noglob; 47959243Sobrien 48059243Sobrien noglob = adrof(STRnoglob) != 0; 48159243Sobrien v[0] = str; 48259243Sobrien v[1] = 0; 483167465Smp gflg = tglob(v); 48459243Sobrien if (gflg == G_NONE) 48559243Sobrien return (strip(Strsave(str))); 48659243Sobrien 48759243Sobrien if (gflg & G_CSH) { 48859243Sobrien /* 48959243Sobrien * Expand back-quote, tilde and brace 49059243Sobrien */ 491167465Smp vo = globexpand(v, noglob); 49259243Sobrien if (noglob || (gflg & G_GLOB) == 0) { 493167465Smp vl = vo; 494167465Smp goto result; 49559243Sobrien } 496167465Smp cleanup_push(vo, blk_cleanup); 49759243Sobrien } 49859243Sobrien else if (noglob || (gflg & G_GLOB) == 0) 49959243Sobrien return (strip(Strsave(str))); 50059243Sobrien else 50159243Sobrien vo = v; 50259243Sobrien 50359243Sobrien vl = libglob(vo); 504167465Smp if (gflg & G_CSH) { 505167465Smp if (vl != vo) 506167465Smp cleanup_until(vo); 507167465Smp else 508167465Smp cleanup_ignore(vo); 509167465Smp } 51059243Sobrien if (vl == NULL) { 51159243Sobrien setname(short2str(str)); 51259243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 51359243Sobrien } 514167465Smp result: 515231990Smp if (vl && vl[0] == NULL) { 516167465Smp xfree(vl); 51759243Sobrien return (Strsave(STRNULL)); 51859243Sobrien } 519231990Smp if (vl && vl[1]) 52059243Sobrien return (handleone(str, vl, action)); 52159243Sobrien else { 52259243Sobrien str = strip(*vl); 523167465Smp xfree(vl); 52459243Sobrien return (str); 52559243Sobrien } 52659243Sobrien} 52759243Sobrien 52859243SobrienChar ** 529167465Smpgloball(Char **v, int gflg) 53059243Sobrien{ 53159243Sobrien Char **vl, **vo; 532167465Smp int noglob; 53359243Sobrien 534167465Smp if (!v || !v[0]) 535167465Smp return saveblk(v); 53659243Sobrien 53759243Sobrien noglob = adrof(STRnoglob) != 0; 53859243Sobrien 53959243Sobrien if (gflg & G_CSH) 54059243Sobrien /* 54159243Sobrien * Expand back-quote, tilde and brace 54259243Sobrien */ 543167465Smp vl = vo = globexpand(v, noglob); 54459243Sobrien else 54559243Sobrien vl = vo = saveblk(v); 54659243Sobrien 54759243Sobrien if (!noglob && (gflg & G_GLOB)) { 548167465Smp cleanup_push(vo, blk_cleanup); 54959243Sobrien vl = libglob(vo); 550167465Smp if (vl == vo) 551167465Smp cleanup_ignore(vo); 552167465Smp cleanup_until(vo); 55359243Sobrien } 55459243Sobrien else 55559243Sobrien trim(vl); 55659243Sobrien 557167465Smp return vl; 55859243Sobrien} 55959243Sobrien 560167465SmpChar ** 561167465Smpglob_all_or_error(Char **v) 56259243Sobrien{ 563167465Smp int gflag; 564167465Smp 565167465Smp gflag = tglob(v); 566167465Smp if (gflag) { 567167465Smp v = globall(v, gflag); 568167465Smp if (v == NULL) 569167465Smp stderror(ERR_NAME | ERR_NOMATCH); 570167465Smp } else { 571167465Smp v = saveblk(v); 572167465Smp trim(v); 573167465Smp } 574167465Smp return v; 57559243Sobrien} 57659243Sobrien 57759243Sobrienvoid 578167465Smprscan(Char **t, void (*f) (Char)) 57959243Sobrien{ 580145479Smp Char *p; 58159243Sobrien 582354195Sbrooks while ((p = *t++) != NULL) 58359243Sobrien while (*p) 58459243Sobrien (*f) (*p++); 58559243Sobrien} 58659243Sobrien 58759243Sobrienvoid 588167465Smptrim(Char **t) 58959243Sobrien{ 590145479Smp Char *p; 59159243Sobrien 592354195Sbrooks while ((p = *t++) != NULL) 593316957Sdchagin while (*p) { 594316957Sdchagin#if INVALID_BYTE != 0 595316957Sdchagin if ((*p & INVALID_BYTE) != INVALID_BYTE) /* *p < INVALID_BYTE */ 596316957Sdchagin#endif 597316957Sdchagin *p &= TRIM; 598316957Sdchagin p++; 599316957Sdchagin } 60059243Sobrien} 60159243Sobrien 602167465Smpint 603167465Smptglob(Char **t) 60459243Sobrien{ 605167465Smp int gflag; 606167465Smp const Char *p; 60759243Sobrien 608167465Smp gflag = 0; 609354195Sbrooks while ((p = *t++) != NULL) { 61059243Sobrien if (*p == '~' || *p == '=') 61159243Sobrien gflag |= G_CSH; 61259243Sobrien else if (*p == '{' && 61359243Sobrien (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 61459243Sobrien continue; 615167465Smp while (*p != '\0') { 616167465Smp if (*p == '`') { 61759243Sobrien gflag |= G_CSH; 61859243Sobrien#ifdef notdef 61959243Sobrien /* 62059243Sobrien * We do want to expand echo `echo '*'`, so we don't\ 62159243Sobrien * use this piece of code anymore. 62259243Sobrien */ 623167465Smp p++; 62459243Sobrien while (*p && *p != '`') 62559243Sobrien if (*p++ == '\\') { 62659243Sobrien if (*p) /* Quoted chars */ 62759243Sobrien p++; 62859243Sobrien else 62959243Sobrien break; 63059243Sobrien } 631167465Smp if (!*p) /* The matching ` */ 63259243Sobrien break; 63359243Sobrien#endif 63459243Sobrien } 635167465Smp else if (*p == '{') 63659243Sobrien gflag |= G_CSH; 637167465Smp else if (isglob(*p)) 63859243Sobrien gflag |= G_GLOB; 63959243Sobrien else if (symlinks == SYM_EXPAND && 640167465Smp p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') ) 64159243Sobrien gflag |= G_CSH; 642167465Smp p++; 64359243Sobrien } 64459243Sobrien } 645167465Smp return gflag; 64659243Sobrien} 64759243Sobrien 64859243Sobrien/* 64959243Sobrien * Command substitute cp. If literal, then this is a substitution from a 65059243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating 65159243Sobrien * words only at newlines. 65259243Sobrien */ 65359243SobrienChar ** 654167465Smpdobackp(Char *cp, int literal) 65559243Sobrien{ 656167465Smp struct Strbuf word = Strbuf_INIT; 657167465Smp struct blk_buf bb = BLK_BUF_INIT; 658167465Smp Char *lp, *rp, *ep; 65959243Sobrien 660167465Smp cleanup_push(&bb, bb_cleanup); 661167465Smp cleanup_push(&word, Strbuf_cleanup); 66259243Sobrien for (;;) { 663167465Smp for (lp = cp; *lp != '\0' && *lp != '`'; lp++) 664167465Smp ; 665167465Smp Strbuf_appendn(&word, cp, lp - cp); 666167465Smp if (*lp == 0) 667167465Smp break; 66859243Sobrien lp++; 66959243Sobrien for (rp = lp; *rp && *rp != '`'; rp++) 67059243Sobrien if (*rp == '\\') { 67159243Sobrien rp++; 67259243Sobrien if (!*rp) 67359243Sobrien goto oops; 67459243Sobrien } 675167465Smp if (!*rp) { 676167465Smp oops: 677195609Smp cleanup_until(&bb); 678167465Smp stderror(ERR_UNMATCHED, '`'); 679167465Smp } 680167465Smp ep = Strnsave(lp, rp - lp); 681167465Smp cleanup_push(ep, xfree); 682167465Smp backeval(&bb, &word, ep, literal); 683167465Smp cleanup_until(ep); 68459243Sobrien cp = rp + 1; 68559243Sobrien } 686167465Smp if (word.len != 0) 687167465Smp pword(&bb, &word); 688167465Smp cleanup_ignore(&bb); 689167465Smp cleanup_until(&bb); 690167465Smp return bb_finish(&bb); 69159243Sobrien} 69259243Sobrien 69359243Sobrien 69459243Sobrienstatic void 695167465Smpbackeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal) 69659243Sobrien{ 697231990Smp ssize_t icnt; 698145479Smp Char c, *ip; 69959243Sobrien struct command faket; 700145479Smp int hadnl; 70159243Sobrien int pvec[2], quoted; 70259243Sobrien Char *fakecom[2], ibuf[BUFSIZE]; 70359243Sobrien 70459243Sobrien hadnl = 0; 70559243Sobrien icnt = 0; 706316957Sdchagin if (!literal) { 707316957Sdchagin for (ip = cp; (*ip & QUOTE) != 0; ip++) 708316957Sdchagin continue; 709316957Sdchagin quoted = *ip == '\0'; 710316957Sdchagin } else 711316957Sdchagin quoted = literal; 71259243Sobrien faket.t_dtyp = NODE_COMMAND; 71359243Sobrien faket.t_dflg = F_BACKQ; 71459243Sobrien faket.t_dlef = 0; 71559243Sobrien faket.t_drit = 0; 71659243Sobrien faket.t_dspr = 0; 71759243Sobrien faket.t_dcom = fakecom; 71859243Sobrien fakecom[0] = STRfakecom1; 71959243Sobrien fakecom[1] = 0; 72059243Sobrien 72159243Sobrien /* 72259243Sobrien * We do the psave job to temporarily change the current job so that the 72359243Sobrien * following fork is considered a separate job. This is so that when 72459243Sobrien * backquotes are used in a builtin function that calls glob the "current 72559243Sobrien * job" is not corrupted. We only need one level of pushed jobs as long as 72659243Sobrien * we are sure to fork here. 72759243Sobrien */ 72859243Sobrien psavejob(); 729167465Smp cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */ 73059243Sobrien 73159243Sobrien /* 73259243Sobrien * It would be nicer if we could integrate this redirection more with the 73359243Sobrien * routines in sh.sem.c by doing a fake execute on a builtin function that 73459243Sobrien * was piped out. 73559243Sobrien */ 73659243Sobrien mypipe(pvec); 737167465Smp cleanup_push(&pvec[0], open_cleanup); 738167465Smp cleanup_push(&pvec[1], open_cleanup); 73959243Sobrien if (pfork(&faket, -1) == 0) { 740145479Smp jmp_buf_t osetexit; 741167465Smp struct command *t; 742167465Smp size_t omark; 74359243Sobrien 744167465Smp xclose(pvec[0]); 74559243Sobrien (void) dmove(pvec[1], 1); 74659243Sobrien (void) dmove(SHDIAG, 2); 74759243Sobrien initdesc(); 748100616Smp closem(); 74959243Sobrien arginp = cp; 750100616Smp for (arginp = cp; *cp; cp++) { 751100616Smp *cp &= TRIM; 752145479Smp if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r')) 753100616Smp *cp = ' '; 754100616Smp } 75559243Sobrien 75659243Sobrien /* 75759243Sobrien * In the child ``forget'' everything about current aliases or 75859243Sobrien * eval vectors. 75959243Sobrien */ 76059243Sobrien alvec = NULL; 76159243Sobrien evalvec = NULL; 76259243Sobrien alvecp = NULL; 76359243Sobrien evalp = NULL; 764145479Smp 765167465Smp omark = cleanup_push_mark(); 766145479Smp getexit(osetexit); 767145479Smp for (;;) { 768316957Sdchagin struct wordent paraml1; 769316957Sdchagin initlex(¶ml1); 770316957Sdchagin 771145479Smp (void) setexit(); 772145479Smp justpr = 0; 773145479Smp 774145479Smp if (haderr) { 775145479Smp /* unwind */ 776145479Smp doneinp = 0; 777167465Smp cleanup_pop_mark(omark); 778145479Smp resexit(osetexit); 779145479Smp reset(); 780145479Smp } 781145479Smp if (seterr) { 782167465Smp xfree(seterr); 783145479Smp seterr = NULL; 784145479Smp } 785145479Smp 786316957Sdchagin freelex(¶ml1); 787316957Sdchagin (void) lex(¶ml1); 788316957Sdchagin cleanup_push(¶ml1, lex_cleanup); 789145479Smp if (seterr) 790145479Smp stderror(ERR_OLD); 791316957Sdchagin alias(¶ml1); 792316957Sdchagin t = syntax(paraml1.next, ¶ml1, 0); 793167465Smp cleanup_push(t, syntax_cleanup); 794231990Smp /* The F_BACKQ flag must set so the job output is correct if 795231990Smp * printexitvalue is set. If it's not set, the job output 796231990Smp * will have "Exit N" appended where N is the exit status. */ 797316957Sdchagin if (t) 798316957Sdchagin t->t_dflg = F_BACKQ|F_NOFORK; 799145479Smp if (seterr) 800145479Smp stderror(ERR_OLD); 80159243Sobrien#ifdef SIGTSTP 802167465Smp signal(SIGTSTP, SIG_IGN); 80359243Sobrien#endif 80459243Sobrien#ifdef SIGTTIN 805167465Smp signal(SIGTTIN, SIG_IGN); 80659243Sobrien#endif 80759243Sobrien#ifdef SIGTTOU 808167465Smp signal(SIGTTOU, SIG_IGN); 80959243Sobrien#endif 810145479Smp execute(t, -1, NULL, NULL, TRUE); 811145479Smp 812316957Sdchagin cleanup_until(¶ml1); 813145479Smp } 81459243Sobrien } 815167465Smp cleanup_until(&pvec[1]); 81659243Sobrien c = 0; 81759243Sobrien ip = NULL; 81859243Sobrien do { 819231990Smp ssize_t cnt = 0; 82059243Sobrien 82159243Sobrien for (;;) { 822316957Sdchagin if (icnt == 0) { 82359243Sobrien ip = ibuf; 824316957Sdchagin icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0); 825316957Sdchagin if (icnt <= 0) 826316957Sdchagin goto eof; 82759243Sobrien } 82859243Sobrien if (hadnl) 82959243Sobrien break; 83059243Sobrien --icnt; 83159243Sobrien c = (*ip++ & TRIM); 83259243Sobrien if (c == 0) 83359243Sobrien break; 834195609Smp#if defined(WINNT_NATIVE) || defined(__CYGWIN__) 83559243Sobrien if (c == '\r') 83659243Sobrien c = ' '; 837195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */ 83859243Sobrien if (c == '\n') { 83959243Sobrien /* 84059243Sobrien * Continue around the loop one more time, so that we can eat 84159243Sobrien * the last newline without terminating this word. 84259243Sobrien */ 84359243Sobrien hadnl = 1; 84459243Sobrien continue; 84559243Sobrien } 84659243Sobrien if (!quoted && (c == ' ' || c == '\t')) 84759243Sobrien break; 84859243Sobrien cnt++; 849316957Sdchagin if (c == '\\' || quoted) 850316957Sdchagin c |= QUOTE; 851316957Sdchagin Strbuf_append1(word, c); 85259243Sobrien } 85359243Sobrien /* 85459243Sobrien * Unless at end-of-file, we will form a new word here if there were 85559243Sobrien * characters in the word, or in any case when we take text literally. 85659243Sobrien * If we didn't make empty words here when literal was set then we 85759243Sobrien * would lose blank lines. 85859243Sobrien */ 859145479Smp if (c != 0 && (cnt || literal)) 860167465Smp pword(bb, word); 86159243Sobrien hadnl = 0; 862145479Smp } while (c > 0); 863145479Smp eof: 864167465Smp cleanup_until(&pvec[0]); 86559243Sobrien pwait(); 866167465Smp cleanup_until(&faket); /* psavejob_cleanup(); */ 86759243Sobrien} 86859243Sobrien 86959243Sobrienstatic void 870167465Smppword(struct blk_buf *bb, struct Strbuf *word) 87159243Sobrien{ 872167465Smp Char *s; 87359243Sobrien 874167465Smp s = Strbuf_finish(word); 875167465Smp bb_append(bb, s); 876167465Smp *word = Strbuf_init; 87759243Sobrien} 87859243Sobrien 87959243Sobrienint 880167465SmpGmatch(const Char *string, const Char *pattern) 88159243Sobrien{ 88259243Sobrien return Gnmatch(string, pattern, NULL); 88359243Sobrien} 88459243Sobrien 885167465Smpint 886167465SmpGnmatch(const Char *string, const Char *pattern, const Char **endstr) 88759243Sobrien{ 888167465Smp Char ***fblk, **p; 889167465Smp const Char *tstring = string; 89059243Sobrien int gpol = 1, gres = 0; 89159243Sobrien 89259243Sobrien if (*pattern == '^') { 89359243Sobrien gpol = 0; 89459243Sobrien pattern++; 89559243Sobrien } 89659243Sobrien 897167465Smp fblk = xmalloc(sizeof(Char ***)); 898167465Smp *fblk = xmalloc(GLOBSPACE * sizeof(Char *)); 899167465Smp (*fblk)[0] = Strsave(pattern); 900167465Smp (*fblk)[1] = NULL; 90159243Sobrien 902167465Smp cleanup_push(fblk, blk_indirect_cleanup); 903167465Smp expbrace(fblk, NULL, GLOBSPACE); 90459243Sobrien 90559243Sobrien if (endstr == NULL) 90659243Sobrien /* Exact matches only */ 907167465Smp for (p = *fblk; *p; p++) 908145479Smp gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0; 90959243Sobrien else { 910167465Smp const Char *end; 911167465Smp 91259243Sobrien /* partial matches */ 913167465Smp end = Strend(string); 914167465Smp for (p = *fblk; *p; p++) 915145479Smp if (t_pmatch(string, *p, &tstring, 1) != 0) { 91659243Sobrien gres |= 1; 917167465Smp if (end > tstring) 918167465Smp end = tstring; 91959243Sobrien } 920167465Smp *endstr = end; 92159243Sobrien } 92259243Sobrien 923167465Smp cleanup_until(fblk); 92459243Sobrien return(gres == gpol); 92559243Sobrien} 92659243Sobrien 927131962Smp/* t_pmatch(): 92859243Sobrien * Return 2 on exact match, 92959243Sobrien * Return 1 on substring match. 93059243Sobrien * Return 0 on no match. 93159243Sobrien * *estr will point to the end of the longest exact or substring match. 93259243Sobrien */ 933131962Smpint 934167465Smpt_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs) 93559243Sobrien{ 936167465Smp Char stringc, patternc, rangec; 93759243Sobrien int match, negate_range; 938167465Smp const Char *pestr, *nstring; 93959243Sobrien 940145479Smp for (nstring = string;; string = nstring) { 941167465Smp stringc = *nstring++ & TRIM; 942167465Smp patternc = *pattern++ & TRIM; 94359243Sobrien switch (patternc) { 944145479Smp case '\0': 94559243Sobrien *estr = string; 946145479Smp return (stringc == '\0' ? 2 : 1); 94759243Sobrien case '?': 94859243Sobrien if (stringc == 0) 94959243Sobrien return (0); 95059243Sobrien break; 95159243Sobrien case '*': 95259243Sobrien if (!*pattern) { 953167465Smp *estr = Strend(string); 95459243Sobrien return (2); 95559243Sobrien } 95659243Sobrien pestr = NULL; 95759243Sobrien 958145479Smp for (;;) { 959131962Smp switch(t_pmatch(string, pattern, estr, cs)) { 96059243Sobrien case 0: 96159243Sobrien break; 96259243Sobrien case 1: 963167465Smp pestr = *estr;/*FIXME: does not guarantee longest match */ 96459243Sobrien break; 96559243Sobrien case 2: 96659243Sobrien return 2; 96759243Sobrien default: 96859243Sobrien abort(); /* Cannot happen */ 96959243Sobrien } 970167465Smp stringc = *string++ & TRIM; 971145479Smp if (!stringc) 972145479Smp break; 97359243Sobrien } 97459243Sobrien 97559243Sobrien if (pestr) { 97659243Sobrien *estr = pestr; 97759243Sobrien return 1; 97859243Sobrien } 979167465Smp else 98059243Sobrien return 0; 98159243Sobrien 98259243Sobrien case '[': 98359243Sobrien match = 0; 98459243Sobrien if ((negate_range = (*pattern == '^')) != 0) 98559243Sobrien pattern++; 986167465Smp while ((rangec = *pattern++ & TRIM) != '\0') { 98759243Sobrien if (rangec == ']') 98859243Sobrien break; 98959243Sobrien if (match) 99059243Sobrien continue; 991145479Smp if (*pattern == '-' && pattern[1] != ']') { 992167465Smp Char rangec2; 99359243Sobrien pattern++; 994167465Smp rangec2 = *pattern++ & TRIM; 995145479Smp match = (globcharcoll(stringc, rangec2, 0) <= 0 && 996145479Smp globcharcoll(rangec, stringc, 0) <= 0); 99759243Sobrien } 99859243Sobrien else 999145479Smp match = (stringc == rangec); 100059243Sobrien } 1001145479Smp if (rangec == '\0') 100259243Sobrien stderror(ERR_NAME | ERR_MISSING, ']'); 1003145479Smp if ((!match) && (stringc == '\0')) 1004145479Smp return (0); 100559243Sobrien if (match == negate_range) 100659243Sobrien return (0); 100759243Sobrien break; 100859243Sobrien default: 1009145479Smp if (cs ? patternc != stringc 1010145479Smp : Tolower(patternc) != Tolower(stringc)) 101159243Sobrien return (0); 101259243Sobrien break; 101359243Sobrien } 101459243Sobrien } 101559243Sobrien} 1016