1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.glob.c,v 3.82 2011/02/27 00:15:17 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 35232633SmpRCSID("$tcsh: sh.glob.c,v 3.82 2011/02/27 00:15:17 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 434232633Smp if (adrof(STRglobdot)) 435232633Smp gflgs |= GLOB_DOT; 436232633Smp 437232633Smp if (adrof(STRglobstar)) 438232633Smp gflgs |= GLOB_STAR; 439232633Smp 44059243Sobrien if (!vl || !vl[0]) 44159243Sobrien return(vl); 44259243Sobrien 44359243Sobrien globv.gl_offs = 0; 44459243Sobrien globv.gl_pathv = 0; 44559243Sobrien globv.gl_pathc = 0; 44659243Sobrien 44759243Sobrien if (nonomatch) 44859243Sobrien gflgs |= GLOB_NOCHECK; 44959243Sobrien 45059243Sobrien do { 45159243Sobrien ptr = short2qstr(*vl); 45259243Sobrien switch (glob(ptr, gflgs, 0, &globv)) { 45359243Sobrien case GLOB_ABEND: 45459243Sobrien globfree(&globv); 45559243Sobrien setname(ptr); 45659243Sobrien stderror(ERR_NAME | ERR_GLOB); 45759243Sobrien /* NOTREACHED */ 45859243Sobrien case GLOB_NOSPACE: 45959243Sobrien globfree(&globv); 46059243Sobrien stderror(ERR_NOMEM); 46159243Sobrien /* NOTREACHED */ 46259243Sobrien default: 46359243Sobrien break; 46459243Sobrien } 46559243Sobrien if (globv.gl_flags & GLOB_MAGCHAR) { 46659243Sobrien match |= (globv.gl_matchc != 0); 46759243Sobrien magic = 1; 46859243Sobrien } 46959243Sobrien gflgs |= GLOB_APPEND; 47059243Sobrien } 47159243Sobrien while (*++vl); 47259243Sobrien vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 47359243Sobrien NULL : blk2short(globv.gl_pathv); 47459243Sobrien globfree(&globv); 47559243Sobrien return (vl); 47659243Sobrien} 47759243Sobrien 47859243SobrienChar * 479167465Smpglobone(Char *str, int action) 48059243Sobrien{ 48159243Sobrien Char *v[2], **vl, **vo; 482167465Smp int gflg, noglob; 48359243Sobrien 48459243Sobrien noglob = adrof(STRnoglob) != 0; 48559243Sobrien v[0] = str; 48659243Sobrien v[1] = 0; 487167465Smp gflg = tglob(v); 48859243Sobrien if (gflg == G_NONE) 48959243Sobrien return (strip(Strsave(str))); 49059243Sobrien 49159243Sobrien if (gflg & G_CSH) { 49259243Sobrien /* 49359243Sobrien * Expand back-quote, tilde and brace 49459243Sobrien */ 495167465Smp vo = globexpand(v, noglob); 49659243Sobrien if (noglob || (gflg & G_GLOB) == 0) { 497167465Smp vl = vo; 498167465Smp goto result; 49959243Sobrien } 500167465Smp cleanup_push(vo, blk_cleanup); 50159243Sobrien } 50259243Sobrien else if (noglob || (gflg & G_GLOB) == 0) 50359243Sobrien return (strip(Strsave(str))); 50459243Sobrien else 50559243Sobrien vo = v; 50659243Sobrien 50759243Sobrien vl = libglob(vo); 508167465Smp if (gflg & G_CSH) { 509167465Smp if (vl != vo) 510167465Smp cleanup_until(vo); 511167465Smp else 512167465Smp cleanup_ignore(vo); 513167465Smp } 51459243Sobrien if (vl == NULL) { 51559243Sobrien setname(short2str(str)); 51659243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 51759243Sobrien } 518167465Smp result: 519232633Smp if (vl && vl[0] == NULL) { 520167465Smp xfree(vl); 52159243Sobrien return (Strsave(STRNULL)); 52259243Sobrien } 523232633Smp if (vl && vl[1]) 52459243Sobrien return (handleone(str, vl, action)); 52559243Sobrien else { 52659243Sobrien str = strip(*vl); 527167465Smp xfree(vl); 52859243Sobrien return (str); 52959243Sobrien } 53059243Sobrien} 53159243Sobrien 53259243SobrienChar ** 533167465Smpgloball(Char **v, int gflg) 53459243Sobrien{ 53559243Sobrien Char **vl, **vo; 536167465Smp int noglob; 53759243Sobrien 538167465Smp if (!v || !v[0]) 539167465Smp return saveblk(v); 54059243Sobrien 54159243Sobrien noglob = adrof(STRnoglob) != 0; 54259243Sobrien 54359243Sobrien if (gflg & G_CSH) 54459243Sobrien /* 54559243Sobrien * Expand back-quote, tilde and brace 54659243Sobrien */ 547167465Smp vl = vo = globexpand(v, noglob); 54859243Sobrien else 54959243Sobrien vl = vo = saveblk(v); 55059243Sobrien 55159243Sobrien if (!noglob && (gflg & G_GLOB)) { 552167465Smp cleanup_push(vo, blk_cleanup); 55359243Sobrien vl = libglob(vo); 554167465Smp if (vl == vo) 555167465Smp cleanup_ignore(vo); 556167465Smp cleanup_until(vo); 55759243Sobrien } 55859243Sobrien else 55959243Sobrien trim(vl); 56059243Sobrien 561167465Smp return vl; 56259243Sobrien} 56359243Sobrien 564167465SmpChar ** 565167465Smpglob_all_or_error(Char **v) 56659243Sobrien{ 567167465Smp int gflag; 568167465Smp 569167465Smp gflag = tglob(v); 570167465Smp if (gflag) { 571167465Smp v = globall(v, gflag); 572167465Smp if (v == NULL) 573167465Smp stderror(ERR_NAME | ERR_NOMATCH); 574167465Smp } else { 575167465Smp v = saveblk(v); 576167465Smp trim(v); 577167465Smp } 578167465Smp return v; 57959243Sobrien} 58059243Sobrien 58159243Sobrienvoid 582167465Smprscan(Char **t, void (*f) (Char)) 58359243Sobrien{ 584145479Smp Char *p; 58559243Sobrien 58659243Sobrien while ((p = *t++) != '\0') 58759243Sobrien while (*p) 58859243Sobrien (*f) (*p++); 58959243Sobrien} 59059243Sobrien 59159243Sobrienvoid 592167465Smptrim(Char **t) 59359243Sobrien{ 594145479Smp Char *p; 59559243Sobrien 59659243Sobrien while ((p = *t++) != '\0') 59759243Sobrien while (*p) 59859243Sobrien *p++ &= TRIM; 59959243Sobrien} 60059243Sobrien 601167465Smpint 602167465Smptglob(Char **t) 60359243Sobrien{ 604167465Smp int gflag; 605167465Smp const Char *p; 60659243Sobrien 607167465Smp gflag = 0; 60859243Sobrien while ((p = *t++) != '\0') { 60959243Sobrien if (*p == '~' || *p == '=') 61059243Sobrien gflag |= G_CSH; 61159243Sobrien else if (*p == '{' && 61259243Sobrien (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 61359243Sobrien continue; 614167465Smp while (*p != '\0') { 615167465Smp if (*p == '`') { 61659243Sobrien gflag |= G_CSH; 61759243Sobrien#ifdef notdef 61859243Sobrien /* 61959243Sobrien * We do want to expand echo `echo '*'`, so we don't\ 62059243Sobrien * use this piece of code anymore. 62159243Sobrien */ 622167465Smp p++; 62359243Sobrien while (*p && *p != '`') 62459243Sobrien if (*p++ == '\\') { 62559243Sobrien if (*p) /* Quoted chars */ 62659243Sobrien p++; 62759243Sobrien else 62859243Sobrien break; 62959243Sobrien } 630167465Smp if (!*p) /* The matching ` */ 63159243Sobrien break; 63259243Sobrien#endif 63359243Sobrien } 634167465Smp else if (*p == '{') 63559243Sobrien gflag |= G_CSH; 636167465Smp else if (isglob(*p)) 63759243Sobrien gflag |= G_GLOB; 63859243Sobrien else if (symlinks == SYM_EXPAND && 639167465Smp p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') ) 64059243Sobrien gflag |= G_CSH; 641167465Smp p++; 64259243Sobrien } 64359243Sobrien } 644167465Smp return gflag; 64559243Sobrien} 64659243Sobrien 64759243Sobrien/* 64859243Sobrien * Command substitute cp. If literal, then this is a substitution from a 64959243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating 65059243Sobrien * words only at newlines. 65159243Sobrien */ 65259243SobrienChar ** 653167465Smpdobackp(Char *cp, int literal) 65459243Sobrien{ 655167465Smp struct Strbuf word = Strbuf_INIT; 656167465Smp struct blk_buf bb = BLK_BUF_INIT; 657167465Smp Char *lp, *rp, *ep; 65859243Sobrien 659167465Smp cleanup_push(&bb, bb_cleanup); 660167465Smp cleanup_push(&word, Strbuf_cleanup); 66159243Sobrien for (;;) { 662167465Smp for (lp = cp; *lp != '\0' && *lp != '`'; lp++) 663167465Smp ; 664167465Smp Strbuf_appendn(&word, cp, lp - cp); 665167465Smp if (*lp == 0) 666167465Smp break; 66759243Sobrien lp++; 66859243Sobrien for (rp = lp; *rp && *rp != '`'; rp++) 66959243Sobrien if (*rp == '\\') { 67059243Sobrien rp++; 67159243Sobrien if (!*rp) 67259243Sobrien goto oops; 67359243Sobrien } 674167465Smp if (!*rp) { 675167465Smp oops: 676195609Smp cleanup_until(&bb); 677167465Smp stderror(ERR_UNMATCHED, '`'); 678167465Smp } 679167465Smp ep = Strnsave(lp, rp - lp); 680167465Smp cleanup_push(ep, xfree); 681167465Smp backeval(&bb, &word, ep, literal); 682167465Smp cleanup_until(ep); 68359243Sobrien cp = rp + 1; 68459243Sobrien } 685167465Smp if (word.len != 0) 686167465Smp pword(&bb, &word); 687167465Smp cleanup_ignore(&bb); 688167465Smp cleanup_until(&bb); 689167465Smp return bb_finish(&bb); 69059243Sobrien} 69159243Sobrien 69259243Sobrien 69359243Sobrienstatic void 694167465Smpbackeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal) 69559243Sobrien{ 696232633Smp ssize_t icnt; 697145479Smp Char c, *ip; 69859243Sobrien struct command faket; 699145479Smp int hadnl; 70059243Sobrien int pvec[2], quoted; 70159243Sobrien Char *fakecom[2], ibuf[BUFSIZE]; 70259243Sobrien char tibuf[BUFSIZE]; 70359243Sobrien 70459243Sobrien hadnl = 0; 70559243Sobrien icnt = 0; 70659243Sobrien quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 70759243Sobrien faket.t_dtyp = NODE_COMMAND; 70859243Sobrien faket.t_dflg = F_BACKQ; 70959243Sobrien faket.t_dlef = 0; 71059243Sobrien faket.t_drit = 0; 71159243Sobrien faket.t_dspr = 0; 71259243Sobrien faket.t_dcom = fakecom; 71359243Sobrien fakecom[0] = STRfakecom1; 71459243Sobrien fakecom[1] = 0; 71559243Sobrien 71659243Sobrien /* 71759243Sobrien * We do the psave job to temporarily change the current job so that the 71859243Sobrien * following fork is considered a separate job. This is so that when 71959243Sobrien * backquotes are used in a builtin function that calls glob the "current 72059243Sobrien * job" is not corrupted. We only need one level of pushed jobs as long as 72159243Sobrien * we are sure to fork here. 72259243Sobrien */ 72359243Sobrien psavejob(); 724167465Smp cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */ 72559243Sobrien 72659243Sobrien /* 72759243Sobrien * It would be nicer if we could integrate this redirection more with the 72859243Sobrien * routines in sh.sem.c by doing a fake execute on a builtin function that 72959243Sobrien * was piped out. 73059243Sobrien */ 73159243Sobrien mypipe(pvec); 732167465Smp cleanup_push(&pvec[0], open_cleanup); 733167465Smp cleanup_push(&pvec[1], open_cleanup); 73459243Sobrien if (pfork(&faket, -1) == 0) { 735145479Smp jmp_buf_t osetexit; 736167465Smp struct command *t; 737167465Smp size_t omark; 73859243Sobrien 739167465Smp xclose(pvec[0]); 74059243Sobrien (void) dmove(pvec[1], 1); 74159243Sobrien (void) dmove(SHDIAG, 2); 74259243Sobrien initdesc(); 743100616Smp closem(); 74459243Sobrien arginp = cp; 745100616Smp for (arginp = cp; *cp; cp++) { 746100616Smp *cp &= TRIM; 747145479Smp if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r')) 748100616Smp *cp = ' '; 749100616Smp } 75059243Sobrien 75159243Sobrien /* 75259243Sobrien * In the child ``forget'' everything about current aliases or 75359243Sobrien * eval vectors. 75459243Sobrien */ 75559243Sobrien alvec = NULL; 75659243Sobrien evalvec = NULL; 75759243Sobrien alvecp = NULL; 75859243Sobrien evalp = NULL; 759145479Smp 760167465Smp omark = cleanup_push_mark(); 761145479Smp getexit(osetexit); 762145479Smp for (;;) { 763145479Smp (void) setexit(); 764145479Smp justpr = 0; 765145479Smp 766145479Smp if (haderr) { 767145479Smp /* unwind */ 768145479Smp doneinp = 0; 769167465Smp cleanup_pop_mark(omark); 770145479Smp resexit(osetexit); 771145479Smp reset(); 772145479Smp } 773145479Smp if (seterr) { 774167465Smp xfree(seterr); 775145479Smp seterr = NULL; 776145479Smp } 777145479Smp 778145479Smp (void) lex(¶ml); 779167465Smp cleanup_push(¶ml, lex_cleanup); 780145479Smp if (seterr) 781145479Smp stderror(ERR_OLD); 782145479Smp alias(¶ml); 783145479Smp t = syntax(paraml.next, ¶ml, 0); 784232633Smp if (t == NULL) 785232633Smp return; 786167465Smp cleanup_push(t, syntax_cleanup); 787232633Smp /* The F_BACKQ flag must set so the job output is correct if 788232633Smp * printexitvalue is set. If it's not set, the job output 789232633Smp * will have "Exit N" appended where N is the exit status. */ 790232633Smp t->t_dflg = F_BACKQ|F_NOFORK; 791145479Smp if (seterr) 792145479Smp stderror(ERR_OLD); 79359243Sobrien#ifdef SIGTSTP 794167465Smp signal(SIGTSTP, SIG_IGN); 79559243Sobrien#endif 79659243Sobrien#ifdef SIGTTIN 797167465Smp signal(SIGTTIN, SIG_IGN); 79859243Sobrien#endif 79959243Sobrien#ifdef SIGTTOU 800167465Smp signal(SIGTTOU, SIG_IGN); 80159243Sobrien#endif 802145479Smp execute(t, -1, NULL, NULL, TRUE); 803145479Smp 804167465Smp cleanup_until(¶ml); 805145479Smp } 80659243Sobrien } 807167465Smp cleanup_until(&pvec[1]); 80859243Sobrien c = 0; 80959243Sobrien ip = NULL; 81059243Sobrien do { 811232633Smp ssize_t cnt = 0; 812145479Smp char *tmp; 81359243Sobrien 814145479Smp tmp = tibuf; 81559243Sobrien for (;;) { 816145479Smp while (icnt == 0) { 817145479Smp int i, eof; 81859243Sobrien 81959243Sobrien ip = ibuf; 820167465Smp icnt = xread(pvec[0], tmp, tibuf + BUFSIZE - tmp); 821145479Smp eof = 0; 82259243Sobrien if (icnt <= 0) { 823145479Smp if (tmp == tibuf) 824145479Smp goto eof; 825145479Smp icnt = 0; 826145479Smp eof = 1; 82759243Sobrien } 828145479Smp icnt += tmp - tibuf; 829145479Smp i = 0; 830145479Smp tmp = tibuf; 831145479Smp while (tmp < tibuf + icnt) { 832145479Smp int len; 833145479Smp 834145479Smp len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp); 835145479Smp if (len == -1) { 836145479Smp reset_mbtowc(); 837145479Smp if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) { 838145479Smp break; /* Maybe a partial character */ 839145479Smp } 840145479Smp ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */ 841145479Smp } 842145479Smp if (len <= 0) 843145479Smp len = 1; 844145479Smp i++; 845145479Smp tmp += len; 846145479Smp } 847145479Smp if (tmp != tibuf) 848145479Smp memmove (tibuf, tmp, tibuf + icnt - tmp); 849145479Smp tmp = tibuf + (tibuf + icnt - tmp); 850145479Smp icnt = i; 85159243Sobrien } 85259243Sobrien if (hadnl) 85359243Sobrien break; 85459243Sobrien --icnt; 85559243Sobrien c = (*ip++ & TRIM); 85659243Sobrien if (c == 0) 85759243Sobrien break; 858195609Smp#if defined(WINNT_NATIVE) || defined(__CYGWIN__) 85959243Sobrien if (c == '\r') 86059243Sobrien c = ' '; 861195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */ 86259243Sobrien if (c == '\n') { 86359243Sobrien /* 86459243Sobrien * Continue around the loop one more time, so that we can eat 86559243Sobrien * the last newline without terminating this word. 86659243Sobrien */ 86759243Sobrien hadnl = 1; 86859243Sobrien continue; 86959243Sobrien } 87059243Sobrien if (!quoted && (c == ' ' || c == '\t')) 87159243Sobrien break; 87259243Sobrien cnt++; 873167465Smp Strbuf_append1(word, c | quoted); 87459243Sobrien } 87559243Sobrien /* 87659243Sobrien * Unless at end-of-file, we will form a new word here if there were 87759243Sobrien * characters in the word, or in any case when we take text literally. 87859243Sobrien * If we didn't make empty words here when literal was set then we 87959243Sobrien * would lose blank lines. 88059243Sobrien */ 881145479Smp if (c != 0 && (cnt || literal)) 882167465Smp pword(bb, word); 88359243Sobrien hadnl = 0; 884145479Smp } while (c > 0); 885145479Smp eof: 886167465Smp cleanup_until(&pvec[0]); 88759243Sobrien pwait(); 888167465Smp cleanup_until(&faket); /* psavejob_cleanup(); */ 88959243Sobrien} 89059243Sobrien 89159243Sobrienstatic void 892167465Smppword(struct blk_buf *bb, struct Strbuf *word) 89359243Sobrien{ 894167465Smp Char *s; 89559243Sobrien 896167465Smp s = Strbuf_finish(word); 897167465Smp bb_append(bb, s); 898167465Smp *word = Strbuf_init; 89959243Sobrien} 90059243Sobrien 90159243Sobrienint 902167465SmpGmatch(const Char *string, const Char *pattern) 90359243Sobrien{ 90459243Sobrien return Gnmatch(string, pattern, NULL); 90559243Sobrien} 90659243Sobrien 907167465Smpint 908167465SmpGnmatch(const Char *string, const Char *pattern, const Char **endstr) 90959243Sobrien{ 910167465Smp Char ***fblk, **p; 911167465Smp const Char *tstring = string; 91259243Sobrien int gpol = 1, gres = 0; 91359243Sobrien 91459243Sobrien if (*pattern == '^') { 91559243Sobrien gpol = 0; 91659243Sobrien pattern++; 91759243Sobrien } 91859243Sobrien 919167465Smp fblk = xmalloc(sizeof(Char ***)); 920167465Smp *fblk = xmalloc(GLOBSPACE * sizeof(Char *)); 921167465Smp (*fblk)[0] = Strsave(pattern); 922167465Smp (*fblk)[1] = NULL; 92359243Sobrien 924167465Smp cleanup_push(fblk, blk_indirect_cleanup); 925167465Smp expbrace(fblk, NULL, GLOBSPACE); 92659243Sobrien 92759243Sobrien if (endstr == NULL) 92859243Sobrien /* Exact matches only */ 929167465Smp for (p = *fblk; *p; p++) 930145479Smp gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0; 93159243Sobrien else { 932167465Smp const Char *end; 933167465Smp 93459243Sobrien /* partial matches */ 935167465Smp end = Strend(string); 936167465Smp for (p = *fblk; *p; p++) 937145479Smp if (t_pmatch(string, *p, &tstring, 1) != 0) { 93859243Sobrien gres |= 1; 939167465Smp if (end > tstring) 940167465Smp end = tstring; 94159243Sobrien } 942167465Smp *endstr = end; 94359243Sobrien } 94459243Sobrien 945167465Smp cleanup_until(fblk); 94659243Sobrien return(gres == gpol); 94759243Sobrien} 94859243Sobrien 949131962Smp/* t_pmatch(): 95059243Sobrien * Return 2 on exact match, 95159243Sobrien * Return 1 on substring match. 95259243Sobrien * Return 0 on no match. 95359243Sobrien * *estr will point to the end of the longest exact or substring match. 95459243Sobrien */ 955131962Smpint 956167465Smpt_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs) 95759243Sobrien{ 958167465Smp Char stringc, patternc, rangec; 95959243Sobrien int match, negate_range; 960167465Smp const Char *pestr, *nstring; 96159243Sobrien 962145479Smp for (nstring = string;; string = nstring) { 963167465Smp stringc = *nstring++ & TRIM; 964167465Smp patternc = *pattern++ & TRIM; 96559243Sobrien switch (patternc) { 966145479Smp case '\0': 96759243Sobrien *estr = string; 968145479Smp return (stringc == '\0' ? 2 : 1); 96959243Sobrien case '?': 97059243Sobrien if (stringc == 0) 97159243Sobrien return (0); 97259243Sobrien break; 97359243Sobrien case '*': 97459243Sobrien if (!*pattern) { 975167465Smp *estr = Strend(string); 97659243Sobrien return (2); 97759243Sobrien } 97859243Sobrien pestr = NULL; 97959243Sobrien 980145479Smp for (;;) { 981131962Smp switch(t_pmatch(string, pattern, estr, cs)) { 98259243Sobrien case 0: 98359243Sobrien break; 98459243Sobrien case 1: 985167465Smp pestr = *estr;/*FIXME: does not guarantee longest match */ 98659243Sobrien break; 98759243Sobrien case 2: 98859243Sobrien return 2; 98959243Sobrien default: 99059243Sobrien abort(); /* Cannot happen */ 99159243Sobrien } 992167465Smp stringc = *string++ & TRIM; 993145479Smp if (!stringc) 994145479Smp break; 99559243Sobrien } 99659243Sobrien 99759243Sobrien if (pestr) { 99859243Sobrien *estr = pestr; 99959243Sobrien return 1; 100059243Sobrien } 1001167465Smp else 100259243Sobrien return 0; 100359243Sobrien 100459243Sobrien case '[': 100559243Sobrien match = 0; 100659243Sobrien if ((negate_range = (*pattern == '^')) != 0) 100759243Sobrien pattern++; 1008167465Smp while ((rangec = *pattern++ & TRIM) != '\0') { 100959243Sobrien if (rangec == ']') 101059243Sobrien break; 101159243Sobrien if (match) 101259243Sobrien continue; 1013145479Smp if (*pattern == '-' && pattern[1] != ']') { 1014167465Smp Char rangec2; 101559243Sobrien pattern++; 1016167465Smp rangec2 = *pattern++ & TRIM; 1017145479Smp match = (globcharcoll(stringc, rangec2, 0) <= 0 && 1018145479Smp globcharcoll(rangec, stringc, 0) <= 0); 101959243Sobrien } 102059243Sobrien else 1021145479Smp match = (stringc == rangec); 102259243Sobrien } 1023145479Smp if (rangec == '\0') 102459243Sobrien stderror(ERR_NAME | ERR_MISSING, ']'); 1025145479Smp if ((!match) && (stringc == '\0')) 1026145479Smp return (0); 102759243Sobrien if (match == negate_range) 102859243Sobrien return (0); 102959243Sobrien break; 103059243Sobrien default: 1031145479Smp if (cs ? patternc != stringc 1032145479Smp : Tolower(patternc) != Tolower(stringc)) 103359243Sobrien return (0); 103459243Sobrien break; 103559243Sobrien } 103659243Sobrien } 103759243Sobrien} 1038