sh.glob.c revision 167465
1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.glob.c,v 3.74 2006/10/14 17:57:21 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.glob.c: Regular expression expansion 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35167465SmpRCSID("$tcsh: sh.glob.c,v 3.74 2006/10/14 17:57:21 christos Exp $") 3659243Sobrien 3759243Sobrien#include "tc.h" 38100616Smp#include "tw.h" 3959243Sobrien 4059243Sobrien#include "glob.h" 4159243Sobrien 4259243Sobrien/* 4359243Sobrien * Values for gflag 4459243Sobrien */ 4559243Sobrien#define G_NONE 0 /* No globbing needed */ 4659243Sobrien#define G_GLOB 1 /* string contains *?[] characters */ 4759243Sobrien#define G_CSH 2 /* string contains ~`{ characters */ 4859243Sobrien 4959243Sobrien#define GLOBSPACE 100 /* Alloc increment */ 5059243Sobrien 5159243Sobrien 5259243Sobrien#define LBRC '{' 5359243Sobrien#define RBRC '}' 5459243Sobrien#define LBRK '[' 5559243Sobrien#define RBRK ']' 5659243Sobrien#define EOS '\0' 5759243Sobrien 5859243Sobrien/* 5959243Sobrien * globbing is now done in two stages. In the first pass we expand 6059243Sobrien * csh globbing idioms ~`{ and then we proceed doing the normal 6159243Sobrien * globbing if needed ?*[ 6259243Sobrien * 6359243Sobrien * Csh type globbing is handled in globexpand() and the rest is 6459243Sobrien * handled in glob() which is part of the 4.4BSD libc. 6559243Sobrien * 6659243Sobrien */ 67167465Smpstatic Char *globtilde (Char *); 68167465Smpstatic Char *handleone (Char *, Char **, int); 69167465Smpstatic Char **libglob (Char **); 70167465Smpstatic Char **globexpand (Char **, int); 71167465Smpstatic int globbrace (const Char *, Char ***); 72167465Smpstatic void expbrace (Char ***, Char ***, int); 73167465Smpstatic void pword (struct blk_buf *, struct Strbuf *); 74167465Smpstatic void backeval (struct blk_buf *, struct Strbuf *, Char *, 75167465Smp int); 7659243Sobrienstatic Char * 77167465Smpglobtilde(Char *s) 7859243Sobrien{ 79167465Smp Char *name, *u, *home, *res; 8059243Sobrien 8159243Sobrien u = s; 82167465Smp for (s++; *s && *s != '/' && *s != ':'; s++) 8359243Sobrien continue; 84167465Smp name = Strnsave(u + 1, s - (u + 1)); 85167465Smp cleanup_push(name, xfree); 86167465Smp home = gethdir(name); 87167465Smp if (home == NULL) { 88167465Smp if (adrof(STRnonomatch)) { 89167465Smp cleanup_until(name); 90167465Smp return u; 91167465Smp } 92167465Smp if (*name) 93167465Smp stderror(ERR_UNKUSER, short2str(name)); 9459243Sobrien else 9559243Sobrien stderror(ERR_NOHOME); 9659243Sobrien } 97167465Smp cleanup_until(name); 98167465Smp if (home[0] == '/' && home[1] == '\0' && s[0] == '/') 99167465Smp res = Strsave(s); 100167465Smp else 101167465Smp res = Strspl(home, s); 102167465Smp xfree(home); 103167465Smp xfree(u); 104167465Smp return res; 10559243Sobrien} 10659243Sobrien 107167465Smp/* Returns a newly allocated string, old or NULL */ 10859243SobrienChar * 109167465Smpglobequal(Char *old) 11059243Sobrien{ 11159243Sobrien int dig; 112167465Smp const Char *dir; 113167465Smp Char *b; 11459243Sobrien 11559243Sobrien /* 11659243Sobrien * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names 11759243Sobrien * in stack. PWP: let =foobar pass through (for X windows) 11859243Sobrien */ 11959243Sobrien if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) { 12059243Sobrien /* =- */ 121167465Smp const Char *olddir = varval (STRowd); 122167465Smp 123167465Smp if (olddir && *olddir && 124167465Smp !dcwd->di_next->di_name && !dcwd->di_prev->di_name) 125167465Smp return Strspl(olddir, &old[2]); 12659243Sobrien dig = -1; 12759243Sobrien b = &old[2]; 12859243Sobrien } 12959243Sobrien else if (Isdigit(old[1])) { 13059243Sobrien /* =<number> */ 13159243Sobrien dig = old[1] - '0'; 13259243Sobrien for (b = &old[2]; Isdigit(*b); b++) 13359243Sobrien dig = dig * 10 + (*b - '0'); 13459243Sobrien if (*b != '\0' && *b != '/') 13559243Sobrien /* =<number>foobar */ 13659243Sobrien return old; 13759243Sobrien } 13859243Sobrien else 13959243Sobrien /* =foobar */ 14059243Sobrien return old; 14159243Sobrien 142167465Smp dir = getstakd(dig); 143167465Smp if (dir == NULL) 14459243Sobrien return NULL; 145167465Smp return Strspl(dir, b); 14659243Sobrien} 14759243Sobrien 14859243Sobrienstatic int 149167465Smpglobbrace(const Char *s, Char ***bl) 15059243Sobrien{ 151167465Smp struct Strbuf gbuf = Strbuf_INIT; 152167465Smp struct blk_buf bb = BLK_BUF_INIT; 153167465Smp int i; 154167465Smp const Char *p, *pm, *pe, *pl; 155167465Smp size_t prefix_len; 15659243Sobrien 15759243Sobrien /* copy part up to the brace */ 158167465Smp for (p = s; *p != LBRC; p++) 159167465Smp ; 160167465Smp prefix_len = p - s; 16159243Sobrien 16259243Sobrien /* check for balanced braces */ 16359243Sobrien for (i = 0, pe = ++p; *pe; pe++) 16459243Sobrien if (*pe == LBRK) { 16559243Sobrien /* Ignore everything between [] */ 16659243Sobrien for (++pe; *pe != RBRK && *pe != EOS; pe++) 16759243Sobrien continue; 168167465Smp if (*pe == EOS) 16959243Sobrien return (-RBRK); 17059243Sobrien } 17159243Sobrien else if (*pe == LBRC) 17259243Sobrien i++; 17359243Sobrien else if (*pe == RBRC) { 17459243Sobrien if (i == 0) 17559243Sobrien break; 17659243Sobrien i--; 17759243Sobrien } 17859243Sobrien 179167465Smp if (i != 0 || *pe == '\0') 18059243Sobrien return (-RBRC); 18159243Sobrien 182167465Smp Strbuf_appendn(&gbuf, s, prefix_len); 183167465Smp 18459243Sobrien for (i = 0, pl = pm = p; pm <= pe; pm++) 18559243Sobrien switch (*pm) { 18659243Sobrien case LBRK: 18759243Sobrien for (++pm; *pm != RBRK && *pm != EOS; pm++) 18859243Sobrien continue; 18959243Sobrien if (*pm == EOS) { 190167465Smp bb_cleanup(&bb); 191167465Smp xfree(gbuf.s); 19259243Sobrien return (-RBRK); 19359243Sobrien } 19459243Sobrien break; 19559243Sobrien case LBRC: 19659243Sobrien i++; 19759243Sobrien break; 19859243Sobrien case RBRC: 19959243Sobrien if (i) { 20059243Sobrien i--; 20159243Sobrien break; 20259243Sobrien } 20359243Sobrien /* FALLTHROUGH */ 20459243Sobrien case ',': 20559243Sobrien if (i && *pm == ',') 20659243Sobrien break; 20759243Sobrien else { 208167465Smp gbuf.len = prefix_len; 209167465Smp Strbuf_appendn(&gbuf, pl, pm - pl); 210167465Smp Strbuf_append(&gbuf, pe + 1); 211167465Smp Strbuf_terminate(&gbuf); 212167465Smp bb_append(&bb, Strsave(gbuf.s)); 21359243Sobrien pl = pm + 1; 21459243Sobrien } 21559243Sobrien break; 21659243Sobrien default: 21759243Sobrien break; 21859243Sobrien } 219167465Smp *bl = bb_finish(&bb); 220167465Smp xfree(gbuf.s); 221167465Smp return bb.len; 22259243Sobrien} 22359243Sobrien 22459243Sobrien 22559243Sobrienstatic void 226167465Smpexpbrace(Char ***nvp, Char ***elp, int size) 22759243Sobrien{ 22859243Sobrien Char **vl, **el, **nv, *s; 22959243Sobrien 23059243Sobrien vl = nv = *nvp; 23159243Sobrien if (elp != NULL) 23259243Sobrien el = *elp; 23359243Sobrien else 234167465Smp el = vl + blklen(vl); 23559243Sobrien 23659243Sobrien for (s = *vl; s; s = *++vl) { 23759243Sobrien Char **vp, **bp; 23859243Sobrien 23959243Sobrien /* leave {} untouched for find */ 24059243Sobrien if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 24159243Sobrien continue; 242167465Smp if (Strchr(s, '{') != NULL) { 243167465Smp Char **bl = NULL; 24459243Sobrien int len; 24559243Sobrien 246167465Smp if ((len = globbrace(s, &bl)) < 0) 24759243Sobrien stderror(ERR_MISSING, -len); 248167465Smp xfree(s); 24959243Sobrien if (len == 1) { 25059243Sobrien *vl-- = *bl; 251167465Smp xfree(bl); 25259243Sobrien continue; 25359243Sobrien } 25459243Sobrien if (&el[len] >= &nv[size]) { 255167465Smp size_t l, e; 256167465Smp l = &el[len] - &nv[size]; 25759243Sobrien size += GLOBSPACE > l ? GLOBSPACE : l; 258167465Smp l = vl - nv; 259167465Smp e = el - nv; 260167465Smp nv = xrealloc(nv, size * sizeof(Char *)); 261167465Smp *nvp = nv; /* To keep cleanups working */ 26259243Sobrien vl = nv + l; 26359243Sobrien el = nv + e; 26459243Sobrien } 26559243Sobrien /* nv vl el bl 26659243Sobrien * | | | | 26759243Sobrien * -.--..-- x-- 26859243Sobrien * | len 26959243Sobrien * vp 27059243Sobrien */ 27159243Sobrien vp = vl--; 27259243Sobrien *vp = *bl; 27359243Sobrien len--; 27459243Sobrien for (bp = el; bp != vp; bp--) 27559243Sobrien bp[len] = *bp; 27659243Sobrien el += len; 27759243Sobrien /* nv vl el bl 27859243Sobrien * | | | | 27959243Sobrien * -.-x --- -- 28059243Sobrien * |len 28159243Sobrien * vp 28259243Sobrien */ 28359243Sobrien vp++; 28459243Sobrien for (bp = bl + 1; *bp; *vp++ = *bp++) 28559243Sobrien continue; 286167465Smp xfree(bl); 28759243Sobrien } 28859243Sobrien 28959243Sobrien } 29059243Sobrien if (elp != NULL) 29159243Sobrien *elp = el; 29259243Sobrien} 29359243Sobrien 29459243Sobrienstatic Char ** 295167465Smpglobexpand(Char **v, int noglob) 29659243Sobrien{ 29759243Sobrien Char *s; 298167465Smp Char ***fnv, **vl, **el; 29959243Sobrien int size = GLOBSPACE; 30059243Sobrien 30159243Sobrien 302167465Smp fnv = xmalloc(sizeof(Char ***)); 303167465Smp *fnv = vl = xmalloc(sizeof(Char *) * size); 30459243Sobrien *vl = NULL; 305167465Smp cleanup_push(fnv, blk_indirect_cleanup); 30659243Sobrien 30759243Sobrien /* 30859243Sobrien * Step 1: expand backquotes. 30959243Sobrien */ 31059243Sobrien while ((s = *v++) != '\0') { 31159243Sobrien if (Strchr(s, '`')) { 31259243Sobrien int i; 313167465Smp Char **expanded; 31459243Sobrien 315167465Smp expanded = dobackp(s, 0); 316167465Smp for (i = 0; expanded[i] != NULL; i++) { 317167465Smp *vl++ = expanded[i]; 318167465Smp if (vl == &(*fnv)[size]) { 31959243Sobrien size += GLOBSPACE; 320167465Smp *fnv = xrealloc(*fnv, size * sizeof(Char *)); 321167465Smp vl = &(*fnv)[size - GLOBSPACE]; 32259243Sobrien } 32359243Sobrien } 324167465Smp xfree(expanded); 32559243Sobrien } 32659243Sobrien else { 32759243Sobrien *vl++ = Strsave(s); 328167465Smp if (vl == &(*fnv)[size]) { 32959243Sobrien size += GLOBSPACE; 330167465Smp *fnv = xrealloc(*fnv, size * sizeof(Char *)); 331167465Smp vl = &(*fnv)[size - GLOBSPACE]; 33259243Sobrien } 33359243Sobrien } 334167465Smp *vl = NULL; 33559243Sobrien } 33659243Sobrien 33759243Sobrien if (noglob) 338167465Smp goto done; 33959243Sobrien 34059243Sobrien /* 34159243Sobrien * Step 2: expand braces 34259243Sobrien */ 34359243Sobrien el = vl; 344167465Smp expbrace(fnv, &el, size); 34559243Sobrien 34659243Sobrien 34759243Sobrien /* 34859243Sobrien * Step 3: expand ~ = 34959243Sobrien */ 350167465Smp vl = *fnv; 35159243Sobrien for (s = *vl; s; s = *++vl) 35259243Sobrien switch (*s) { 353167465Smp Char *ns; 35459243Sobrien case '~': 355167465Smp *vl = globtilde(s); 35659243Sobrien break; 35759243Sobrien case '=': 358167465Smp if ((ns = globequal(s)) == NULL) { 359167465Smp if (!adrof(STRnonomatch)) 360167465Smp stderror(ERR_DEEP); /* Error */ 36159243Sobrien } 36259243Sobrien if (ns && ns != s) { 36359243Sobrien /* Expansion succeeded */ 364167465Smp xfree(s); 365167465Smp *vl = ns; 36659243Sobrien } 36759243Sobrien break; 36859243Sobrien default: 36959243Sobrien break; 37059243Sobrien } 371167465Smp vl = *fnv; 37259243Sobrien 37359243Sobrien /* 37459243Sobrien * Step 4: expand .. if the variable symlinks==expand is set 37559243Sobrien */ 37683098Smp if (symlinks == SYM_EXPAND) { 37759243Sobrien for (s = *vl; s; s = *++vl) { 37883098Smp *vl = dnormalize(s, 1); 379167465Smp xfree(s); 38059243Sobrien } 38183098Smp } 38259243Sobrien 383167465Smp done: 384167465Smp cleanup_ignore(fnv); 385167465Smp cleanup_until(fnv); 386167465Smp vl = *fnv; 387167465Smp xfree(fnv); 388167465Smp return vl; 38959243Sobrien} 39059243Sobrien 39159243Sobrienstatic Char * 392167465Smphandleone(Char *str, Char **vl, int action) 39359243Sobrien{ 394167465Smp size_t chars; 39559243Sobrien Char **t, *p, *strp; 39659243Sobrien 39759243Sobrien switch (action) { 39859243Sobrien case G_ERROR: 39959243Sobrien setname(short2str(str)); 40059243Sobrien blkfree(vl); 40159243Sobrien stderror(ERR_NAME | ERR_AMBIG); 40259243Sobrien break; 40359243Sobrien case G_APPEND: 40459243Sobrien chars = 0; 405167465Smp for (t = vl; (p = *t++) != NULL; chars++) 406167465Smp chars += Strlen(p); 407167465Smp str = xmalloc(chars * sizeof(Char)); 408167465Smp for (t = vl, strp = str; (p = *t++) != '\0'; chars++) { 40959243Sobrien while (*p) 41059243Sobrien *strp++ = *p++ & TRIM; 41159243Sobrien *strp++ = ' '; 41259243Sobrien } 41359243Sobrien *--strp = '\0'; 41459243Sobrien blkfree(vl); 41559243Sobrien break; 41659243Sobrien case G_IGNORE: 417167465Smp str = Strsave(strip(*vl)); 41859243Sobrien blkfree(vl); 41959243Sobrien break; 42059243Sobrien default: 42159243Sobrien break; 42259243Sobrien } 42359243Sobrien return (str); 42459243Sobrien} 42559243Sobrien 42659243Sobrienstatic Char ** 427167465Smplibglob(Char **vl) 42859243Sobrien{ 42959243Sobrien int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT; 43059243Sobrien glob_t globv; 43159243Sobrien char *ptr; 43259243Sobrien int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; 43359243Sobrien 43459243Sobrien if (!vl || !vl[0]) 43559243Sobrien return(vl); 43659243Sobrien 43759243Sobrien globv.gl_offs = 0; 43859243Sobrien globv.gl_pathv = 0; 43959243Sobrien globv.gl_pathc = 0; 44059243Sobrien 44159243Sobrien if (nonomatch) 44259243Sobrien gflgs |= GLOB_NOCHECK; 44359243Sobrien 44459243Sobrien do { 44559243Sobrien ptr = short2qstr(*vl); 44659243Sobrien switch (glob(ptr, gflgs, 0, &globv)) { 44759243Sobrien case GLOB_ABEND: 44859243Sobrien globfree(&globv); 44959243Sobrien setname(ptr); 45059243Sobrien stderror(ERR_NAME | ERR_GLOB); 45159243Sobrien /* NOTREACHED */ 45259243Sobrien case GLOB_NOSPACE: 45359243Sobrien globfree(&globv); 45459243Sobrien stderror(ERR_NOMEM); 45559243Sobrien /* NOTREACHED */ 45659243Sobrien default: 45759243Sobrien break; 45859243Sobrien } 45959243Sobrien if (globv.gl_flags & GLOB_MAGCHAR) { 46059243Sobrien match |= (globv.gl_matchc != 0); 46159243Sobrien magic = 1; 46259243Sobrien } 46359243Sobrien gflgs |= GLOB_APPEND; 46459243Sobrien } 46559243Sobrien while (*++vl); 46659243Sobrien vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 46759243Sobrien NULL : blk2short(globv.gl_pathv); 46859243Sobrien globfree(&globv); 46959243Sobrien return (vl); 47059243Sobrien} 47159243Sobrien 47259243SobrienChar * 473167465Smpglobone(Char *str, int action) 47459243Sobrien{ 47559243Sobrien Char *v[2], **vl, **vo; 476167465Smp int gflg, noglob; 47759243Sobrien 47859243Sobrien noglob = adrof(STRnoglob) != 0; 47959243Sobrien v[0] = str; 48059243Sobrien v[1] = 0; 481167465Smp gflg = tglob(v); 48259243Sobrien if (gflg == G_NONE) 48359243Sobrien return (strip(Strsave(str))); 48459243Sobrien 48559243Sobrien if (gflg & G_CSH) { 48659243Sobrien /* 48759243Sobrien * Expand back-quote, tilde and brace 48859243Sobrien */ 489167465Smp vo = globexpand(v, noglob); 49059243Sobrien if (noglob || (gflg & G_GLOB) == 0) { 491167465Smp vl = vo; 492167465Smp goto result; 49359243Sobrien } 494167465Smp cleanup_push(vo, blk_cleanup); 49559243Sobrien } 49659243Sobrien else if (noglob || (gflg & G_GLOB) == 0) 49759243Sobrien return (strip(Strsave(str))); 49859243Sobrien else 49959243Sobrien vo = v; 50059243Sobrien 50159243Sobrien vl = libglob(vo); 502167465Smp if (gflg & G_CSH) { 503167465Smp if (vl != vo) 504167465Smp cleanup_until(vo); 505167465Smp else 506167465Smp cleanup_ignore(vo); 507167465Smp } 50859243Sobrien if (vl == NULL) { 50959243Sobrien setname(short2str(str)); 51059243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 51159243Sobrien } 512167465Smp result: 51359243Sobrien if (vl[0] == NULL) { 514167465Smp xfree(vl); 51559243Sobrien return (Strsave(STRNULL)); 51659243Sobrien } 51759243Sobrien if (vl[1]) 51859243Sobrien return (handleone(str, vl, action)); 51959243Sobrien else { 52059243Sobrien str = strip(*vl); 521167465Smp xfree(vl); 52259243Sobrien return (str); 52359243Sobrien } 52459243Sobrien} 52559243Sobrien 52659243SobrienChar ** 527167465Smpgloball(Char **v, int gflg) 52859243Sobrien{ 52959243Sobrien Char **vl, **vo; 530167465Smp int noglob; 53159243Sobrien 532167465Smp if (!v || !v[0]) 533167465Smp return saveblk(v); 53459243Sobrien 53559243Sobrien noglob = adrof(STRnoglob) != 0; 53659243Sobrien 53759243Sobrien if (gflg & G_CSH) 53859243Sobrien /* 53959243Sobrien * Expand back-quote, tilde and brace 54059243Sobrien */ 541167465Smp vl = vo = globexpand(v, noglob); 54259243Sobrien else 54359243Sobrien vl = vo = saveblk(v); 54459243Sobrien 54559243Sobrien if (!noglob && (gflg & G_GLOB)) { 546167465Smp cleanup_push(vo, blk_cleanup); 54759243Sobrien vl = libglob(vo); 548167465Smp if (vl == vo) 549167465Smp cleanup_ignore(vo); 550167465Smp cleanup_until(vo); 55159243Sobrien } 55259243Sobrien else 55359243Sobrien trim(vl); 55459243Sobrien 555167465Smp return vl; 55659243Sobrien} 55759243Sobrien 558167465SmpChar ** 559167465Smpglob_all_or_error(Char **v) 56059243Sobrien{ 561167465Smp int gflag; 562167465Smp 563167465Smp gflag = tglob(v); 564167465Smp if (gflag) { 565167465Smp v = globall(v, gflag); 566167465Smp if (v == NULL) 567167465Smp stderror(ERR_NAME | ERR_NOMATCH); 568167465Smp } else { 569167465Smp v = saveblk(v); 570167465Smp trim(v); 571167465Smp } 572167465Smp return v; 57359243Sobrien} 57459243Sobrien 57559243Sobrienvoid 576167465Smprscan(Char **t, void (*f) (Char)) 57759243Sobrien{ 578145479Smp Char *p; 57959243Sobrien 58059243Sobrien while ((p = *t++) != '\0') 58159243Sobrien while (*p) 58259243Sobrien (*f) (*p++); 58359243Sobrien} 58459243Sobrien 58559243Sobrienvoid 586167465Smptrim(Char **t) 58759243Sobrien{ 588145479Smp Char *p; 58959243Sobrien 59059243Sobrien while ((p = *t++) != '\0') 59159243Sobrien while (*p) 59259243Sobrien *p++ &= TRIM; 59359243Sobrien} 59459243Sobrien 595167465Smpint 596167465Smptglob(Char **t) 59759243Sobrien{ 598167465Smp int gflag; 599167465Smp const Char *p; 60059243Sobrien 601167465Smp gflag = 0; 60259243Sobrien while ((p = *t++) != '\0') { 60359243Sobrien if (*p == '~' || *p == '=') 60459243Sobrien gflag |= G_CSH; 60559243Sobrien else if (*p == '{' && 60659243Sobrien (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 60759243Sobrien continue; 608167465Smp while (*p != '\0') { 609167465Smp if (*p == '`') { 61059243Sobrien gflag |= G_CSH; 61159243Sobrien#ifdef notdef 61259243Sobrien /* 61359243Sobrien * We do want to expand echo `echo '*'`, so we don't\ 61459243Sobrien * use this piece of code anymore. 61559243Sobrien */ 616167465Smp p++; 61759243Sobrien while (*p && *p != '`') 61859243Sobrien if (*p++ == '\\') { 61959243Sobrien if (*p) /* Quoted chars */ 62059243Sobrien p++; 62159243Sobrien else 62259243Sobrien break; 62359243Sobrien } 624167465Smp if (!*p) /* The matching ` */ 62559243Sobrien break; 62659243Sobrien#endif 62759243Sobrien } 628167465Smp else if (*p == '{') 62959243Sobrien gflag |= G_CSH; 630167465Smp else if (isglob(*p)) 63159243Sobrien gflag |= G_GLOB; 63259243Sobrien else if (symlinks == SYM_EXPAND && 633167465Smp p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') ) 63459243Sobrien gflag |= G_CSH; 635167465Smp p++; 63659243Sobrien } 63759243Sobrien } 638167465Smp return gflag; 63959243Sobrien} 64059243Sobrien 64159243Sobrien/* 64259243Sobrien * Command substitute cp. If literal, then this is a substitution from a 64359243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating 64459243Sobrien * words only at newlines. 64559243Sobrien */ 64659243SobrienChar ** 647167465Smpdobackp(Char *cp, int literal) 64859243Sobrien{ 649167465Smp struct Strbuf word = Strbuf_INIT; 650167465Smp struct blk_buf bb = BLK_BUF_INIT; 651167465Smp Char *lp, *rp, *ep; 65259243Sobrien 653167465Smp cleanup_push(&bb, bb_cleanup); 654167465Smp cleanup_push(&word, Strbuf_cleanup); 65559243Sobrien for (;;) { 656167465Smp for (lp = cp; *lp != '\0' && *lp != '`'; lp++) 657167465Smp ; 658167465Smp Strbuf_appendn(&word, cp, lp - cp); 659167465Smp if (*lp == 0) 660167465Smp break; 66159243Sobrien lp++; 66259243Sobrien for (rp = lp; *rp && *rp != '`'; rp++) 66359243Sobrien if (*rp == '\\') { 66459243Sobrien rp++; 66559243Sobrien if (!*rp) 66659243Sobrien goto oops; 66759243Sobrien } 668167465Smp if (!*rp) { 669167465Smp oops: 670167465Smp stderror(ERR_UNMATCHED, '`'); 671167465Smp } 672167465Smp ep = Strnsave(lp, rp - lp); 673167465Smp cleanup_push(ep, xfree); 674167465Smp backeval(&bb, &word, ep, literal); 675167465Smp cleanup_until(ep); 67659243Sobrien cp = rp + 1; 67759243Sobrien } 678167465Smp if (word.len != 0) 679167465Smp pword(&bb, &word); 680167465Smp cleanup_ignore(&bb); 681167465Smp cleanup_until(&bb); 682167465Smp return bb_finish(&bb); 68359243Sobrien} 68459243Sobrien 68559243Sobrien 68659243Sobrienstatic void 687167465Smpbackeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal) 68859243Sobrien{ 689145479Smp int icnt; 690145479Smp Char c, *ip; 69159243Sobrien struct command faket; 692145479Smp int hadnl; 69359243Sobrien int pvec[2], quoted; 69459243Sobrien Char *fakecom[2], ibuf[BUFSIZE]; 69559243Sobrien char tibuf[BUFSIZE]; 69659243Sobrien 69759243Sobrien hadnl = 0; 69859243Sobrien icnt = 0; 69959243Sobrien quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 70059243Sobrien faket.t_dtyp = NODE_COMMAND; 70159243Sobrien faket.t_dflg = F_BACKQ; 70259243Sobrien faket.t_dlef = 0; 70359243Sobrien faket.t_drit = 0; 70459243Sobrien faket.t_dspr = 0; 70559243Sobrien faket.t_dcom = fakecom; 70659243Sobrien fakecom[0] = STRfakecom1; 70759243Sobrien fakecom[1] = 0; 70859243Sobrien 70959243Sobrien /* 71059243Sobrien * We do the psave job to temporarily change the current job so that the 71159243Sobrien * following fork is considered a separate job. This is so that when 71259243Sobrien * backquotes are used in a builtin function that calls glob the "current 71359243Sobrien * job" is not corrupted. We only need one level of pushed jobs as long as 71459243Sobrien * we are sure to fork here. 71559243Sobrien */ 71659243Sobrien psavejob(); 717167465Smp cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */ 71859243Sobrien 71959243Sobrien /* 72059243Sobrien * It would be nicer if we could integrate this redirection more with the 72159243Sobrien * routines in sh.sem.c by doing a fake execute on a builtin function that 72259243Sobrien * was piped out. 72359243Sobrien */ 72459243Sobrien mypipe(pvec); 725167465Smp cleanup_push(&pvec[0], open_cleanup); 726167465Smp cleanup_push(&pvec[1], open_cleanup); 72759243Sobrien if (pfork(&faket, -1) == 0) { 728145479Smp jmp_buf_t osetexit; 729167465Smp struct command *t; 730167465Smp size_t omark; 73159243Sobrien 732167465Smp xclose(pvec[0]); 73359243Sobrien (void) dmove(pvec[1], 1); 73459243Sobrien (void) dmove(SHDIAG, 2); 73559243Sobrien initdesc(); 736100616Smp closem(); 73759243Sobrien arginp = cp; 738100616Smp for (arginp = cp; *cp; cp++) { 739100616Smp *cp &= TRIM; 740145479Smp if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r')) 741100616Smp *cp = ' '; 742100616Smp } 74359243Sobrien 74459243Sobrien /* 74559243Sobrien * In the child ``forget'' everything about current aliases or 74659243Sobrien * eval vectors. 74759243Sobrien */ 74859243Sobrien alvec = NULL; 74959243Sobrien evalvec = NULL; 75059243Sobrien alvecp = NULL; 75159243Sobrien evalp = NULL; 752145479Smp 753167465Smp omark = cleanup_push_mark(); 754145479Smp getexit(osetexit); 755145479Smp for (;;) { 756145479Smp (void) setexit(); 757145479Smp justpr = 0; 758145479Smp 759145479Smp if (haderr) { 760145479Smp /* unwind */ 761145479Smp doneinp = 0; 762167465Smp cleanup_pop_mark(omark); 763145479Smp resexit(osetexit); 764145479Smp reset(); 765145479Smp } 766145479Smp if (seterr) { 767167465Smp xfree(seterr); 768145479Smp seterr = NULL; 769145479Smp } 770145479Smp 771145479Smp (void) lex(¶ml); 772167465Smp cleanup_push(¶ml, lex_cleanup); 773145479Smp if (seterr) 774145479Smp stderror(ERR_OLD); 775145479Smp alias(¶ml); 776145479Smp t = syntax(paraml.next, ¶ml, 0); 777167465Smp cleanup_push(t, syntax_cleanup); 778145479Smp if (seterr) 779145479Smp stderror(ERR_OLD); 78059243Sobrien#ifdef SIGTSTP 781167465Smp signal(SIGTSTP, SIG_IGN); 78259243Sobrien#endif 78359243Sobrien#ifdef SIGTTIN 784167465Smp signal(SIGTTIN, SIG_IGN); 78559243Sobrien#endif 78659243Sobrien#ifdef SIGTTOU 787167465Smp signal(SIGTTOU, SIG_IGN); 78859243Sobrien#endif 789145479Smp execute(t, -1, NULL, NULL, TRUE); 790145479Smp 791167465Smp cleanup_until(¶ml); 792145479Smp } 79359243Sobrien } 794167465Smp cleanup_until(&pvec[1]); 79559243Sobrien c = 0; 79659243Sobrien ip = NULL; 79759243Sobrien do { 79859243Sobrien int cnt = 0; 799145479Smp char *tmp; 80059243Sobrien 801145479Smp tmp = tibuf; 80259243Sobrien for (;;) { 803145479Smp while (icnt == 0) { 804145479Smp int i, eof; 80559243Sobrien 80659243Sobrien ip = ibuf; 807167465Smp icnt = xread(pvec[0], tmp, tibuf + BUFSIZE - tmp); 808145479Smp eof = 0; 80959243Sobrien if (icnt <= 0) { 810145479Smp if (tmp == tibuf) 811145479Smp goto eof; 812145479Smp icnt = 0; 813145479Smp eof = 1; 81459243Sobrien } 815145479Smp icnt += tmp - tibuf; 816145479Smp i = 0; 817145479Smp tmp = tibuf; 818145479Smp while (tmp < tibuf + icnt) { 819145479Smp int len; 820145479Smp 821145479Smp len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp); 822145479Smp if (len == -1) { 823145479Smp reset_mbtowc(); 824145479Smp if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) { 825145479Smp break; /* Maybe a partial character */ 826145479Smp } 827145479Smp ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */ 828145479Smp } 829145479Smp if (len <= 0) 830145479Smp len = 1; 831145479Smp i++; 832145479Smp tmp += len; 833145479Smp } 834145479Smp if (tmp != tibuf) 835145479Smp memmove (tibuf, tmp, tibuf + icnt - tmp); 836145479Smp tmp = tibuf + (tibuf + icnt - tmp); 837145479Smp icnt = i; 83859243Sobrien } 83959243Sobrien if (hadnl) 84059243Sobrien break; 84159243Sobrien --icnt; 84259243Sobrien c = (*ip++ & TRIM); 84359243Sobrien if (c == 0) 84459243Sobrien break; 84569408Sache#ifdef WINNT_NATIVE 84659243Sobrien if (c == '\r') 84759243Sobrien c = ' '; 84869408Sache#endif /* WINNT_NATIVE */ 84959243Sobrien if (c == '\n') { 85059243Sobrien /* 85159243Sobrien * Continue around the loop one more time, so that we can eat 85259243Sobrien * the last newline without terminating this word. 85359243Sobrien */ 85459243Sobrien hadnl = 1; 85559243Sobrien continue; 85659243Sobrien } 85759243Sobrien if (!quoted && (c == ' ' || c == '\t')) 85859243Sobrien break; 85959243Sobrien cnt++; 860167465Smp Strbuf_append1(word, c | quoted); 86159243Sobrien } 86259243Sobrien /* 86359243Sobrien * Unless at end-of-file, we will form a new word here if there were 86459243Sobrien * characters in the word, or in any case when we take text literally. 86559243Sobrien * If we didn't make empty words here when literal was set then we 86659243Sobrien * would lose blank lines. 86759243Sobrien */ 868145479Smp if (c != 0 && (cnt || literal)) 869167465Smp pword(bb, word); 87059243Sobrien hadnl = 0; 871145479Smp } while (c > 0); 872145479Smp eof: 873167465Smp cleanup_until(&pvec[0]); 87459243Sobrien pwait(); 875167465Smp cleanup_until(&faket); /* psavejob_cleanup(); */ 87659243Sobrien} 87759243Sobrien 87859243Sobrienstatic void 879167465Smppword(struct blk_buf *bb, struct Strbuf *word) 88059243Sobrien{ 881167465Smp Char *s; 88259243Sobrien 883167465Smp s = Strbuf_finish(word); 884167465Smp bb_append(bb, s); 885167465Smp *word = Strbuf_init; 88659243Sobrien} 88759243Sobrien 88859243Sobrienint 889167465SmpGmatch(const Char *string, const Char *pattern) 89059243Sobrien{ 89159243Sobrien return Gnmatch(string, pattern, NULL); 89259243Sobrien} 89359243Sobrien 894167465Smpint 895167465SmpGnmatch(const Char *string, const Char *pattern, const Char **endstr) 89659243Sobrien{ 897167465Smp Char ***fblk, **p; 898167465Smp const Char *tstring = string; 89959243Sobrien int gpol = 1, gres = 0; 90059243Sobrien 90159243Sobrien if (*pattern == '^') { 90259243Sobrien gpol = 0; 90359243Sobrien pattern++; 90459243Sobrien } 90559243Sobrien 906167465Smp fblk = xmalloc(sizeof(Char ***)); 907167465Smp *fblk = xmalloc(GLOBSPACE * sizeof(Char *)); 908167465Smp (*fblk)[0] = Strsave(pattern); 909167465Smp (*fblk)[1] = NULL; 91059243Sobrien 911167465Smp cleanup_push(fblk, blk_indirect_cleanup); 912167465Smp expbrace(fblk, NULL, GLOBSPACE); 91359243Sobrien 91459243Sobrien if (endstr == NULL) 91559243Sobrien /* Exact matches only */ 916167465Smp for (p = *fblk; *p; p++) 917145479Smp gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0; 91859243Sobrien else { 919167465Smp const Char *end; 920167465Smp 92159243Sobrien /* partial matches */ 922167465Smp end = Strend(string); 923167465Smp for (p = *fblk; *p; p++) 924145479Smp if (t_pmatch(string, *p, &tstring, 1) != 0) { 92559243Sobrien gres |= 1; 926167465Smp if (end > tstring) 927167465Smp end = tstring; 92859243Sobrien } 929167465Smp *endstr = end; 93059243Sobrien } 93159243Sobrien 932167465Smp cleanup_until(fblk); 93359243Sobrien return(gres == gpol); 93459243Sobrien} 93559243Sobrien 936131962Smp/* t_pmatch(): 93759243Sobrien * Return 2 on exact match, 93859243Sobrien * Return 1 on substring match. 93959243Sobrien * Return 0 on no match. 94059243Sobrien * *estr will point to the end of the longest exact or substring match. 94159243Sobrien */ 942131962Smpint 943167465Smpt_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs) 94459243Sobrien{ 945167465Smp Char stringc, patternc, rangec; 94659243Sobrien int match, negate_range; 947167465Smp const Char *pestr, *nstring; 94859243Sobrien 949145479Smp for (nstring = string;; string = nstring) { 950167465Smp stringc = *nstring++ & TRIM; 951167465Smp patternc = *pattern++ & TRIM; 95259243Sobrien switch (patternc) { 953145479Smp case '\0': 95459243Sobrien *estr = string; 955145479Smp return (stringc == '\0' ? 2 : 1); 95659243Sobrien case '?': 95759243Sobrien if (stringc == 0) 95859243Sobrien return (0); 95959243Sobrien break; 96059243Sobrien case '*': 96159243Sobrien if (!*pattern) { 962167465Smp *estr = Strend(string); 96359243Sobrien return (2); 96459243Sobrien } 96559243Sobrien pestr = NULL; 96659243Sobrien 967145479Smp for (;;) { 968131962Smp switch(t_pmatch(string, pattern, estr, cs)) { 96959243Sobrien case 0: 97059243Sobrien break; 97159243Sobrien case 1: 972167465Smp pestr = *estr;/*FIXME: does not guarantee longest match */ 97359243Sobrien break; 97459243Sobrien case 2: 97559243Sobrien return 2; 97659243Sobrien default: 97759243Sobrien abort(); /* Cannot happen */ 97859243Sobrien } 979167465Smp stringc = *string++ & TRIM; 980145479Smp if (!stringc) 981145479Smp break; 98259243Sobrien } 98359243Sobrien 98459243Sobrien if (pestr) { 98559243Sobrien *estr = pestr; 98659243Sobrien return 1; 98759243Sobrien } 988167465Smp else 98959243Sobrien return 0; 99059243Sobrien 99159243Sobrien case '[': 99259243Sobrien match = 0; 99359243Sobrien if ((negate_range = (*pattern == '^')) != 0) 99459243Sobrien pattern++; 995167465Smp while ((rangec = *pattern++ & TRIM) != '\0') { 99659243Sobrien if (rangec == ']') 99759243Sobrien break; 99859243Sobrien if (match) 99959243Sobrien continue; 1000145479Smp if (*pattern == '-' && pattern[1] != ']') { 1001167465Smp Char rangec2; 100259243Sobrien pattern++; 1003167465Smp rangec2 = *pattern++ & TRIM; 1004145479Smp match = (globcharcoll(stringc, rangec2, 0) <= 0 && 1005145479Smp globcharcoll(rangec, stringc, 0) <= 0); 100659243Sobrien } 100759243Sobrien else 1008145479Smp match = (stringc == rangec); 100959243Sobrien } 1010145479Smp if (rangec == '\0') 101159243Sobrien stderror(ERR_NAME | ERR_MISSING, ']'); 1012145479Smp if ((!match) && (stringc == '\0')) 1013145479Smp return (0); 101459243Sobrien if (match == negate_range) 101559243Sobrien return (0); 101659243Sobrien break; 101759243Sobrien default: 1018145479Smp if (cs ? patternc != stringc 1019145479Smp : Tolower(patternc) != Tolower(stringc)) 102059243Sobrien return (0); 102159243Sobrien break; 102259243Sobrien } 102359243Sobrien } 102459243Sobrien} 1025