1316958Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/sh.glob.c,v 3.95 2016/08/01 16:21:09 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 35316958SdchaginRCSID("$tcsh: sh.glob.c,v 3.95 2016/08/01 16:21:09 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 434231990Smp if (adrof(STRglobdot)) 435231990Smp gflgs |= GLOB_DOT; 436231990Smp 437231990Smp if (adrof(STRglobstar)) 438231990Smp gflgs |= GLOB_STAR; 439231990Smp 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: 519231990Smp if (vl && vl[0] == NULL) { 520167465Smp xfree(vl); 52159243Sobrien return (Strsave(STRNULL)); 52259243Sobrien } 523231990Smp 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') 597316958Sdchagin while (*p) { 598316958Sdchagin#if INVALID_BYTE != 0 599316958Sdchagin if ((*p & INVALID_BYTE) != INVALID_BYTE) /* *p < INVALID_BYTE */ 600316958Sdchagin#endif 601316958Sdchagin *p &= TRIM; 602316958Sdchagin p++; 603316958Sdchagin } 60459243Sobrien} 60559243Sobrien 606167465Smpint 607167465Smptglob(Char **t) 60859243Sobrien{ 609167465Smp int gflag; 610167465Smp const Char *p; 61159243Sobrien 612167465Smp gflag = 0; 61359243Sobrien while ((p = *t++) != '\0') { 61459243Sobrien if (*p == '~' || *p == '=') 61559243Sobrien gflag |= G_CSH; 61659243Sobrien else if (*p == '{' && 61759243Sobrien (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 61859243Sobrien continue; 619167465Smp while (*p != '\0') { 620167465Smp if (*p == '`') { 62159243Sobrien gflag |= G_CSH; 62259243Sobrien#ifdef notdef 62359243Sobrien /* 62459243Sobrien * We do want to expand echo `echo '*'`, so we don't\ 62559243Sobrien * use this piece of code anymore. 62659243Sobrien */ 627167465Smp p++; 62859243Sobrien while (*p && *p != '`') 62959243Sobrien if (*p++ == '\\') { 63059243Sobrien if (*p) /* Quoted chars */ 63159243Sobrien p++; 63259243Sobrien else 63359243Sobrien break; 63459243Sobrien } 635167465Smp if (!*p) /* The matching ` */ 63659243Sobrien break; 63759243Sobrien#endif 63859243Sobrien } 639167465Smp else if (*p == '{') 64059243Sobrien gflag |= G_CSH; 641167465Smp else if (isglob(*p)) 64259243Sobrien gflag |= G_GLOB; 64359243Sobrien else if (symlinks == SYM_EXPAND && 644167465Smp p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') ) 64559243Sobrien gflag |= G_CSH; 646167465Smp p++; 64759243Sobrien } 64859243Sobrien } 649167465Smp return gflag; 65059243Sobrien} 65159243Sobrien 65259243Sobrien/* 65359243Sobrien * Command substitute cp. If literal, then this is a substitution from a 65459243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating 65559243Sobrien * words only at newlines. 65659243Sobrien */ 65759243SobrienChar ** 658167465Smpdobackp(Char *cp, int literal) 65959243Sobrien{ 660167465Smp struct Strbuf word = Strbuf_INIT; 661167465Smp struct blk_buf bb = BLK_BUF_INIT; 662167465Smp Char *lp, *rp, *ep; 66359243Sobrien 664167465Smp cleanup_push(&bb, bb_cleanup); 665167465Smp cleanup_push(&word, Strbuf_cleanup); 66659243Sobrien for (;;) { 667167465Smp for (lp = cp; *lp != '\0' && *lp != '`'; lp++) 668167465Smp ; 669167465Smp Strbuf_appendn(&word, cp, lp - cp); 670167465Smp if (*lp == 0) 671167465Smp break; 67259243Sobrien lp++; 67359243Sobrien for (rp = lp; *rp && *rp != '`'; rp++) 67459243Sobrien if (*rp == '\\') { 67559243Sobrien rp++; 67659243Sobrien if (!*rp) 67759243Sobrien goto oops; 67859243Sobrien } 679167465Smp if (!*rp) { 680167465Smp oops: 681195609Smp cleanup_until(&bb); 682167465Smp stderror(ERR_UNMATCHED, '`'); 683167465Smp } 684167465Smp ep = Strnsave(lp, rp - lp); 685167465Smp cleanup_push(ep, xfree); 686167465Smp backeval(&bb, &word, ep, literal); 687167465Smp cleanup_until(ep); 68859243Sobrien cp = rp + 1; 68959243Sobrien } 690167465Smp if (word.len != 0) 691167465Smp pword(&bb, &word); 692167465Smp cleanup_ignore(&bb); 693167465Smp cleanup_until(&bb); 694167465Smp return bb_finish(&bb); 69559243Sobrien} 69659243Sobrien 69759243Sobrien 69859243Sobrienstatic void 699167465Smpbackeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal) 70059243Sobrien{ 701231990Smp ssize_t icnt; 702145479Smp Char c, *ip; 70359243Sobrien struct command faket; 704145479Smp int hadnl; 70559243Sobrien int pvec[2], quoted; 70659243Sobrien Char *fakecom[2], ibuf[BUFSIZE]; 70759243Sobrien 70859243Sobrien hadnl = 0; 70959243Sobrien icnt = 0; 710316958Sdchagin if (!literal) { 711316958Sdchagin for (ip = cp; (*ip & QUOTE) != 0; ip++) 712316958Sdchagin continue; 713316958Sdchagin quoted = *ip == '\0'; 714316958Sdchagin } else 715316958Sdchagin quoted = literal; 71659243Sobrien faket.t_dtyp = NODE_COMMAND; 71759243Sobrien faket.t_dflg = F_BACKQ; 71859243Sobrien faket.t_dlef = 0; 71959243Sobrien faket.t_drit = 0; 72059243Sobrien faket.t_dspr = 0; 72159243Sobrien faket.t_dcom = fakecom; 72259243Sobrien fakecom[0] = STRfakecom1; 72359243Sobrien fakecom[1] = 0; 72459243Sobrien 72559243Sobrien /* 72659243Sobrien * We do the psave job to temporarily change the current job so that the 72759243Sobrien * following fork is considered a separate job. This is so that when 72859243Sobrien * backquotes are used in a builtin function that calls glob the "current 72959243Sobrien * job" is not corrupted. We only need one level of pushed jobs as long as 73059243Sobrien * we are sure to fork here. 73159243Sobrien */ 73259243Sobrien psavejob(); 733167465Smp cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */ 73459243Sobrien 73559243Sobrien /* 73659243Sobrien * It would be nicer if we could integrate this redirection more with the 73759243Sobrien * routines in sh.sem.c by doing a fake execute on a builtin function that 73859243Sobrien * was piped out. 73959243Sobrien */ 74059243Sobrien mypipe(pvec); 741167465Smp cleanup_push(&pvec[0], open_cleanup); 742167465Smp cleanup_push(&pvec[1], open_cleanup); 74359243Sobrien if (pfork(&faket, -1) == 0) { 744145479Smp jmp_buf_t osetexit; 745167465Smp struct command *t; 746167465Smp size_t omark; 74759243Sobrien 748167465Smp xclose(pvec[0]); 74959243Sobrien (void) dmove(pvec[1], 1); 75059243Sobrien (void) dmove(SHDIAG, 2); 75159243Sobrien initdesc(); 752100616Smp closem(); 75359243Sobrien arginp = cp; 754100616Smp for (arginp = cp; *cp; cp++) { 755100616Smp *cp &= TRIM; 756145479Smp if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r')) 757100616Smp *cp = ' '; 758100616Smp } 75959243Sobrien 76059243Sobrien /* 76159243Sobrien * In the child ``forget'' everything about current aliases or 76259243Sobrien * eval vectors. 76359243Sobrien */ 76459243Sobrien alvec = NULL; 76559243Sobrien evalvec = NULL; 76659243Sobrien alvecp = NULL; 76759243Sobrien evalp = NULL; 768145479Smp 769167465Smp omark = cleanup_push_mark(); 770145479Smp getexit(osetexit); 771145479Smp for (;;) { 772316958Sdchagin struct wordent paraml1; 773316958Sdchagin initlex(¶ml1); 774316958Sdchagin 775145479Smp (void) setexit(); 776145479Smp justpr = 0; 777145479Smp 778145479Smp if (haderr) { 779145479Smp /* unwind */ 780145479Smp doneinp = 0; 781167465Smp cleanup_pop_mark(omark); 782145479Smp resexit(osetexit); 783145479Smp reset(); 784145479Smp } 785145479Smp if (seterr) { 786167465Smp xfree(seterr); 787145479Smp seterr = NULL; 788145479Smp } 789145479Smp 790316958Sdchagin freelex(¶ml1); 791316958Sdchagin (void) lex(¶ml1); 792316958Sdchagin cleanup_push(¶ml1, lex_cleanup); 793145479Smp if (seterr) 794145479Smp stderror(ERR_OLD); 795316958Sdchagin alias(¶ml1); 796316958Sdchagin t = syntax(paraml1.next, ¶ml1, 0); 797167465Smp cleanup_push(t, syntax_cleanup); 798231990Smp /* The F_BACKQ flag must set so the job output is correct if 799231990Smp * printexitvalue is set. If it's not set, the job output 800231990Smp * will have "Exit N" appended where N is the exit status. */ 801316958Sdchagin if (t) 802316958Sdchagin t->t_dflg = F_BACKQ|F_NOFORK; 803145479Smp if (seterr) 804145479Smp stderror(ERR_OLD); 80559243Sobrien#ifdef SIGTSTP 806167465Smp signal(SIGTSTP, SIG_IGN); 80759243Sobrien#endif 80859243Sobrien#ifdef SIGTTIN 809167465Smp signal(SIGTTIN, SIG_IGN); 81059243Sobrien#endif 81159243Sobrien#ifdef SIGTTOU 812167465Smp signal(SIGTTOU, SIG_IGN); 81359243Sobrien#endif 814145479Smp execute(t, -1, NULL, NULL, TRUE); 815145479Smp 816316958Sdchagin cleanup_until(¶ml1); 817145479Smp } 81859243Sobrien } 819167465Smp cleanup_until(&pvec[1]); 82059243Sobrien c = 0; 82159243Sobrien ip = NULL; 82259243Sobrien do { 823231990Smp ssize_t cnt = 0; 82459243Sobrien 82559243Sobrien for (;;) { 826316958Sdchagin if (icnt == 0) { 82759243Sobrien ip = ibuf; 828316958Sdchagin icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0); 829316958Sdchagin if (icnt <= 0) 830316958Sdchagin goto eof; 83159243Sobrien } 83259243Sobrien if (hadnl) 83359243Sobrien break; 83459243Sobrien --icnt; 83559243Sobrien c = (*ip++ & TRIM); 83659243Sobrien if (c == 0) 83759243Sobrien break; 838195609Smp#if defined(WINNT_NATIVE) || defined(__CYGWIN__) 83959243Sobrien if (c == '\r') 84059243Sobrien c = ' '; 841195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */ 84259243Sobrien if (c == '\n') { 84359243Sobrien /* 84459243Sobrien * Continue around the loop one more time, so that we can eat 84559243Sobrien * the last newline without terminating this word. 84659243Sobrien */ 84759243Sobrien hadnl = 1; 84859243Sobrien continue; 84959243Sobrien } 85059243Sobrien if (!quoted && (c == ' ' || c == '\t')) 85159243Sobrien break; 85259243Sobrien cnt++; 853316958Sdchagin if (c == '\\' || quoted) 854316958Sdchagin c |= QUOTE; 855316958Sdchagin Strbuf_append1(word, c); 85659243Sobrien } 85759243Sobrien /* 85859243Sobrien * Unless at end-of-file, we will form a new word here if there were 85959243Sobrien * characters in the word, or in any case when we take text literally. 86059243Sobrien * If we didn't make empty words here when literal was set then we 86159243Sobrien * would lose blank lines. 86259243Sobrien */ 863145479Smp if (c != 0 && (cnt || literal)) 864167465Smp pword(bb, word); 86559243Sobrien hadnl = 0; 866145479Smp } while (c > 0); 867145479Smp eof: 868167465Smp cleanup_until(&pvec[0]); 86959243Sobrien pwait(); 870167465Smp cleanup_until(&faket); /* psavejob_cleanup(); */ 87159243Sobrien} 87259243Sobrien 87359243Sobrienstatic void 874167465Smppword(struct blk_buf *bb, struct Strbuf *word) 87559243Sobrien{ 876167465Smp Char *s; 87759243Sobrien 878167465Smp s = Strbuf_finish(word); 879167465Smp bb_append(bb, s); 880167465Smp *word = Strbuf_init; 88159243Sobrien} 88259243Sobrien 88359243Sobrienint 884167465SmpGmatch(const Char *string, const Char *pattern) 88559243Sobrien{ 88659243Sobrien return Gnmatch(string, pattern, NULL); 88759243Sobrien} 88859243Sobrien 889167465Smpint 890167465SmpGnmatch(const Char *string, const Char *pattern, const Char **endstr) 89159243Sobrien{ 892167465Smp Char ***fblk, **p; 893167465Smp const Char *tstring = string; 89459243Sobrien int gpol = 1, gres = 0; 89559243Sobrien 89659243Sobrien if (*pattern == '^') { 89759243Sobrien gpol = 0; 89859243Sobrien pattern++; 89959243Sobrien } 90059243Sobrien 901167465Smp fblk = xmalloc(sizeof(Char ***)); 902167465Smp *fblk = xmalloc(GLOBSPACE * sizeof(Char *)); 903167465Smp (*fblk)[0] = Strsave(pattern); 904167465Smp (*fblk)[1] = NULL; 90559243Sobrien 906167465Smp cleanup_push(fblk, blk_indirect_cleanup); 907167465Smp expbrace(fblk, NULL, GLOBSPACE); 90859243Sobrien 90959243Sobrien if (endstr == NULL) 91059243Sobrien /* Exact matches only */ 911167465Smp for (p = *fblk; *p; p++) 912145479Smp gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0; 91359243Sobrien else { 914167465Smp const Char *end; 915167465Smp 91659243Sobrien /* partial matches */ 917167465Smp end = Strend(string); 918167465Smp for (p = *fblk; *p; p++) 919145479Smp if (t_pmatch(string, *p, &tstring, 1) != 0) { 92059243Sobrien gres |= 1; 921167465Smp if (end > tstring) 922167465Smp end = tstring; 92359243Sobrien } 924167465Smp *endstr = end; 92559243Sobrien } 92659243Sobrien 927167465Smp cleanup_until(fblk); 92859243Sobrien return(gres == gpol); 92959243Sobrien} 93059243Sobrien 931131962Smp/* t_pmatch(): 93259243Sobrien * Return 2 on exact match, 93359243Sobrien * Return 1 on substring match. 93459243Sobrien * Return 0 on no match. 93559243Sobrien * *estr will point to the end of the longest exact or substring match. 93659243Sobrien */ 937131962Smpint 938167465Smpt_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs) 93959243Sobrien{ 940167465Smp Char stringc, patternc, rangec; 94159243Sobrien int match, negate_range; 942167465Smp const Char *pestr, *nstring; 94359243Sobrien 944145479Smp for (nstring = string;; string = nstring) { 945167465Smp stringc = *nstring++ & TRIM; 946167465Smp patternc = *pattern++ & TRIM; 94759243Sobrien switch (patternc) { 948145479Smp case '\0': 94959243Sobrien *estr = string; 950145479Smp return (stringc == '\0' ? 2 : 1); 95159243Sobrien case '?': 95259243Sobrien if (stringc == 0) 95359243Sobrien return (0); 95459243Sobrien break; 95559243Sobrien case '*': 95659243Sobrien if (!*pattern) { 957167465Smp *estr = Strend(string); 95859243Sobrien return (2); 95959243Sobrien } 96059243Sobrien pestr = NULL; 96159243Sobrien 962145479Smp for (;;) { 963131962Smp switch(t_pmatch(string, pattern, estr, cs)) { 96459243Sobrien case 0: 96559243Sobrien break; 96659243Sobrien case 1: 967167465Smp pestr = *estr;/*FIXME: does not guarantee longest match */ 96859243Sobrien break; 96959243Sobrien case 2: 97059243Sobrien return 2; 97159243Sobrien default: 97259243Sobrien abort(); /* Cannot happen */ 97359243Sobrien } 974167465Smp stringc = *string++ & TRIM; 975145479Smp if (!stringc) 976145479Smp break; 97759243Sobrien } 97859243Sobrien 97959243Sobrien if (pestr) { 98059243Sobrien *estr = pestr; 98159243Sobrien return 1; 98259243Sobrien } 983167465Smp else 98459243Sobrien return 0; 98559243Sobrien 98659243Sobrien case '[': 98759243Sobrien match = 0; 98859243Sobrien if ((negate_range = (*pattern == '^')) != 0) 98959243Sobrien pattern++; 990167465Smp while ((rangec = *pattern++ & TRIM) != '\0') { 99159243Sobrien if (rangec == ']') 99259243Sobrien break; 99359243Sobrien if (match) 99459243Sobrien continue; 995145479Smp if (*pattern == '-' && pattern[1] != ']') { 996167465Smp Char rangec2; 99759243Sobrien pattern++; 998167465Smp rangec2 = *pattern++ & TRIM; 999145479Smp match = (globcharcoll(stringc, rangec2, 0) <= 0 && 1000145479Smp globcharcoll(rangec, stringc, 0) <= 0); 100159243Sobrien } 100259243Sobrien else 1003145479Smp match = (stringc == rangec); 100459243Sobrien } 1005145479Smp if (rangec == '\0') 100659243Sobrien stderror(ERR_NAME | ERR_MISSING, ']'); 1007145479Smp if ((!match) && (stringc == '\0')) 1008145479Smp return (0); 100959243Sobrien if (match == negate_range) 101059243Sobrien return (0); 101159243Sobrien break; 101259243Sobrien default: 1013145479Smp if (cs ? patternc != stringc 1014145479Smp : Tolower(patternc) != Tolower(stringc)) 101559243Sobrien return (0); 101659243Sobrien break; 101759243Sobrien } 101859243Sobrien } 101959243Sobrien} 1020