sh.glob.c revision 59243
159243Sobrien/* $Header: /src/pub/tcsh/sh.glob.c,v 3.43 1998/10/25 15:10:14 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. 1759243Sobrien * 3. All advertising materials mentioning features or use of this software 1859243Sobrien * must display the following acknowledgement: 1959243Sobrien * This product includes software developed by the University of 2059243Sobrien * California, Berkeley and its contributors. 2159243Sobrien * 4. Neither the name of the University nor the names of its contributors 2259243Sobrien * may be used to endorse or promote products derived from this software 2359243Sobrien * without specific prior written permission. 2459243Sobrien * 2559243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2659243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2759243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2859243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2959243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3059243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3159243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3259243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3359243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3459243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3559243Sobrien * SUCH DAMAGE. 3659243Sobrien */ 3759243Sobrien#include "sh.h" 3859243Sobrien 3959243SobrienRCSID("$Id: sh.glob.c,v 3.43 1998/10/25 15:10:14 christos Exp $") 4059243Sobrien 4159243Sobrien#include "tc.h" 4259243Sobrien 4359243Sobrien#include "glob.h" 4459243Sobrien 4559243Sobrienstatic int noglob; 4659243Sobrienstatic int pargsiz, gargsiz; 4759243Sobrien 4859243Sobrien/* 4959243Sobrien * Values for gflag 5059243Sobrien */ 5159243Sobrien#define G_NONE 0 /* No globbing needed */ 5259243Sobrien#define G_GLOB 1 /* string contains *?[] characters */ 5359243Sobrien#define G_CSH 2 /* string contains ~`{ characters */ 5459243Sobrien 5559243Sobrien#define GLOBSPACE 100 /* Alloc increment */ 5659243Sobrien#define LONGBSIZE 10240 /* Backquote expansion buffer size */ 5759243Sobrien 5859243Sobrien 5959243Sobrien#define LBRC '{' 6059243Sobrien#define RBRC '}' 6159243Sobrien#define LBRK '[' 6259243Sobrien#define RBRK ']' 6359243Sobrien#define EOS '\0' 6459243Sobrien 6559243SobrienChar **gargv = NULL; 6659243Sobrienint gargc = 0; 6759243SobrienChar **pargv = NULL; 6859243Sobrienstatic int pargc = 0; 6959243Sobrien 7059243Sobrien/* 7159243Sobrien * globbing is now done in two stages. In the first pass we expand 7259243Sobrien * csh globbing idioms ~`{ and then we proceed doing the normal 7359243Sobrien * globbing if needed ?*[ 7459243Sobrien * 7559243Sobrien * Csh type globbing is handled in globexpand() and the rest is 7659243Sobrien * handled in glob() which is part of the 4.4BSD libc. 7759243Sobrien * 7859243Sobrien */ 7959243Sobrienstatic Char *globtilde __P((Char **, Char *)); 8059243Sobrienstatic Char *handleone __P((Char *, Char **, int)); 8159243Sobrienstatic Char **libglob __P((Char **)); 8259243Sobrienstatic Char **globexpand __P((Char **)); 8359243Sobrienstatic int globbrace __P((Char *, Char *, Char ***)); 8459243Sobrienstatic void expbrace __P((Char ***, Char ***, int)); 8559243Sobrienstatic int pmatch __P((Char *, Char *, Char **)); 8659243Sobrienstatic void pword __P((int)); 8759243Sobrienstatic void psave __P((int)); 8859243Sobrienstatic void backeval __P((Char *, bool)); 8959243Sobrien 9059243Sobrienstatic Char * 9159243Sobrienglobtilde(nv, s) 9259243Sobrien Char **nv, *s; 9359243Sobrien{ 9459243Sobrien Char gbuf[BUFSIZE], *gstart, *b, *u, *e; 9559243Sobrien#ifdef apollo 9659243Sobrien int slash; 9759243Sobrien#endif 9859243Sobrien 9959243Sobrien gstart = gbuf; 10059243Sobrien *gstart++ = *s++; 10159243Sobrien u = s; 10259243Sobrien for (b = gstart, e = &gbuf[BUFSIZE - 1]; 10359243Sobrien *s && *s != '/' && *s != ':' && b < e; 10459243Sobrien *b++ = *s++) 10559243Sobrien continue; 10659243Sobrien *b = EOS; 10759243Sobrien if (gethdir(gstart)) { 10859243Sobrien if (adrof(STRnonomatch)) 10959243Sobrien return (--u); 11059243Sobrien blkfree(nv); 11159243Sobrien if (*gstart) 11259243Sobrien stderror(ERR_UNKUSER, short2str(gstart)); 11359243Sobrien else 11459243Sobrien stderror(ERR_NOHOME); 11559243Sobrien } 11659243Sobrien b = &gstart[Strlen(gstart)]; 11759243Sobrien#ifdef apollo 11859243Sobrien slash = gstart[0] == '/' && gstart[1] == '\0'; 11959243Sobrien#endif 12059243Sobrien while (*s) 12159243Sobrien *b++ = *s++; 12259243Sobrien *b = EOS; 12359243Sobrien --u; 12459243Sobrien xfree((ptr_t) u); 12559243Sobrien#ifdef apollo 12659243Sobrien if (slash && gstart[1] == '/') 12759243Sobrien gstart++; 12859243Sobrien#endif 12959243Sobrien return (Strsave(gstart)); 13059243Sobrien} 13159243Sobrien 13259243SobrienChar * 13359243Sobrienglobequal(new, old) 13459243Sobrien Char *new, *old; 13559243Sobrien{ 13659243Sobrien int dig; 13759243Sobrien Char *b, *d; 13859243Sobrien 13959243Sobrien /* 14059243Sobrien * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names 14159243Sobrien * in stack. PWP: let =foobar pass through (for X windows) 14259243Sobrien */ 14359243Sobrien if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) { 14459243Sobrien /* =- */ 14559243Sobrien dig = -1; 14659243Sobrien b = &old[2]; 14759243Sobrien } 14859243Sobrien else if (Isdigit(old[1])) { 14959243Sobrien /* =<number> */ 15059243Sobrien dig = old[1] - '0'; 15159243Sobrien for (b = &old[2]; Isdigit(*b); b++) 15259243Sobrien dig = dig * 10 + (*b - '0'); 15359243Sobrien if (*b != '\0' && *b != '/') 15459243Sobrien /* =<number>foobar */ 15559243Sobrien return old; 15659243Sobrien } 15759243Sobrien else 15859243Sobrien /* =foobar */ 15959243Sobrien return old; 16059243Sobrien 16159243Sobrien if (!getstakd(new, dig)) 16259243Sobrien return NULL; 16359243Sobrien 16459243Sobrien /* Copy the rest of the string */ 16559243Sobrien for (d = &new[Strlen(new)]; 16659243Sobrien d < &new[BUFSIZE - 1] && (*d++ = *b++) != '\0';) 16759243Sobrien continue; 16859243Sobrien *d = '\0'; 16959243Sobrien 17059243Sobrien return new; 17159243Sobrien} 17259243Sobrien 17359243Sobrienstatic int 17459243Sobrienglobbrace(s, p, bl) 17559243Sobrien Char *s, *p, ***bl; 17659243Sobrien{ 17759243Sobrien int i, len; 17859243Sobrien Char *pm, *pe, *lm, *pl; 17959243Sobrien Char **nv, **vl; 18059243Sobrien Char gbuf[BUFSIZE]; 18159243Sobrien int size = GLOBSPACE; 18259243Sobrien 18359243Sobrien nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size)); 18459243Sobrien *vl = NULL; 18559243Sobrien 18659243Sobrien len = 0; 18759243Sobrien /* copy part up to the brace */ 18859243Sobrien for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) 18959243Sobrien continue; 19059243Sobrien 19159243Sobrien /* check for balanced braces */ 19259243Sobrien for (i = 0, pe = ++p; *pe; pe++) 19359243Sobrien if (*pe == LBRK) { 19459243Sobrien /* Ignore everything between [] */ 19559243Sobrien for (++pe; *pe != RBRK && *pe != EOS; pe++) 19659243Sobrien continue; 19759243Sobrien if (*pe == EOS) { 19859243Sobrien blkfree(nv); 19959243Sobrien return (-RBRK); 20059243Sobrien } 20159243Sobrien } 20259243Sobrien else if (*pe == LBRC) 20359243Sobrien i++; 20459243Sobrien else if (*pe == RBRC) { 20559243Sobrien if (i == 0) 20659243Sobrien break; 20759243Sobrien i--; 20859243Sobrien } 20959243Sobrien 21059243Sobrien if (i != 0 || *pe == '\0') { 21159243Sobrien blkfree(nv); 21259243Sobrien return (-RBRC); 21359243Sobrien } 21459243Sobrien 21559243Sobrien for (i = 0, pl = pm = p; pm <= pe; pm++) 21659243Sobrien switch (*pm) { 21759243Sobrien case LBRK: 21859243Sobrien for (++pm; *pm != RBRK && *pm != EOS; pm++) 21959243Sobrien continue; 22059243Sobrien if (*pm == EOS) { 22159243Sobrien *vl = NULL; 22259243Sobrien blkfree(nv); 22359243Sobrien return (-RBRK); 22459243Sobrien } 22559243Sobrien break; 22659243Sobrien case LBRC: 22759243Sobrien i++; 22859243Sobrien break; 22959243Sobrien case RBRC: 23059243Sobrien if (i) { 23159243Sobrien i--; 23259243Sobrien break; 23359243Sobrien } 23459243Sobrien /* FALLTHROUGH */ 23559243Sobrien case ',': 23659243Sobrien if (i && *pm == ',') 23759243Sobrien break; 23859243Sobrien else { 23959243Sobrien Char savec = *pm; 24059243Sobrien 24159243Sobrien *pm = EOS; 24259243Sobrien (void) Strcpy(lm, pl); 24359243Sobrien (void) Strcat(gbuf, pe + 1); 24459243Sobrien *pm = savec; 24559243Sobrien *vl++ = Strsave(gbuf); 24659243Sobrien len++; 24759243Sobrien pl = pm + 1; 24859243Sobrien if (vl == &nv[size]) { 24959243Sobrien size += GLOBSPACE; 25059243Sobrien nv = (Char **) xrealloc((ptr_t) nv, 25159243Sobrien (size_t) (size * sizeof(Char *))); 25259243Sobrien vl = &nv[size - GLOBSPACE]; 25359243Sobrien } 25459243Sobrien } 25559243Sobrien break; 25659243Sobrien default: 25759243Sobrien break; 25859243Sobrien } 25959243Sobrien *vl = NULL; 26059243Sobrien *bl = nv; 26159243Sobrien return (len); 26259243Sobrien} 26359243Sobrien 26459243Sobrien 26559243Sobrienstatic void 26659243Sobrienexpbrace(nvp, elp, size) 26759243Sobrien Char ***nvp, ***elp; 26859243Sobrien int size; 26959243Sobrien{ 27059243Sobrien Char **vl, **el, **nv, *s; 27159243Sobrien 27259243Sobrien vl = nv = *nvp; 27359243Sobrien if (elp != NULL) 27459243Sobrien el = *elp; 27559243Sobrien else 27659243Sobrien for (el = vl; *el; el++) 27759243Sobrien continue; 27859243Sobrien 27959243Sobrien for (s = *vl; s; s = *++vl) { 28059243Sobrien Char *b; 28159243Sobrien Char **vp, **bp; 28259243Sobrien 28359243Sobrien /* leave {} untouched for find */ 28459243Sobrien if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 28559243Sobrien continue; 28659243Sobrien if ((b = Strchr(s, '{')) != NULL) { 28759243Sobrien Char **bl; 28859243Sobrien int len; 28959243Sobrien 29059243Sobrien if ((len = globbrace(s, b, &bl)) < 0) { 29159243Sobrien xfree((ptr_t) nv); 29259243Sobrien stderror(ERR_MISSING, -len); 29359243Sobrien } 29459243Sobrien xfree((ptr_t) s); 29559243Sobrien if (len == 1) { 29659243Sobrien *vl-- = *bl; 29759243Sobrien xfree((ptr_t) bl); 29859243Sobrien continue; 29959243Sobrien } 30059243Sobrien if (&el[len] >= &nv[size]) { 30159243Sobrien int l, e; 30259243Sobrien l = (int) (&el[len] - &nv[size]); 30359243Sobrien size += GLOBSPACE > l ? GLOBSPACE : l; 30459243Sobrien l = (int) (vl - nv); 30559243Sobrien e = (int) (el - nv); 30659243Sobrien nv = (Char **) xrealloc((ptr_t) nv, 30759243Sobrien (size_t) (size * sizeof(Char *))); 30859243Sobrien vl = nv + l; 30959243Sobrien el = nv + e; 31059243Sobrien } 31159243Sobrien /* nv vl el bl 31259243Sobrien * | | | | 31359243Sobrien * -.--..-- x-- 31459243Sobrien * | len 31559243Sobrien * vp 31659243Sobrien */ 31759243Sobrien vp = vl--; 31859243Sobrien *vp = *bl; 31959243Sobrien len--; 32059243Sobrien for (bp = el; bp != vp; bp--) 32159243Sobrien bp[len] = *bp; 32259243Sobrien el += len; 32359243Sobrien /* nv vl el bl 32459243Sobrien * | | | | 32559243Sobrien * -.-x --- -- 32659243Sobrien * |len 32759243Sobrien * vp 32859243Sobrien */ 32959243Sobrien vp++; 33059243Sobrien for (bp = bl + 1; *bp; *vp++ = *bp++) 33159243Sobrien continue; 33259243Sobrien xfree((ptr_t) bl); 33359243Sobrien } 33459243Sobrien 33559243Sobrien } 33659243Sobrien if (elp != NULL) 33759243Sobrien *elp = el; 33859243Sobrien *nvp = nv; 33959243Sobrien} 34059243Sobrien 34159243Sobrienstatic Char ** 34259243Sobrienglobexpand(v) 34359243Sobrien Char **v; 34459243Sobrien{ 34559243Sobrien Char *s; 34659243Sobrien Char **nv, **vl, **el; 34759243Sobrien int size = GLOBSPACE; 34859243Sobrien 34959243Sobrien 35059243Sobrien nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size)); 35159243Sobrien *vl = NULL; 35259243Sobrien 35359243Sobrien /* 35459243Sobrien * Step 1: expand backquotes. 35559243Sobrien */ 35659243Sobrien while ((s = *v++) != '\0') { 35759243Sobrien if (Strchr(s, '`')) { 35859243Sobrien int i; 35959243Sobrien 36059243Sobrien (void) dobackp(s, 0); 36159243Sobrien for (i = 0; i < pargc; i++) { 36259243Sobrien *vl++ = pargv[i]; 36359243Sobrien if (vl == &nv[size]) { 36459243Sobrien size += GLOBSPACE; 36559243Sobrien nv = (Char **) xrealloc((ptr_t) nv, 36659243Sobrien (size_t) (size * sizeof(Char *))); 36759243Sobrien vl = &nv[size - GLOBSPACE]; 36859243Sobrien } 36959243Sobrien } 37059243Sobrien xfree((ptr_t) pargv); 37159243Sobrien pargv = NULL; 37259243Sobrien } 37359243Sobrien else { 37459243Sobrien *vl++ = Strsave(s); 37559243Sobrien if (vl == &nv[size]) { 37659243Sobrien size += GLOBSPACE; 37759243Sobrien nv = (Char **) xrealloc((ptr_t) nv, 37859243Sobrien (size_t) (size * sizeof(Char *))); 37959243Sobrien vl = &nv[size - GLOBSPACE]; 38059243Sobrien } 38159243Sobrien } 38259243Sobrien } 38359243Sobrien *vl = NULL; 38459243Sobrien 38559243Sobrien if (noglob) 38659243Sobrien return (nv); 38759243Sobrien 38859243Sobrien /* 38959243Sobrien * Step 2: expand braces 39059243Sobrien */ 39159243Sobrien el = vl; 39259243Sobrien expbrace(&nv, &el, size); 39359243Sobrien 39459243Sobrien 39559243Sobrien /* 39659243Sobrien * Step 3: expand ~ = 39759243Sobrien */ 39859243Sobrien vl = nv; 39959243Sobrien for (s = *vl; s; s = *++vl) 40059243Sobrien switch (*s) { 40159243Sobrien Char gp[BUFSIZE], *ns; 40259243Sobrien case '~': 40359243Sobrien *vl = globtilde(nv, s); 40459243Sobrien break; 40559243Sobrien case '=': 40659243Sobrien if ((ns = globequal(gp, s)) == NULL) { 40759243Sobrien if (!adrof(STRnonomatch)) { 40859243Sobrien /* Error */ 40959243Sobrien blkfree(nv); 41059243Sobrien stderror(ERR_DEEP); 41159243Sobrien } 41259243Sobrien } 41359243Sobrien if (ns && ns != s) { 41459243Sobrien /* Expansion succeeded */ 41559243Sobrien xfree((ptr_t) s); 41659243Sobrien *vl = Strsave(gp); 41759243Sobrien } 41859243Sobrien break; 41959243Sobrien default: 42059243Sobrien break; 42159243Sobrien } 42259243Sobrien vl = nv; 42359243Sobrien 42459243Sobrien /* 42559243Sobrien * Step 4: expand .. if the variable symlinks==expand is set 42659243Sobrien */ 42759243Sobrien if ( symlinks == SYM_EXPAND ) 42859243Sobrien for (s = *vl; s; s = *++vl) { 42959243Sobrien *vl = dnormalize(s, 1); 43059243Sobrien xfree((ptr_t) s); 43159243Sobrien } 43259243Sobrien vl = nv; 43359243Sobrien 43459243Sobrien return (vl); 43559243Sobrien} 43659243Sobrien 43759243Sobrienstatic Char * 43859243Sobrienhandleone(str, vl, action) 43959243Sobrien Char *str, **vl; 44059243Sobrien int action; 44159243Sobrien{ 44259243Sobrien 44359243Sobrien Char **vlp = vl; 44459243Sobrien int chars; 44559243Sobrien Char **t, *p, *strp; 44659243Sobrien 44759243Sobrien switch (action) { 44859243Sobrien case G_ERROR: 44959243Sobrien setname(short2str(str)); 45059243Sobrien blkfree(vl); 45159243Sobrien stderror(ERR_NAME | ERR_AMBIG); 45259243Sobrien break; 45359243Sobrien case G_APPEND: 45459243Sobrien chars = 0; 45559243Sobrien for (t = vlp; (p = *t++) != '\0'; chars++) 45659243Sobrien while (*p++) 45759243Sobrien chars++; 45859243Sobrien str = (Char *)xmalloc((size_t)(chars * sizeof(Char))); 45959243Sobrien for (t = vlp, strp = str; (p = *t++) != '\0'; chars++) { 46059243Sobrien while (*p) 46159243Sobrien *strp++ = *p++ & TRIM; 46259243Sobrien *strp++ = ' '; 46359243Sobrien } 46459243Sobrien *--strp = '\0'; 46559243Sobrien blkfree(vl); 46659243Sobrien break; 46759243Sobrien case G_IGNORE: 46859243Sobrien str = Strsave(strip(*vlp)); 46959243Sobrien blkfree(vl); 47059243Sobrien break; 47159243Sobrien default: 47259243Sobrien break; 47359243Sobrien } 47459243Sobrien return (str); 47559243Sobrien} 47659243Sobrien 47759243Sobrienstatic Char ** 47859243Sobrienlibglob(vl) 47959243Sobrien Char **vl; 48059243Sobrien{ 48159243Sobrien int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT; 48259243Sobrien glob_t globv; 48359243Sobrien char *ptr; 48459243Sobrien int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; 48559243Sobrien 48659243Sobrien if (!vl || !vl[0]) 48759243Sobrien return(vl); 48859243Sobrien 48959243Sobrien globv.gl_offs = 0; 49059243Sobrien globv.gl_pathv = 0; 49159243Sobrien globv.gl_pathc = 0; 49259243Sobrien 49359243Sobrien if (nonomatch) 49459243Sobrien gflgs |= GLOB_NOCHECK; 49559243Sobrien 49659243Sobrien do { 49759243Sobrien ptr = short2qstr(*vl); 49859243Sobrien switch (glob(ptr, gflgs, 0, &globv)) { 49959243Sobrien case GLOB_ABEND: 50059243Sobrien globfree(&globv); 50159243Sobrien setname(ptr); 50259243Sobrien stderror(ERR_NAME | ERR_GLOB); 50359243Sobrien /* NOTREACHED */ 50459243Sobrien case GLOB_NOSPACE: 50559243Sobrien globfree(&globv); 50659243Sobrien stderror(ERR_NOMEM); 50759243Sobrien /* NOTREACHED */ 50859243Sobrien default: 50959243Sobrien break; 51059243Sobrien } 51159243Sobrien if (globv.gl_flags & GLOB_MAGCHAR) { 51259243Sobrien match |= (globv.gl_matchc != 0); 51359243Sobrien magic = 1; 51459243Sobrien } 51559243Sobrien gflgs |= GLOB_APPEND; 51659243Sobrien } 51759243Sobrien while (*++vl); 51859243Sobrien vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 51959243Sobrien NULL : blk2short(globv.gl_pathv); 52059243Sobrien globfree(&globv); 52159243Sobrien return (vl); 52259243Sobrien} 52359243Sobrien 52459243SobrienChar * 52559243Sobrienglobone(str, action) 52659243Sobrien Char *str; 52759243Sobrien int action; 52859243Sobrien{ 52959243Sobrien 53059243Sobrien Char *v[2], **vl, **vo; 53159243Sobrien int gflg; 53259243Sobrien 53359243Sobrien noglob = adrof(STRnoglob) != 0; 53459243Sobrien gflag = 0; 53559243Sobrien v[0] = str; 53659243Sobrien v[1] = 0; 53759243Sobrien tglob(v); 53859243Sobrien gflg = gflag; 53959243Sobrien if (gflg == G_NONE) 54059243Sobrien return (strip(Strsave(str))); 54159243Sobrien 54259243Sobrien if (gflg & G_CSH) { 54359243Sobrien /* 54459243Sobrien * Expand back-quote, tilde and brace 54559243Sobrien */ 54659243Sobrien vo = globexpand(v); 54759243Sobrien if (noglob || (gflg & G_GLOB) == 0) { 54859243Sobrien if (vo[0] == NULL) { 54959243Sobrien xfree((ptr_t) vo); 55059243Sobrien return (Strsave(STRNULL)); 55159243Sobrien } 55259243Sobrien if (vo[1] != NULL) 55359243Sobrien return (handleone(str, vo, action)); 55459243Sobrien else { 55559243Sobrien str = strip(vo[0]); 55659243Sobrien xfree((ptr_t) vo); 55759243Sobrien return (str); 55859243Sobrien } 55959243Sobrien } 56059243Sobrien } 56159243Sobrien else if (noglob || (gflg & G_GLOB) == 0) 56259243Sobrien return (strip(Strsave(str))); 56359243Sobrien else 56459243Sobrien vo = v; 56559243Sobrien 56659243Sobrien vl = libglob(vo); 56759243Sobrien if ((gflg & G_CSH) && vl != vo) 56859243Sobrien blkfree(vo); 56959243Sobrien if (vl == NULL) { 57059243Sobrien setname(short2str(str)); 57159243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 57259243Sobrien } 57359243Sobrien if (vl[0] == NULL) { 57459243Sobrien xfree((ptr_t) vl); 57559243Sobrien return (Strsave(STRNULL)); 57659243Sobrien } 57759243Sobrien if (vl[1]) 57859243Sobrien return (handleone(str, vl, action)); 57959243Sobrien else { 58059243Sobrien str = strip(*vl); 58159243Sobrien xfree((ptr_t) vl); 58259243Sobrien return (str); 58359243Sobrien } 58459243Sobrien} 58559243Sobrien 58659243SobrienChar ** 58759243Sobriengloball(v) 58859243Sobrien Char **v; 58959243Sobrien{ 59059243Sobrien Char **vl, **vo; 59159243Sobrien int gflg = gflag; 59259243Sobrien 59359243Sobrien if (!v || !v[0]) { 59459243Sobrien gargv = saveblk(v); 59559243Sobrien gargc = blklen(gargv); 59659243Sobrien return (gargv); 59759243Sobrien } 59859243Sobrien 59959243Sobrien noglob = adrof(STRnoglob) != 0; 60059243Sobrien 60159243Sobrien if (gflg & G_CSH) 60259243Sobrien /* 60359243Sobrien * Expand back-quote, tilde and brace 60459243Sobrien */ 60559243Sobrien vl = vo = globexpand(v); 60659243Sobrien else 60759243Sobrien vl = vo = saveblk(v); 60859243Sobrien 60959243Sobrien if (!noglob && (gflg & G_GLOB)) { 61059243Sobrien vl = libglob(vo); 61159243Sobrien if (vl != vo) 61259243Sobrien blkfree(vo); 61359243Sobrien } 61459243Sobrien else 61559243Sobrien trim(vl); 61659243Sobrien 61759243Sobrien gargc = vl ? blklen(vl) : 0; 61859243Sobrien return (gargv = vl); 61959243Sobrien} 62059243Sobrien 62159243Sobrienvoid 62259243Sobrienginit() 62359243Sobrien{ 62459243Sobrien gargsiz = GLOBSPACE; 62559243Sobrien gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz)); 62659243Sobrien gargv[0] = 0; 62759243Sobrien gargc = 0; 62859243Sobrien} 62959243Sobrien 63059243Sobrienvoid 63159243Sobrienrscan(t, f) 63259243Sobrien register Char **t; 63359243Sobrien void (*f) __P((int)); 63459243Sobrien{ 63559243Sobrien register Char *p; 63659243Sobrien 63759243Sobrien while ((p = *t++) != '\0') 63859243Sobrien while (*p) 63959243Sobrien (*f) (*p++); 64059243Sobrien} 64159243Sobrien 64259243Sobrienvoid 64359243Sobrientrim(t) 64459243Sobrien register Char **t; 64559243Sobrien{ 64659243Sobrien register Char *p; 64759243Sobrien 64859243Sobrien while ((p = *t++) != '\0') 64959243Sobrien while (*p) 65059243Sobrien *p++ &= TRIM; 65159243Sobrien} 65259243Sobrien 65359243Sobrienvoid 65459243Sobrientglob(t) 65559243Sobrien register Char **t; 65659243Sobrien{ 65759243Sobrien register Char *p, *c; 65859243Sobrien 65959243Sobrien while ((p = *t++) != '\0') { 66059243Sobrien if (*p == '~' || *p == '=') 66159243Sobrien gflag |= G_CSH; 66259243Sobrien else if (*p == '{' && 66359243Sobrien (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 66459243Sobrien continue; 66559243Sobrien /* 66659243Sobrien * The following line used to be *(c = p++), but hp broke their 66759243Sobrien * optimizer in 9.01, so we break the assignment into two pieces 66859243Sobrien * The careful reader here will note that *most* compiler workarounds 66959243Sobrien * in tcsh are either for apollo/DomainOS or hpux. Is it a coincidence? 67059243Sobrien */ 67159243Sobrien while ( *(c = p) != '\0') { 67259243Sobrien p++; 67359243Sobrien if (*c == '`') { 67459243Sobrien gflag |= G_CSH; 67559243Sobrien#ifdef notdef 67659243Sobrien /* 67759243Sobrien * We do want to expand echo `echo '*'`, so we don't\ 67859243Sobrien * use this piece of code anymore. 67959243Sobrien */ 68059243Sobrien while (*p && *p != '`') 68159243Sobrien if (*p++ == '\\') { 68259243Sobrien if (*p) /* Quoted chars */ 68359243Sobrien p++; 68459243Sobrien else 68559243Sobrien break; 68659243Sobrien } 68759243Sobrien if (*p) /* The matching ` */ 68859243Sobrien p++; 68959243Sobrien else 69059243Sobrien break; 69159243Sobrien#endif 69259243Sobrien } 69359243Sobrien else if (*c == '{') 69459243Sobrien gflag |= G_CSH; 69559243Sobrien else if (isglob(*c)) 69659243Sobrien gflag |= G_GLOB; 69759243Sobrien else if (symlinks == SYM_EXPAND && 69859243Sobrien *p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') ) 69959243Sobrien gflag |= G_CSH; 70059243Sobrien } 70159243Sobrien } 70259243Sobrien} 70359243Sobrien 70459243Sobrien/* 70559243Sobrien * Command substitute cp. If literal, then this is a substitution from a 70659243Sobrien * << redirection, and so we should not crunch blanks and tabs, separating 70759243Sobrien * words only at newlines. 70859243Sobrien */ 70959243SobrienChar ** 71059243Sobriendobackp(cp, literal) 71159243Sobrien Char *cp; 71259243Sobrien bool literal; 71359243Sobrien{ 71459243Sobrien register Char *lp, *rp; 71559243Sobrien Char *ep, word[LONGBSIZE]; 71659243Sobrien 71759243Sobrien if (pargv) { 71859243Sobrien#ifdef notdef 71959243Sobrien abort(); 72059243Sobrien#endif 72159243Sobrien blkfree(pargv); 72259243Sobrien } 72359243Sobrien pargsiz = GLOBSPACE; 72459243Sobrien pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz)); 72559243Sobrien pargv[0] = NULL; 72659243Sobrien pargcp = pargs = word; 72759243Sobrien pargc = 0; 72859243Sobrien pnleft = LONGBSIZE - 4; 72959243Sobrien for (;;) { 73059243Sobrien for (lp = cp; *lp != '`'; lp++) { 73159243Sobrien if (*lp == 0) { 73259243Sobrien if (pargcp != pargs) 73359243Sobrien pword(LONGBSIZE); 73459243Sobrien return (pargv); 73559243Sobrien } 73659243Sobrien psave(*lp); 73759243Sobrien } 73859243Sobrien lp++; 73959243Sobrien for (rp = lp; *rp && *rp != '`'; rp++) 74059243Sobrien if (*rp == '\\') { 74159243Sobrien rp++; 74259243Sobrien if (!*rp) 74359243Sobrien goto oops; 74459243Sobrien } 74559243Sobrien if (!*rp) 74659243Sobrien oops: stderror(ERR_UNMATCHED, '`'); 74759243Sobrien ep = Strsave(lp); 74859243Sobrien ep[rp - lp] = 0; 74959243Sobrien backeval(ep, literal); 75059243Sobrien cp = rp + 1; 75159243Sobrien } 75259243Sobrien} 75359243Sobrien 75459243Sobrien 75559243Sobrienstatic void 75659243Sobrienbackeval(cp, literal) 75759243Sobrien Char *cp; 75859243Sobrien bool literal; 75959243Sobrien{ 76059243Sobrien register int icnt, c; 76159243Sobrien register Char *ip; 76259243Sobrien struct command faket; 76359243Sobrien bool hadnl; 76459243Sobrien int pvec[2], quoted; 76559243Sobrien Char *fakecom[2], ibuf[BUFSIZE]; 76659243Sobrien char tibuf[BUFSIZE]; 76759243Sobrien 76859243Sobrien hadnl = 0; 76959243Sobrien icnt = 0; 77059243Sobrien quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 77159243Sobrien faket.t_dtyp = NODE_COMMAND; 77259243Sobrien faket.t_dflg = F_BACKQ; 77359243Sobrien faket.t_dlef = 0; 77459243Sobrien faket.t_drit = 0; 77559243Sobrien faket.t_dspr = 0; 77659243Sobrien faket.t_dcom = fakecom; 77759243Sobrien fakecom[0] = STRfakecom1; 77859243Sobrien fakecom[1] = 0; 77959243Sobrien 78059243Sobrien /* 78159243Sobrien * We do the psave job to temporarily change the current job so that the 78259243Sobrien * following fork is considered a separate job. This is so that when 78359243Sobrien * backquotes are used in a builtin function that calls glob the "current 78459243Sobrien * job" is not corrupted. We only need one level of pushed jobs as long as 78559243Sobrien * we are sure to fork here. 78659243Sobrien */ 78759243Sobrien psavejob(); 78859243Sobrien 78959243Sobrien /* 79059243Sobrien * It would be nicer if we could integrate this redirection more with the 79159243Sobrien * routines in sh.sem.c by doing a fake execute on a builtin function that 79259243Sobrien * was piped out. 79359243Sobrien */ 79459243Sobrien mypipe(pvec); 79559243Sobrien if (pfork(&faket, -1) == 0) { 79659243Sobrien struct command *t; 79759243Sobrien 79859243Sobrien (void) close(pvec[0]); 79959243Sobrien (void) dmove(pvec[1], 1); 80059243Sobrien (void) dmove(SHDIAG, 2); 80159243Sobrien initdesc(); 80259243Sobrien /* 80359243Sobrien * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, 80459243Sobrien * posted to comp.bugs.4bsd 12 Sep. 1989. 80559243Sobrien */ 80659243Sobrien if (pargv) /* mg, 21.dec.88 */ 80759243Sobrien blkfree(pargv), pargv = 0, pargsiz = 0; 80859243Sobrien /* mg, 21.dec.88 */ 80959243Sobrien arginp = cp; 81059243Sobrien while (*cp) 81159243Sobrien *cp++ &= TRIM; 81259243Sobrien 81359243Sobrien /* 81459243Sobrien * In the child ``forget'' everything about current aliases or 81559243Sobrien * eval vectors. 81659243Sobrien */ 81759243Sobrien alvec = NULL; 81859243Sobrien evalvec = NULL; 81959243Sobrien alvecp = NULL; 82059243Sobrien evalp = NULL; 82159243Sobrien (void) lex(¶ml); 82259243Sobrien if (seterr) 82359243Sobrien stderror(ERR_OLD); 82459243Sobrien alias(¶ml); 82559243Sobrien t = syntax(paraml.next, ¶ml, 0); 82659243Sobrien if (seterr) 82759243Sobrien stderror(ERR_OLD); 82859243Sobrien if (t) 82959243Sobrien t->t_dflg |= F_NOFORK; 83059243Sobrien#ifdef SIGTSTP 83159243Sobrien (void) sigignore(SIGTSTP); 83259243Sobrien#endif 83359243Sobrien#ifdef SIGTTIN 83459243Sobrien (void) sigignore(SIGTTIN); 83559243Sobrien#endif 83659243Sobrien#ifdef SIGTTOU 83759243Sobrien (void) sigignore(SIGTTOU); 83859243Sobrien#endif 83959243Sobrien execute(t, -1, NULL, NULL); 84059243Sobrien exitstat(); 84159243Sobrien } 84259243Sobrien xfree((ptr_t) cp); 84359243Sobrien (void) close(pvec[1]); 84459243Sobrien c = 0; 84559243Sobrien ip = NULL; 84659243Sobrien do { 84759243Sobrien int cnt = 0; 84859243Sobrien 84959243Sobrien for (;;) { 85059243Sobrien if (icnt == 0) { 85159243Sobrien int i; 85259243Sobrien 85359243Sobrien ip = ibuf; 85459243Sobrien do 85559243Sobrien icnt = read(pvec[0], tibuf, BUFSIZE); 85659243Sobrien while (icnt == -1 && errno == EINTR); 85759243Sobrien if (icnt <= 0) { 85859243Sobrien c = -1; 85959243Sobrien break; 86059243Sobrien } 86159243Sobrien for (i = 0; i < icnt; i++) 86259243Sobrien ip[i] = (unsigned char) tibuf[i]; 86359243Sobrien } 86459243Sobrien if (hadnl) 86559243Sobrien break; 86659243Sobrien --icnt; 86759243Sobrien c = (*ip++ & TRIM); 86859243Sobrien if (c == 0) 86959243Sobrien break; 87059243Sobrien#ifdef WINNT 87159243Sobrien if (c == '\r') 87259243Sobrien c = ' '; 87359243Sobrien#endif /* WINNT */ 87459243Sobrien if (c == '\n') { 87559243Sobrien /* 87659243Sobrien * Continue around the loop one more time, so that we can eat 87759243Sobrien * the last newline without terminating this word. 87859243Sobrien */ 87959243Sobrien hadnl = 1; 88059243Sobrien continue; 88159243Sobrien } 88259243Sobrien if (!quoted && (c == ' ' || c == '\t')) 88359243Sobrien break; 88459243Sobrien cnt++; 88559243Sobrien psave(c | quoted); 88659243Sobrien } 88759243Sobrien /* 88859243Sobrien * Unless at end-of-file, we will form a new word here if there were 88959243Sobrien * characters in the word, or in any case when we take text literally. 89059243Sobrien * If we didn't make empty words here when literal was set then we 89159243Sobrien * would lose blank lines. 89259243Sobrien */ 89359243Sobrien if (c != -1 && (cnt || literal)) 89459243Sobrien pword(BUFSIZE); 89559243Sobrien hadnl = 0; 89659243Sobrien } while (c >= 0); 89759243Sobrien (void) close(pvec[0]); 89859243Sobrien pwait(); 89959243Sobrien prestjob(); 90059243Sobrien} 90159243Sobrien 90259243Sobrienstatic void 90359243Sobrienpsave(c) 90459243Sobrien int c; 90559243Sobrien{ 90659243Sobrien if (--pnleft <= 0) 90759243Sobrien stderror(ERR_WTOOLONG); 90859243Sobrien *pargcp++ = (Char) c; 90959243Sobrien} 91059243Sobrien 91159243Sobrienstatic void 91259243Sobrienpword(bufsiz) 91359243Sobrien int bufsiz; 91459243Sobrien{ 91559243Sobrien psave(0); 91659243Sobrien if (pargc == pargsiz - 1) { 91759243Sobrien pargsiz += GLOBSPACE; 91859243Sobrien pargv = (Char **) xrealloc((ptr_t) pargv, 91959243Sobrien (size_t) (pargsiz * sizeof(Char *))); 92059243Sobrien } 92159243Sobrien pargv[pargc++] = Strsave(pargs); 92259243Sobrien pargv[pargc] = NULL; 92359243Sobrien pargcp = pargs; 92459243Sobrien pnleft = bufsiz - 4; 92559243Sobrien} 92659243Sobrien 92759243Sobrienint 92859243SobrienGmatch(string, pattern) 92959243Sobrien Char *string, *pattern; 93059243Sobrien{ 93159243Sobrien return Gnmatch(string, pattern, NULL); 93259243Sobrien} 93359243Sobrien 93459243Sobrienint 93559243SobrienGnmatch(string, pattern, endstr) 93659243Sobrien Char *string, *pattern, **endstr; 93759243Sobrien{ 93859243Sobrien Char **blk, **p, *tstring = string; 93959243Sobrien int gpol = 1, gres = 0; 94059243Sobrien 94159243Sobrien if (*pattern == '^') { 94259243Sobrien gpol = 0; 94359243Sobrien pattern++; 94459243Sobrien } 94559243Sobrien 94659243Sobrien blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *))); 94759243Sobrien blk[0] = Strsave(pattern); 94859243Sobrien blk[1] = NULL; 94959243Sobrien 95059243Sobrien expbrace(&blk, NULL, GLOBSPACE); 95159243Sobrien 95259243Sobrien if (endstr == NULL) 95359243Sobrien /* Exact matches only */ 95459243Sobrien for (p = blk; *p; p++) 95559243Sobrien gres |= pmatch(string, *p, &tstring) == 2 ? 1 : 0; 95659243Sobrien else { 95759243Sobrien /* partial matches */ 95859243Sobrien int minc = 0x7fffffff; 95959243Sobrien for (p = blk; *p; p++) 96059243Sobrien if (pmatch(string, *p, &tstring) != 0) { 96159243Sobrien int t = (int) (tstring - string); 96259243Sobrien gres |= 1; 96359243Sobrien if (minc == -1 || minc > t) 96459243Sobrien minc = t; 96559243Sobrien } 96659243Sobrien *endstr = string + minc; 96759243Sobrien } 96859243Sobrien 96959243Sobrien blkfree(blk); 97059243Sobrien return(gres == gpol); 97159243Sobrien} 97259243Sobrien 97359243Sobrien/* pmatch(): 97459243Sobrien * Return 2 on exact match, 97559243Sobrien * Return 1 on substring match. 97659243Sobrien * Return 0 on no match. 97759243Sobrien * *estr will point to the end of the longest exact or substring match. 97859243Sobrien */ 97959243Sobrienstatic int 98059243Sobrienpmatch(string, pattern, estr) 98159243Sobrien register Char *string, *pattern, **estr; 98259243Sobrien{ 98359243Sobrien register Char stringc, patternc; 98459243Sobrien int match, negate_range; 98559243Sobrien Char rangec, *oestr, *pestr; 98659243Sobrien 98759243Sobrien for (;; ++string) { 98859243Sobrien stringc = *string & TRIM; 98959243Sobrien /* 99059243Sobrien * apollo compiler bug: switch (patternc = *pattern++) dies 99159243Sobrien */ 99259243Sobrien patternc = *pattern++; 99359243Sobrien switch (patternc) { 99459243Sobrien case 0: 99559243Sobrien *estr = string; 99659243Sobrien return (stringc == 0 ? 2 : 1); 99759243Sobrien case '?': 99859243Sobrien if (stringc == 0) 99959243Sobrien return (0); 100059243Sobrien *estr = string; 100159243Sobrien break; 100259243Sobrien case '*': 100359243Sobrien if (!*pattern) { 100459243Sobrien while (*string) string++; 100559243Sobrien *estr = string; 100659243Sobrien return (2); 100759243Sobrien } 100859243Sobrien oestr = *estr; 100959243Sobrien pestr = NULL; 101059243Sobrien 101159243Sobrien do { 101259243Sobrien switch(pmatch(string, pattern, estr)) { 101359243Sobrien case 0: 101459243Sobrien break; 101559243Sobrien case 1: 101659243Sobrien pestr = *estr; 101759243Sobrien break; 101859243Sobrien case 2: 101959243Sobrien return 2; 102059243Sobrien default: 102159243Sobrien abort(); /* Cannot happen */ 102259243Sobrien } 102359243Sobrien *estr = string; 102459243Sobrien } 102559243Sobrien while (*string++); 102659243Sobrien 102759243Sobrien if (pestr) { 102859243Sobrien *estr = pestr; 102959243Sobrien return 1; 103059243Sobrien } 103159243Sobrien else { 103259243Sobrien *estr = oestr; 103359243Sobrien return 0; 103459243Sobrien } 103559243Sobrien 103659243Sobrien case '[': 103759243Sobrien match = 0; 103859243Sobrien if ((negate_range = (*pattern == '^')) != 0) 103959243Sobrien pattern++; 104059243Sobrien while ((rangec = *pattern++) != '\0') { 104159243Sobrien if (rangec == ']') 104259243Sobrien break; 104359243Sobrien if (match) 104459243Sobrien continue; 104559243Sobrien if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') { 104659243Sobrien match = (globcharcoll(stringc, *pattern & TRIM) <= 0 && 104759243Sobrien globcharcoll(*(pattern-2) & TRIM, stringc) <= 0); 104859243Sobrien pattern++; 104959243Sobrien } 105059243Sobrien else 105159243Sobrien match = (stringc == (rangec & TRIM)); 105259243Sobrien } 105359243Sobrien if (rangec == 0) 105459243Sobrien stderror(ERR_NAME | ERR_MISSING, ']'); 105559243Sobrien if (match == negate_range) 105659243Sobrien return (0); 105759243Sobrien *estr = string; 105859243Sobrien break; 105959243Sobrien default: 106059243Sobrien if ((patternc & TRIM) != stringc) 106159243Sobrien return (0); 106259243Sobrien *estr = string; 106359243Sobrien break; 106459243Sobrien } 106559243Sobrien } 106659243Sobrien} 106759243Sobrien 106859243Sobrienvoid 106959243SobrienGcat(s1, s2) 107059243Sobrien Char *s1, *s2; 107159243Sobrien{ 107259243Sobrien register Char *p, *q; 107359243Sobrien int n; 107459243Sobrien 107559243Sobrien for (p = s1; *p++;) 107659243Sobrien continue; 107759243Sobrien for (q = s2; *q++;) 107859243Sobrien continue; 107959243Sobrien n = (int) ((p - s1) + (q - s2) - 1); 108059243Sobrien if (++gargc >= gargsiz) { 108159243Sobrien gargsiz += GLOBSPACE; 108259243Sobrien gargv = (Char **) xrealloc((ptr_t) gargv, 108359243Sobrien (size_t) (gargsiz * sizeof(Char *))); 108459243Sobrien } 108559243Sobrien gargv[gargc] = 0; 108659243Sobrien p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char))); 108759243Sobrien for (q = s1; (*p++ = *q++) != '\0';) 108859243Sobrien continue; 108959243Sobrien for (p--, q = s2; (*p++ = *q++) != '\0';) 109059243Sobrien continue; 109159243Sobrien} 109259243Sobrien 109359243Sobrien#ifdef FILEC 109459243Sobrienint 109559243Sobriensortscmp(a, b) 109659243Sobrien register Char **a, **b; 109759243Sobrien{ 109859243Sobrien if (!a) /* check for NULL */ 109959243Sobrien return (b ? 1 : 0); 110059243Sobrien if (!b) 110159243Sobrien return (-1); 110259243Sobrien 110359243Sobrien if (!*a) /* check for NULL */ 110459243Sobrien return (*b ? 1 : 0); 110559243Sobrien if (!*b) 110659243Sobrien return (-1); 110759243Sobrien 110859243Sobrien return (int) collate(*a, *b); 110959243Sobrien} 111059243Sobrien 111159243Sobrien#endif 1112