145e5710bSMark Peek /* $Header: /p/tcsh/cvsroot/tcsh/sh.glob.c,v 3.74 2006/10/14 17:57:21 christos Exp $ */ 2c80476e4SDavid E. O'Brien /* 3c80476e4SDavid E. O'Brien * sh.glob.c: Regular expression expansion 4c80476e4SDavid E. O'Brien */ 5c80476e4SDavid E. O'Brien /*- 6c80476e4SDavid E. O'Brien * Copyright (c) 1980, 1991 The Regents of the University of California. 7c80476e4SDavid E. O'Brien * All rights reserved. 8c80476e4SDavid E. O'Brien * 9c80476e4SDavid E. O'Brien * Redistribution and use in source and binary forms, with or without 10c80476e4SDavid E. O'Brien * modification, are permitted provided that the following conditions 11c80476e4SDavid E. O'Brien * are met: 12c80476e4SDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright 13c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer. 14c80476e4SDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright 15c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the 16c80476e4SDavid E. O'Brien * documentation and/or other materials provided with the distribution. 1729301572SMark Peek * 3. Neither the name of the University nor the names of its contributors 18c80476e4SDavid E. O'Brien * may be used to endorse or promote products derived from this software 19c80476e4SDavid E. O'Brien * without specific prior written permission. 20c80476e4SDavid E. O'Brien * 21c80476e4SDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22c80476e4SDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23c80476e4SDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24c80476e4SDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25c80476e4SDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26c80476e4SDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27c80476e4SDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28c80476e4SDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29c80476e4SDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30c80476e4SDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31c80476e4SDavid E. O'Brien * SUCH DAMAGE. 32c80476e4SDavid E. O'Brien */ 33c80476e4SDavid E. O'Brien #include "sh.h" 34c80476e4SDavid E. O'Brien 3545e5710bSMark Peek RCSID("$tcsh: sh.glob.c,v 3.74 2006/10/14 17:57:21 christos Exp $") 36c80476e4SDavid E. O'Brien 37c80476e4SDavid E. O'Brien #include "tc.h" 3829301572SMark Peek #include "tw.h" 39c80476e4SDavid E. O'Brien 40c80476e4SDavid E. O'Brien #include "glob.h" 41c80476e4SDavid E. O'Brien 42c80476e4SDavid E. O'Brien /* 43c80476e4SDavid E. O'Brien * Values for gflag 44c80476e4SDavid E. O'Brien */ 45c80476e4SDavid E. O'Brien #define G_NONE 0 /* No globbing needed */ 46c80476e4SDavid E. O'Brien #define G_GLOB 1 /* string contains *?[] characters */ 47c80476e4SDavid E. O'Brien #define G_CSH 2 /* string contains ~`{ characters */ 48c80476e4SDavid E. O'Brien 49c80476e4SDavid E. O'Brien #define GLOBSPACE 100 /* Alloc increment */ 50c80476e4SDavid E. O'Brien 51c80476e4SDavid E. O'Brien 52c80476e4SDavid E. O'Brien #define LBRC '{' 53c80476e4SDavid E. O'Brien #define RBRC '}' 54c80476e4SDavid E. O'Brien #define LBRK '[' 55c80476e4SDavid E. O'Brien #define RBRK ']' 56c80476e4SDavid E. O'Brien #define EOS '\0' 57c80476e4SDavid E. O'Brien 58c80476e4SDavid E. O'Brien /* 59c80476e4SDavid E. O'Brien * globbing is now done in two stages. In the first pass we expand 60c80476e4SDavid E. O'Brien * csh globbing idioms ~`{ and then we proceed doing the normal 61c80476e4SDavid E. O'Brien * globbing if needed ?*[ 62c80476e4SDavid E. O'Brien * 63c80476e4SDavid E. O'Brien * Csh type globbing is handled in globexpand() and the rest is 64c80476e4SDavid E. O'Brien * handled in glob() which is part of the 4.4BSD libc. 65c80476e4SDavid E. O'Brien * 66c80476e4SDavid E. O'Brien */ 6745e5710bSMark Peek static Char *globtilde (Char *); 6845e5710bSMark Peek static Char *handleone (Char *, Char **, int); 6945e5710bSMark Peek static Char **libglob (Char **); 7045e5710bSMark Peek static Char **globexpand (Char **, int); 7145e5710bSMark Peek static int globbrace (const Char *, Char ***); 7245e5710bSMark Peek static void expbrace (Char ***, Char ***, int); 7345e5710bSMark Peek static void pword (struct blk_buf *, struct Strbuf *); 7445e5710bSMark Peek static void backeval (struct blk_buf *, struct Strbuf *, Char *, 7545e5710bSMark Peek int); 76c80476e4SDavid E. O'Brien static Char * 7745e5710bSMark Peek globtilde(Char *s) 78c80476e4SDavid E. O'Brien { 7945e5710bSMark Peek Char *name, *u, *home, *res; 80c80476e4SDavid E. O'Brien 81c80476e4SDavid E. O'Brien u = s; 8245e5710bSMark Peek for (s++; *s && *s != '/' && *s != ':'; s++) 83c80476e4SDavid E. O'Brien continue; 8445e5710bSMark Peek name = Strnsave(u + 1, s - (u + 1)); 8545e5710bSMark Peek cleanup_push(name, xfree); 8645e5710bSMark Peek home = gethdir(name); 8745e5710bSMark Peek if (home == NULL) { 8845e5710bSMark Peek if (adrof(STRnonomatch)) { 8945e5710bSMark Peek cleanup_until(name); 9045e5710bSMark Peek return u; 9145e5710bSMark Peek } 9245e5710bSMark Peek if (*name) 9345e5710bSMark Peek stderror(ERR_UNKUSER, short2str(name)); 94c80476e4SDavid E. O'Brien else 95c80476e4SDavid E. O'Brien stderror(ERR_NOHOME); 96c80476e4SDavid E. O'Brien } 9745e5710bSMark Peek cleanup_until(name); 9845e5710bSMark Peek if (home[0] == '/' && home[1] == '\0' && s[0] == '/') 9945e5710bSMark Peek res = Strsave(s); 10045e5710bSMark Peek else 10145e5710bSMark Peek res = Strspl(home, s); 10245e5710bSMark Peek xfree(home); 10345e5710bSMark Peek xfree(u); 10445e5710bSMark Peek return res; 105c80476e4SDavid E. O'Brien } 106c80476e4SDavid E. O'Brien 10745e5710bSMark Peek /* Returns a newly allocated string, old or NULL */ 108c80476e4SDavid E. O'Brien Char * 10945e5710bSMark Peek globequal(Char *old) 110c80476e4SDavid E. O'Brien { 111c80476e4SDavid E. O'Brien int dig; 11245e5710bSMark Peek const Char *dir; 11345e5710bSMark Peek Char *b; 114c80476e4SDavid E. O'Brien 115c80476e4SDavid E. O'Brien /* 116c80476e4SDavid E. O'Brien * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names 117c80476e4SDavid E. O'Brien * in stack. PWP: let =foobar pass through (for X windows) 118c80476e4SDavid E. O'Brien */ 119c80476e4SDavid E. O'Brien if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) { 120c80476e4SDavid E. O'Brien /* =- */ 12145e5710bSMark Peek const Char *olddir = varval (STRowd); 12245e5710bSMark Peek 12345e5710bSMark Peek if (olddir && *olddir && 12445e5710bSMark Peek !dcwd->di_next->di_name && !dcwd->di_prev->di_name) 12545e5710bSMark Peek return Strspl(olddir, &old[2]); 126c80476e4SDavid E. O'Brien dig = -1; 127c80476e4SDavid E. O'Brien b = &old[2]; 128c80476e4SDavid E. O'Brien } 129c80476e4SDavid E. O'Brien else if (Isdigit(old[1])) { 130c80476e4SDavid E. O'Brien /* =<number> */ 131c80476e4SDavid E. O'Brien dig = old[1] - '0'; 132c80476e4SDavid E. O'Brien for (b = &old[2]; Isdigit(*b); b++) 133c80476e4SDavid E. O'Brien dig = dig * 10 + (*b - '0'); 134c80476e4SDavid E. O'Brien if (*b != '\0' && *b != '/') 135c80476e4SDavid E. O'Brien /* =<number>foobar */ 136c80476e4SDavid E. O'Brien return old; 137c80476e4SDavid E. O'Brien } 138c80476e4SDavid E. O'Brien else 139c80476e4SDavid E. O'Brien /* =foobar */ 140c80476e4SDavid E. O'Brien return old; 141c80476e4SDavid E. O'Brien 14245e5710bSMark Peek dir = getstakd(dig); 14345e5710bSMark Peek if (dir == NULL) 144c80476e4SDavid E. O'Brien return NULL; 14545e5710bSMark Peek return Strspl(dir, b); 146c80476e4SDavid E. O'Brien } 147c80476e4SDavid E. O'Brien 148c80476e4SDavid E. O'Brien static int 14945e5710bSMark Peek globbrace(const Char *s, Char ***bl) 150c80476e4SDavid E. O'Brien { 15145e5710bSMark Peek struct Strbuf gbuf = Strbuf_INIT; 15245e5710bSMark Peek struct blk_buf bb = BLK_BUF_INIT; 15345e5710bSMark Peek int i; 15445e5710bSMark Peek const Char *p, *pm, *pe, *pl; 15545e5710bSMark Peek size_t prefix_len; 156c80476e4SDavid E. O'Brien 157c80476e4SDavid E. O'Brien /* copy part up to the brace */ 15845e5710bSMark Peek for (p = s; *p != LBRC; p++) 15945e5710bSMark Peek ; 16045e5710bSMark Peek prefix_len = p - s; 161c80476e4SDavid E. O'Brien 162c80476e4SDavid E. O'Brien /* check for balanced braces */ 163c80476e4SDavid E. O'Brien for (i = 0, pe = ++p; *pe; pe++) 164c80476e4SDavid E. O'Brien if (*pe == LBRK) { 165c80476e4SDavid E. O'Brien /* Ignore everything between [] */ 166c80476e4SDavid E. O'Brien for (++pe; *pe != RBRK && *pe != EOS; pe++) 167c80476e4SDavid E. O'Brien continue; 16845e5710bSMark Peek if (*pe == EOS) 169c80476e4SDavid E. O'Brien return (-RBRK); 170c80476e4SDavid E. O'Brien } 171c80476e4SDavid E. O'Brien else if (*pe == LBRC) 172c80476e4SDavid E. O'Brien i++; 173c80476e4SDavid E. O'Brien else if (*pe == RBRC) { 174c80476e4SDavid E. O'Brien if (i == 0) 175c80476e4SDavid E. O'Brien break; 176c80476e4SDavid E. O'Brien i--; 177c80476e4SDavid E. O'Brien } 178c80476e4SDavid E. O'Brien 17945e5710bSMark Peek if (i != 0 || *pe == '\0') 180c80476e4SDavid E. O'Brien return (-RBRC); 18145e5710bSMark Peek 18245e5710bSMark Peek Strbuf_appendn(&gbuf, s, prefix_len); 183c80476e4SDavid E. O'Brien 184c80476e4SDavid E. O'Brien for (i = 0, pl = pm = p; pm <= pe; pm++) 185c80476e4SDavid E. O'Brien switch (*pm) { 186c80476e4SDavid E. O'Brien case LBRK: 187c80476e4SDavid E. O'Brien for (++pm; *pm != RBRK && *pm != EOS; pm++) 188c80476e4SDavid E. O'Brien continue; 189c80476e4SDavid E. O'Brien if (*pm == EOS) { 19045e5710bSMark Peek bb_cleanup(&bb); 19145e5710bSMark Peek xfree(gbuf.s); 192c80476e4SDavid E. O'Brien return (-RBRK); 193c80476e4SDavid E. O'Brien } 194c80476e4SDavid E. O'Brien break; 195c80476e4SDavid E. O'Brien case LBRC: 196c80476e4SDavid E. O'Brien i++; 197c80476e4SDavid E. O'Brien break; 198c80476e4SDavid E. O'Brien case RBRC: 199c80476e4SDavid E. O'Brien if (i) { 200c80476e4SDavid E. O'Brien i--; 201c80476e4SDavid E. O'Brien break; 202c80476e4SDavid E. O'Brien } 203c80476e4SDavid E. O'Brien /* FALLTHROUGH */ 204c80476e4SDavid E. O'Brien case ',': 205c80476e4SDavid E. O'Brien if (i && *pm == ',') 206c80476e4SDavid E. O'Brien break; 207c80476e4SDavid E. O'Brien else { 20845e5710bSMark Peek gbuf.len = prefix_len; 20945e5710bSMark Peek Strbuf_appendn(&gbuf, pl, pm - pl); 21045e5710bSMark Peek Strbuf_append(&gbuf, pe + 1); 21145e5710bSMark Peek Strbuf_terminate(&gbuf); 21245e5710bSMark Peek bb_append(&bb, Strsave(gbuf.s)); 213c80476e4SDavid E. O'Brien pl = pm + 1; 214c80476e4SDavid E. O'Brien } 215c80476e4SDavid E. O'Brien break; 216c80476e4SDavid E. O'Brien default: 217c80476e4SDavid E. O'Brien break; 218c80476e4SDavid E. O'Brien } 21945e5710bSMark Peek *bl = bb_finish(&bb); 22045e5710bSMark Peek xfree(gbuf.s); 22145e5710bSMark Peek return bb.len; 222c80476e4SDavid E. O'Brien } 223c80476e4SDavid E. O'Brien 224c80476e4SDavid E. O'Brien 225c80476e4SDavid E. O'Brien static void 22645e5710bSMark Peek expbrace(Char ***nvp, Char ***elp, int size) 227c80476e4SDavid E. O'Brien { 228c80476e4SDavid E. O'Brien Char **vl, **el, **nv, *s; 229c80476e4SDavid E. O'Brien 230c80476e4SDavid E. O'Brien vl = nv = *nvp; 231c80476e4SDavid E. O'Brien if (elp != NULL) 232c80476e4SDavid E. O'Brien el = *elp; 233c80476e4SDavid E. O'Brien else 23445e5710bSMark Peek el = vl + blklen(vl); 235c80476e4SDavid E. O'Brien 236c80476e4SDavid E. O'Brien for (s = *vl; s; s = *++vl) { 237c80476e4SDavid E. O'Brien Char **vp, **bp; 238c80476e4SDavid E. O'Brien 239c80476e4SDavid E. O'Brien /* leave {} untouched for find */ 240c80476e4SDavid E. O'Brien if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 241c80476e4SDavid E. O'Brien continue; 24245e5710bSMark Peek if (Strchr(s, '{') != NULL) { 24345e5710bSMark Peek Char **bl = NULL; 244c80476e4SDavid E. O'Brien int len; 245c80476e4SDavid E. O'Brien 24645e5710bSMark Peek if ((len = globbrace(s, &bl)) < 0) 247c80476e4SDavid E. O'Brien stderror(ERR_MISSING, -len); 24845e5710bSMark Peek xfree(s); 249c80476e4SDavid E. O'Brien if (len == 1) { 250c80476e4SDavid E. O'Brien *vl-- = *bl; 25145e5710bSMark Peek xfree(bl); 252c80476e4SDavid E. O'Brien continue; 253c80476e4SDavid E. O'Brien } 254c80476e4SDavid E. O'Brien if (&el[len] >= &nv[size]) { 25545e5710bSMark Peek size_t l, e; 25645e5710bSMark Peek l = &el[len] - &nv[size]; 257c80476e4SDavid E. O'Brien size += GLOBSPACE > l ? GLOBSPACE : l; 25845e5710bSMark Peek l = vl - nv; 25945e5710bSMark Peek e = el - nv; 26045e5710bSMark Peek nv = xrealloc(nv, size * sizeof(Char *)); 26145e5710bSMark Peek *nvp = nv; /* To keep cleanups working */ 262c80476e4SDavid E. O'Brien vl = nv + l; 263c80476e4SDavid E. O'Brien el = nv + e; 264c80476e4SDavid E. O'Brien } 265c80476e4SDavid E. O'Brien /* nv vl el bl 266c80476e4SDavid E. O'Brien * | | | | 267c80476e4SDavid E. O'Brien * -.--..-- x-- 268c80476e4SDavid E. O'Brien * | len 269c80476e4SDavid E. O'Brien * vp 270c80476e4SDavid E. O'Brien */ 271c80476e4SDavid E. O'Brien vp = vl--; 272c80476e4SDavid E. O'Brien *vp = *bl; 273c80476e4SDavid E. O'Brien len--; 274c80476e4SDavid E. O'Brien for (bp = el; bp != vp; bp--) 275c80476e4SDavid E. O'Brien bp[len] = *bp; 276c80476e4SDavid E. O'Brien el += len; 277c80476e4SDavid E. O'Brien /* nv vl el bl 278c80476e4SDavid E. O'Brien * | | | | 279c80476e4SDavid E. O'Brien * -.-x --- -- 280c80476e4SDavid E. O'Brien * |len 281c80476e4SDavid E. O'Brien * vp 282c80476e4SDavid E. O'Brien */ 283c80476e4SDavid E. O'Brien vp++; 284c80476e4SDavid E. O'Brien for (bp = bl + 1; *bp; *vp++ = *bp++) 285c80476e4SDavid E. O'Brien continue; 28645e5710bSMark Peek xfree(bl); 287c80476e4SDavid E. O'Brien } 288c80476e4SDavid E. O'Brien 289c80476e4SDavid E. O'Brien } 290c80476e4SDavid E. O'Brien if (elp != NULL) 291c80476e4SDavid E. O'Brien *elp = el; 292c80476e4SDavid E. O'Brien } 293c80476e4SDavid E. O'Brien 294c80476e4SDavid E. O'Brien static Char ** 29545e5710bSMark Peek globexpand(Char **v, int noglob) 296c80476e4SDavid E. O'Brien { 297c80476e4SDavid E. O'Brien Char *s; 29845e5710bSMark Peek Char ***fnv, **vl, **el; 299c80476e4SDavid E. O'Brien int size = GLOBSPACE; 300c80476e4SDavid E. O'Brien 301c80476e4SDavid E. O'Brien 30245e5710bSMark Peek fnv = xmalloc(sizeof(Char ***)); 30345e5710bSMark Peek *fnv = vl = xmalloc(sizeof(Char *) * size); 304c80476e4SDavid E. O'Brien *vl = NULL; 30545e5710bSMark Peek cleanup_push(fnv, blk_indirect_cleanup); 306c80476e4SDavid E. O'Brien 307c80476e4SDavid E. O'Brien /* 308c80476e4SDavid E. O'Brien * Step 1: expand backquotes. 309c80476e4SDavid E. O'Brien */ 310c80476e4SDavid E. O'Brien while ((s = *v++) != '\0') { 311c80476e4SDavid E. O'Brien if (Strchr(s, '`')) { 312c80476e4SDavid E. O'Brien int i; 31345e5710bSMark Peek Char **expanded; 314c80476e4SDavid E. O'Brien 31545e5710bSMark Peek expanded = dobackp(s, 0); 31645e5710bSMark Peek for (i = 0; expanded[i] != NULL; i++) { 31745e5710bSMark Peek *vl++ = expanded[i]; 31845e5710bSMark Peek if (vl == &(*fnv)[size]) { 319c80476e4SDavid E. O'Brien size += GLOBSPACE; 32045e5710bSMark Peek *fnv = xrealloc(*fnv, size * sizeof(Char *)); 32145e5710bSMark Peek vl = &(*fnv)[size - GLOBSPACE]; 322c80476e4SDavid E. O'Brien } 323c80476e4SDavid E. O'Brien } 32445e5710bSMark Peek xfree(expanded); 325c80476e4SDavid E. O'Brien } 326c80476e4SDavid E. O'Brien else { 327c80476e4SDavid E. O'Brien *vl++ = Strsave(s); 32845e5710bSMark Peek if (vl == &(*fnv)[size]) { 329c80476e4SDavid E. O'Brien size += GLOBSPACE; 33045e5710bSMark Peek *fnv = xrealloc(*fnv, size * sizeof(Char *)); 33145e5710bSMark Peek vl = &(*fnv)[size - GLOBSPACE]; 332c80476e4SDavid E. O'Brien } 333c80476e4SDavid E. O'Brien } 334c80476e4SDavid E. O'Brien *vl = NULL; 33545e5710bSMark Peek } 336c80476e4SDavid E. O'Brien 337c80476e4SDavid E. O'Brien if (noglob) 33845e5710bSMark Peek goto done; 339c80476e4SDavid E. O'Brien 340c80476e4SDavid E. O'Brien /* 341c80476e4SDavid E. O'Brien * Step 2: expand braces 342c80476e4SDavid E. O'Brien */ 343c80476e4SDavid E. O'Brien el = vl; 34445e5710bSMark Peek expbrace(fnv, &el, size); 345c80476e4SDavid E. O'Brien 346c80476e4SDavid E. O'Brien 347c80476e4SDavid E. O'Brien /* 348c80476e4SDavid E. O'Brien * Step 3: expand ~ = 349c80476e4SDavid E. O'Brien */ 35045e5710bSMark Peek vl = *fnv; 351c80476e4SDavid E. O'Brien for (s = *vl; s; s = *++vl) 352c80476e4SDavid E. O'Brien switch (*s) { 35345e5710bSMark Peek Char *ns; 354c80476e4SDavid E. O'Brien case '~': 35545e5710bSMark Peek *vl = globtilde(s); 356c80476e4SDavid E. O'Brien break; 357c80476e4SDavid E. O'Brien case '=': 35845e5710bSMark Peek if ((ns = globequal(s)) == NULL) { 35945e5710bSMark Peek if (!adrof(STRnonomatch)) 36045e5710bSMark Peek stderror(ERR_DEEP); /* Error */ 361c80476e4SDavid E. O'Brien } 362c80476e4SDavid E. O'Brien if (ns && ns != s) { 363c80476e4SDavid E. O'Brien /* Expansion succeeded */ 36445e5710bSMark Peek xfree(s); 36545e5710bSMark Peek *vl = ns; 366c80476e4SDavid E. O'Brien } 367c80476e4SDavid E. O'Brien break; 368c80476e4SDavid E. O'Brien default: 369c80476e4SDavid E. O'Brien break; 370c80476e4SDavid E. O'Brien } 37145e5710bSMark Peek vl = *fnv; 372c80476e4SDavid E. O'Brien 373c80476e4SDavid E. O'Brien /* 374c80476e4SDavid E. O'Brien * Step 4: expand .. if the variable symlinks==expand is set 375c80476e4SDavid E. O'Brien */ 3766767bd61SMark Peek if (symlinks == SYM_EXPAND) { 377c80476e4SDavid E. O'Brien for (s = *vl; s; s = *++vl) { 378c80476e4SDavid E. O'Brien *vl = dnormalize(s, 1); 37945e5710bSMark Peek xfree(s); 380c80476e4SDavid E. O'Brien } 3813b6eaa7bSAndrey A. Chernov } 382c80476e4SDavid E. O'Brien 38345e5710bSMark Peek done: 38445e5710bSMark Peek cleanup_ignore(fnv); 38545e5710bSMark Peek cleanup_until(fnv); 38645e5710bSMark Peek vl = *fnv; 38745e5710bSMark Peek xfree(fnv); 38845e5710bSMark Peek return vl; 389c80476e4SDavid E. O'Brien } 390c80476e4SDavid E. O'Brien 391c80476e4SDavid E. O'Brien static Char * 39245e5710bSMark Peek handleone(Char *str, Char **vl, int action) 393c80476e4SDavid E. O'Brien { 39445e5710bSMark Peek size_t chars; 395c80476e4SDavid E. O'Brien Char **t, *p, *strp; 396c80476e4SDavid E. O'Brien 397c80476e4SDavid E. O'Brien switch (action) { 398c80476e4SDavid E. O'Brien case G_ERROR: 399c80476e4SDavid E. O'Brien setname(short2str(str)); 400c80476e4SDavid E. O'Brien blkfree(vl); 401c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_AMBIG); 402c80476e4SDavid E. O'Brien break; 403c80476e4SDavid E. O'Brien case G_APPEND: 404c80476e4SDavid E. O'Brien chars = 0; 40545e5710bSMark Peek for (t = vl; (p = *t++) != NULL; chars++) 40645e5710bSMark Peek chars += Strlen(p); 40745e5710bSMark Peek str = xmalloc(chars * sizeof(Char)); 40845e5710bSMark Peek for (t = vl, strp = str; (p = *t++) != '\0'; chars++) { 409c80476e4SDavid E. O'Brien while (*p) 410c80476e4SDavid E. O'Brien *strp++ = *p++ & TRIM; 411c80476e4SDavid E. O'Brien *strp++ = ' '; 412c80476e4SDavid E. O'Brien } 413c80476e4SDavid E. O'Brien *--strp = '\0'; 414c80476e4SDavid E. O'Brien blkfree(vl); 415c80476e4SDavid E. O'Brien break; 416c80476e4SDavid E. O'Brien case G_IGNORE: 41745e5710bSMark Peek str = Strsave(strip(*vl)); 418c80476e4SDavid E. O'Brien blkfree(vl); 419c80476e4SDavid E. O'Brien break; 420c80476e4SDavid E. O'Brien default: 421c80476e4SDavid E. O'Brien break; 422c80476e4SDavid E. O'Brien } 423c80476e4SDavid E. O'Brien return (str); 424c80476e4SDavid E. O'Brien } 425c80476e4SDavid E. O'Brien 426c80476e4SDavid E. O'Brien static Char ** 42745e5710bSMark Peek libglob(Char **vl) 428c80476e4SDavid E. O'Brien { 429c80476e4SDavid E. O'Brien int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT; 430c80476e4SDavid E. O'Brien glob_t globv; 431c80476e4SDavid E. O'Brien char *ptr; 432c80476e4SDavid E. O'Brien int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; 433c80476e4SDavid E. O'Brien 434c80476e4SDavid E. O'Brien if (!vl || !vl[0]) 435c80476e4SDavid E. O'Brien return(vl); 436c80476e4SDavid E. O'Brien 437c80476e4SDavid E. O'Brien globv.gl_offs = 0; 438c80476e4SDavid E. O'Brien globv.gl_pathv = 0; 439c80476e4SDavid E. O'Brien globv.gl_pathc = 0; 440c80476e4SDavid E. O'Brien 441c80476e4SDavid E. O'Brien if (nonomatch) 442c80476e4SDavid E. O'Brien gflgs |= GLOB_NOCHECK; 443c80476e4SDavid E. O'Brien 444c80476e4SDavid E. O'Brien do { 445c80476e4SDavid E. O'Brien ptr = short2qstr(*vl); 446c80476e4SDavid E. O'Brien switch (glob(ptr, gflgs, 0, &globv)) { 447c80476e4SDavid E. O'Brien case GLOB_ABEND: 448c80476e4SDavid E. O'Brien globfree(&globv); 449c80476e4SDavid E. O'Brien setname(ptr); 450c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_GLOB); 451c80476e4SDavid E. O'Brien /* NOTREACHED */ 452c80476e4SDavid E. O'Brien case GLOB_NOSPACE: 453c80476e4SDavid E. O'Brien globfree(&globv); 454c80476e4SDavid E. O'Brien stderror(ERR_NOMEM); 455c80476e4SDavid E. O'Brien /* NOTREACHED */ 456c80476e4SDavid E. O'Brien default: 457c80476e4SDavid E. O'Brien break; 458c80476e4SDavid E. O'Brien } 459c80476e4SDavid E. O'Brien if (globv.gl_flags & GLOB_MAGCHAR) { 460c80476e4SDavid E. O'Brien match |= (globv.gl_matchc != 0); 461c80476e4SDavid E. O'Brien magic = 1; 462c80476e4SDavid E. O'Brien } 463c80476e4SDavid E. O'Brien gflgs |= GLOB_APPEND; 464c80476e4SDavid E. O'Brien } 465c80476e4SDavid E. O'Brien while (*++vl); 466c80476e4SDavid E. O'Brien vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 467c80476e4SDavid E. O'Brien NULL : blk2short(globv.gl_pathv); 468c80476e4SDavid E. O'Brien globfree(&globv); 469c80476e4SDavid E. O'Brien return (vl); 470c80476e4SDavid E. O'Brien } 471c80476e4SDavid E. O'Brien 472c80476e4SDavid E. O'Brien Char * 47345e5710bSMark Peek globone(Char *str, int action) 474c80476e4SDavid E. O'Brien { 475c80476e4SDavid E. O'Brien Char *v[2], **vl, **vo; 47645e5710bSMark Peek int gflg, noglob; 477c80476e4SDavid E. O'Brien 478c80476e4SDavid E. O'Brien noglob = adrof(STRnoglob) != 0; 479c80476e4SDavid E. O'Brien v[0] = str; 480c80476e4SDavid E. O'Brien v[1] = 0; 48145e5710bSMark Peek gflg = tglob(v); 482c80476e4SDavid E. O'Brien if (gflg == G_NONE) 483c80476e4SDavid E. O'Brien return (strip(Strsave(str))); 484c80476e4SDavid E. O'Brien 485c80476e4SDavid E. O'Brien if (gflg & G_CSH) { 486c80476e4SDavid E. O'Brien /* 487c80476e4SDavid E. O'Brien * Expand back-quote, tilde and brace 488c80476e4SDavid E. O'Brien */ 48945e5710bSMark Peek vo = globexpand(v, noglob); 490c80476e4SDavid E. O'Brien if (noglob || (gflg & G_GLOB) == 0) { 49145e5710bSMark Peek vl = vo; 49245e5710bSMark Peek goto result; 493c80476e4SDavid E. O'Brien } 49445e5710bSMark Peek cleanup_push(vo, blk_cleanup); 495c80476e4SDavid E. O'Brien } 496c80476e4SDavid E. O'Brien else if (noglob || (gflg & G_GLOB) == 0) 497c80476e4SDavid E. O'Brien return (strip(Strsave(str))); 498c80476e4SDavid E. O'Brien else 499c80476e4SDavid E. O'Brien vo = v; 500c80476e4SDavid E. O'Brien 501c80476e4SDavid E. O'Brien vl = libglob(vo); 50245e5710bSMark Peek if (gflg & G_CSH) { 50345e5710bSMark Peek if (vl != vo) 50445e5710bSMark Peek cleanup_until(vo); 50545e5710bSMark Peek else 50645e5710bSMark Peek cleanup_ignore(vo); 50745e5710bSMark Peek } 508c80476e4SDavid E. O'Brien if (vl == NULL) { 509c80476e4SDavid E. O'Brien setname(short2str(str)); 510c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_NOMATCH); 511c80476e4SDavid E. O'Brien } 51245e5710bSMark Peek result: 513c80476e4SDavid E. O'Brien if (vl[0] == NULL) { 51445e5710bSMark Peek xfree(vl); 515c80476e4SDavid E. O'Brien return (Strsave(STRNULL)); 516c80476e4SDavid E. O'Brien } 517c80476e4SDavid E. O'Brien if (vl[1]) 518c80476e4SDavid E. O'Brien return (handleone(str, vl, action)); 519c80476e4SDavid E. O'Brien else { 520c80476e4SDavid E. O'Brien str = strip(*vl); 52145e5710bSMark Peek xfree(vl); 522c80476e4SDavid E. O'Brien return (str); 523c80476e4SDavid E. O'Brien } 524c80476e4SDavid E. O'Brien } 525c80476e4SDavid E. O'Brien 526c80476e4SDavid E. O'Brien Char ** 52745e5710bSMark Peek globall(Char **v, int gflg) 528c80476e4SDavid E. O'Brien { 529c80476e4SDavid E. O'Brien Char **vl, **vo; 53045e5710bSMark Peek int noglob; 531c80476e4SDavid E. O'Brien 53245e5710bSMark Peek if (!v || !v[0]) 53345e5710bSMark Peek return saveblk(v); 534c80476e4SDavid E. O'Brien 535c80476e4SDavid E. O'Brien noglob = adrof(STRnoglob) != 0; 536c80476e4SDavid E. O'Brien 537c80476e4SDavid E. O'Brien if (gflg & G_CSH) 538c80476e4SDavid E. O'Brien /* 539c80476e4SDavid E. O'Brien * Expand back-quote, tilde and brace 540c80476e4SDavid E. O'Brien */ 54145e5710bSMark Peek vl = vo = globexpand(v, noglob); 542c80476e4SDavid E. O'Brien else 543c80476e4SDavid E. O'Brien vl = vo = saveblk(v); 544c80476e4SDavid E. O'Brien 545c80476e4SDavid E. O'Brien if (!noglob && (gflg & G_GLOB)) { 54645e5710bSMark Peek cleanup_push(vo, blk_cleanup); 547c80476e4SDavid E. O'Brien vl = libglob(vo); 54845e5710bSMark Peek if (vl == vo) 54945e5710bSMark Peek cleanup_ignore(vo); 55045e5710bSMark Peek cleanup_until(vo); 551c80476e4SDavid E. O'Brien } 552c80476e4SDavid E. O'Brien else 553c80476e4SDavid E. O'Brien trim(vl); 554c80476e4SDavid E. O'Brien 55545e5710bSMark Peek return vl; 556c80476e4SDavid E. O'Brien } 557c80476e4SDavid E. O'Brien 55845e5710bSMark Peek Char ** 55945e5710bSMark Peek glob_all_or_error(Char **v) 560c80476e4SDavid E. O'Brien { 56145e5710bSMark Peek int gflag; 56245e5710bSMark Peek 56345e5710bSMark Peek gflag = tglob(v); 56445e5710bSMark Peek if (gflag) { 56545e5710bSMark Peek v = globall(v, gflag); 56645e5710bSMark Peek if (v == NULL) 56745e5710bSMark Peek stderror(ERR_NAME | ERR_NOMATCH); 56845e5710bSMark Peek } else { 56945e5710bSMark Peek v = saveblk(v); 57045e5710bSMark Peek trim(v); 57145e5710bSMark Peek } 57245e5710bSMark Peek return v; 573c80476e4SDavid E. O'Brien } 574c80476e4SDavid E. O'Brien 575c80476e4SDavid E. O'Brien void 57645e5710bSMark Peek rscan(Char **t, void (*f) (Char)) 577c80476e4SDavid E. O'Brien { 57823338178SMark Peek Char *p; 579c80476e4SDavid E. O'Brien 580c80476e4SDavid E. O'Brien while ((p = *t++) != '\0') 581c80476e4SDavid E. O'Brien while (*p) 582c80476e4SDavid E. O'Brien (*f) (*p++); 583c80476e4SDavid E. O'Brien } 584c80476e4SDavid E. O'Brien 585c80476e4SDavid E. O'Brien void 58645e5710bSMark Peek trim(Char **t) 587c80476e4SDavid E. O'Brien { 58823338178SMark Peek Char *p; 589c80476e4SDavid E. O'Brien 590c80476e4SDavid E. O'Brien while ((p = *t++) != '\0') 591c80476e4SDavid E. O'Brien while (*p) 592c80476e4SDavid E. O'Brien *p++ &= TRIM; 593c80476e4SDavid E. O'Brien } 594c80476e4SDavid E. O'Brien 59545e5710bSMark Peek int 59645e5710bSMark Peek tglob(Char **t) 597c80476e4SDavid E. O'Brien { 59845e5710bSMark Peek int gflag; 59945e5710bSMark Peek const Char *p; 600c80476e4SDavid E. O'Brien 60145e5710bSMark Peek gflag = 0; 602c80476e4SDavid E. O'Brien while ((p = *t++) != '\0') { 603c80476e4SDavid E. O'Brien if (*p == '~' || *p == '=') 604c80476e4SDavid E. O'Brien gflag |= G_CSH; 605c80476e4SDavid E. O'Brien else if (*p == '{' && 606c80476e4SDavid E. O'Brien (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 607c80476e4SDavid E. O'Brien continue; 60845e5710bSMark Peek while (*p != '\0') { 60945e5710bSMark Peek if (*p == '`') { 610c80476e4SDavid E. O'Brien gflag |= G_CSH; 611c80476e4SDavid E. O'Brien #ifdef notdef 612c80476e4SDavid E. O'Brien /* 613c80476e4SDavid E. O'Brien * We do want to expand echo `echo '*'`, so we don't\ 614c80476e4SDavid E. O'Brien * use this piece of code anymore. 615c80476e4SDavid E. O'Brien */ 61645e5710bSMark Peek p++; 617c80476e4SDavid E. O'Brien while (*p && *p != '`') 618c80476e4SDavid E. O'Brien if (*p++ == '\\') { 619c80476e4SDavid E. O'Brien if (*p) /* Quoted chars */ 620c80476e4SDavid E. O'Brien p++; 621c80476e4SDavid E. O'Brien else 622c80476e4SDavid E. O'Brien break; 623c80476e4SDavid E. O'Brien } 62445e5710bSMark Peek if (!*p) /* The matching ` */ 625c80476e4SDavid E. O'Brien break; 626c80476e4SDavid E. O'Brien #endif 627c80476e4SDavid E. O'Brien } 62845e5710bSMark Peek else if (*p == '{') 629c80476e4SDavid E. O'Brien gflag |= G_CSH; 63045e5710bSMark Peek else if (isglob(*p)) 631c80476e4SDavid E. O'Brien gflag |= G_GLOB; 632c80476e4SDavid E. O'Brien else if (symlinks == SYM_EXPAND && 63345e5710bSMark Peek p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') ) 634c80476e4SDavid E. O'Brien gflag |= G_CSH; 63545e5710bSMark Peek p++; 636c80476e4SDavid E. O'Brien } 637c80476e4SDavid E. O'Brien } 63845e5710bSMark Peek return gflag; 639c80476e4SDavid E. O'Brien } 640c80476e4SDavid E. O'Brien 641c80476e4SDavid E. O'Brien /* 642c80476e4SDavid E. O'Brien * Command substitute cp. If literal, then this is a substitution from a 643c80476e4SDavid E. O'Brien * << redirection, and so we should not crunch blanks and tabs, separating 644c80476e4SDavid E. O'Brien * words only at newlines. 645c80476e4SDavid E. O'Brien */ 646c80476e4SDavid E. O'Brien Char ** 64745e5710bSMark Peek dobackp(Char *cp, int literal) 648c80476e4SDavid E. O'Brien { 64945e5710bSMark Peek struct Strbuf word = Strbuf_INIT; 65045e5710bSMark Peek struct blk_buf bb = BLK_BUF_INIT; 65145e5710bSMark Peek Char *lp, *rp, *ep; 652c80476e4SDavid E. O'Brien 65345e5710bSMark Peek cleanup_push(&bb, bb_cleanup); 65445e5710bSMark Peek cleanup_push(&word, Strbuf_cleanup); 655c80476e4SDavid E. O'Brien for (;;) { 65645e5710bSMark Peek for (lp = cp; *lp != '\0' && *lp != '`'; lp++) 65745e5710bSMark Peek ; 65845e5710bSMark Peek Strbuf_appendn(&word, cp, lp - cp); 65945e5710bSMark Peek if (*lp == 0) 66045e5710bSMark Peek break; 661c80476e4SDavid E. O'Brien lp++; 662c80476e4SDavid E. O'Brien for (rp = lp; *rp && *rp != '`'; rp++) 663c80476e4SDavid E. O'Brien if (*rp == '\\') { 664c80476e4SDavid E. O'Brien rp++; 665c80476e4SDavid E. O'Brien if (!*rp) 666c80476e4SDavid E. O'Brien goto oops; 667c80476e4SDavid E. O'Brien } 66845e5710bSMark Peek if (!*rp) { 66945e5710bSMark Peek oops: 67045e5710bSMark Peek stderror(ERR_UNMATCHED, '`'); 67145e5710bSMark Peek } 67245e5710bSMark Peek ep = Strnsave(lp, rp - lp); 67345e5710bSMark Peek cleanup_push(ep, xfree); 67445e5710bSMark Peek backeval(&bb, &word, ep, literal); 67545e5710bSMark Peek cleanup_until(ep); 676c80476e4SDavid E. O'Brien cp = rp + 1; 677c80476e4SDavid E. O'Brien } 67845e5710bSMark Peek if (word.len != 0) 67945e5710bSMark Peek pword(&bb, &word); 68045e5710bSMark Peek cleanup_ignore(&bb); 68145e5710bSMark Peek cleanup_until(&bb); 68245e5710bSMark Peek return bb_finish(&bb); 683c80476e4SDavid E. O'Brien } 684c80476e4SDavid E. O'Brien 685c80476e4SDavid E. O'Brien 686c80476e4SDavid E. O'Brien static void 68745e5710bSMark Peek backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal) 688c80476e4SDavid E. O'Brien { 68923338178SMark Peek int icnt; 69023338178SMark Peek Char c, *ip; 691c80476e4SDavid E. O'Brien struct command faket; 69223338178SMark Peek int hadnl; 693c80476e4SDavid E. O'Brien int pvec[2], quoted; 694c80476e4SDavid E. O'Brien Char *fakecom[2], ibuf[BUFSIZE]; 695c80476e4SDavid E. O'Brien char tibuf[BUFSIZE]; 696c80476e4SDavid E. O'Brien 697c80476e4SDavid E. O'Brien hadnl = 0; 698c80476e4SDavid E. O'Brien icnt = 0; 699c80476e4SDavid E. O'Brien quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 700c80476e4SDavid E. O'Brien faket.t_dtyp = NODE_COMMAND; 701c80476e4SDavid E. O'Brien faket.t_dflg = F_BACKQ; 702c80476e4SDavid E. O'Brien faket.t_dlef = 0; 703c80476e4SDavid E. O'Brien faket.t_drit = 0; 704c80476e4SDavid E. O'Brien faket.t_dspr = 0; 705c80476e4SDavid E. O'Brien faket.t_dcom = fakecom; 706c80476e4SDavid E. O'Brien fakecom[0] = STRfakecom1; 707c80476e4SDavid E. O'Brien fakecom[1] = 0; 708c80476e4SDavid E. O'Brien 709c80476e4SDavid E. O'Brien /* 710c80476e4SDavid E. O'Brien * We do the psave job to temporarily change the current job so that the 711c80476e4SDavid E. O'Brien * following fork is considered a separate job. This is so that when 712c80476e4SDavid E. O'Brien * backquotes are used in a builtin function that calls glob the "current 713c80476e4SDavid E. O'Brien * job" is not corrupted. We only need one level of pushed jobs as long as 714c80476e4SDavid E. O'Brien * we are sure to fork here. 715c80476e4SDavid E. O'Brien */ 716c80476e4SDavid E. O'Brien psavejob(); 71745e5710bSMark Peek cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */ 718c80476e4SDavid E. O'Brien 719c80476e4SDavid E. O'Brien /* 720c80476e4SDavid E. O'Brien * It would be nicer if we could integrate this redirection more with the 721c80476e4SDavid E. O'Brien * routines in sh.sem.c by doing a fake execute on a builtin function that 722c80476e4SDavid E. O'Brien * was piped out. 723c80476e4SDavid E. O'Brien */ 724c80476e4SDavid E. O'Brien mypipe(pvec); 72545e5710bSMark Peek cleanup_push(&pvec[0], open_cleanup); 72645e5710bSMark Peek cleanup_push(&pvec[1], open_cleanup); 727c80476e4SDavid E. O'Brien if (pfork(&faket, -1) == 0) { 72823338178SMark Peek jmp_buf_t osetexit; 72945e5710bSMark Peek struct command *t; 73045e5710bSMark Peek size_t omark; 731c80476e4SDavid E. O'Brien 73245e5710bSMark Peek xclose(pvec[0]); 733c80476e4SDavid E. O'Brien (void) dmove(pvec[1], 1); 734c80476e4SDavid E. O'Brien (void) dmove(SHDIAG, 2); 735c80476e4SDavid E. O'Brien initdesc(); 73629301572SMark Peek closem(); 737c80476e4SDavid E. O'Brien arginp = cp; 73829301572SMark Peek for (arginp = cp; *cp; cp++) { 73929301572SMark Peek *cp &= TRIM; 74023338178SMark Peek if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r')) 74129301572SMark Peek *cp = ' '; 74229301572SMark Peek } 743c80476e4SDavid E. O'Brien 744c80476e4SDavid E. O'Brien /* 745c80476e4SDavid E. O'Brien * In the child ``forget'' everything about current aliases or 746c80476e4SDavid E. O'Brien * eval vectors. 747c80476e4SDavid E. O'Brien */ 748c80476e4SDavid E. O'Brien alvec = NULL; 749c80476e4SDavid E. O'Brien evalvec = NULL; 750c80476e4SDavid E. O'Brien alvecp = NULL; 751c80476e4SDavid E. O'Brien evalp = NULL; 75223338178SMark Peek 75345e5710bSMark Peek omark = cleanup_push_mark(); 75423338178SMark Peek getexit(osetexit); 75523338178SMark Peek for (;;) { 75623338178SMark Peek (void) setexit(); 75723338178SMark Peek justpr = 0; 75823338178SMark Peek 75923338178SMark Peek if (haderr) { 76023338178SMark Peek /* unwind */ 76123338178SMark Peek doneinp = 0; 76245e5710bSMark Peek cleanup_pop_mark(omark); 76323338178SMark Peek resexit(osetexit); 76423338178SMark Peek reset(); 76523338178SMark Peek } 76623338178SMark Peek if (seterr) { 76745e5710bSMark Peek xfree(seterr); 76823338178SMark Peek seterr = NULL; 76923338178SMark Peek } 77023338178SMark Peek 771c80476e4SDavid E. O'Brien (void) lex(¶ml); 77245e5710bSMark Peek cleanup_push(¶ml, lex_cleanup); 773c80476e4SDavid E. O'Brien if (seterr) 774c80476e4SDavid E. O'Brien stderror(ERR_OLD); 775c80476e4SDavid E. O'Brien alias(¶ml); 776c80476e4SDavid E. O'Brien t = syntax(paraml.next, ¶ml, 0); 77745e5710bSMark Peek cleanup_push(t, syntax_cleanup); 778c80476e4SDavid E. O'Brien if (seterr) 779c80476e4SDavid E. O'Brien stderror(ERR_OLD); 780c80476e4SDavid E. O'Brien #ifdef SIGTSTP 78145e5710bSMark Peek signal(SIGTSTP, SIG_IGN); 782c80476e4SDavid E. O'Brien #endif 783c80476e4SDavid E. O'Brien #ifdef SIGTTIN 78445e5710bSMark Peek signal(SIGTTIN, SIG_IGN); 785c80476e4SDavid E. O'Brien #endif 786c80476e4SDavid E. O'Brien #ifdef SIGTTOU 78745e5710bSMark Peek signal(SIGTTOU, SIG_IGN); 788c80476e4SDavid E. O'Brien #endif 78929301572SMark Peek execute(t, -1, NULL, NULL, TRUE); 79023338178SMark Peek 79145e5710bSMark Peek cleanup_until(¶ml); 79223338178SMark Peek } 793c80476e4SDavid E. O'Brien } 79445e5710bSMark Peek cleanup_until(&pvec[1]); 795c80476e4SDavid E. O'Brien c = 0; 796c80476e4SDavid E. O'Brien ip = NULL; 797c80476e4SDavid E. O'Brien do { 798c80476e4SDavid E. O'Brien int cnt = 0; 79923338178SMark Peek char *tmp; 800c80476e4SDavid E. O'Brien 80123338178SMark Peek tmp = tibuf; 802c80476e4SDavid E. O'Brien for (;;) { 80323338178SMark Peek while (icnt == 0) { 80423338178SMark Peek int i, eof; 805c80476e4SDavid E. O'Brien 806c80476e4SDavid E. O'Brien ip = ibuf; 80745e5710bSMark Peek icnt = xread(pvec[0], tmp, tibuf + BUFSIZE - tmp); 80823338178SMark Peek eof = 0; 809c80476e4SDavid E. O'Brien if (icnt <= 0) { 81023338178SMark Peek if (tmp == tibuf) 81123338178SMark Peek goto eof; 81223338178SMark Peek icnt = 0; 81323338178SMark Peek eof = 1; 814c80476e4SDavid E. O'Brien } 81523338178SMark Peek icnt += tmp - tibuf; 81623338178SMark Peek i = 0; 81723338178SMark Peek tmp = tibuf; 81823338178SMark Peek while (tmp < tibuf + icnt) { 81923338178SMark Peek int len; 82023338178SMark Peek 82123338178SMark Peek len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp); 82223338178SMark Peek if (len == -1) { 82323338178SMark Peek reset_mbtowc(); 82423338178SMark Peek if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) { 82523338178SMark Peek break; /* Maybe a partial character */ 82623338178SMark Peek } 82723338178SMark Peek ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */ 82823338178SMark Peek } 82923338178SMark Peek if (len <= 0) 83023338178SMark Peek len = 1; 83123338178SMark Peek i++; 83223338178SMark Peek tmp += len; 83323338178SMark Peek } 83423338178SMark Peek if (tmp != tibuf) 83523338178SMark Peek memmove (tibuf, tmp, tibuf + icnt - tmp); 83623338178SMark Peek tmp = tibuf + (tibuf + icnt - tmp); 83723338178SMark Peek icnt = i; 838c80476e4SDavid E. O'Brien } 839c80476e4SDavid E. O'Brien if (hadnl) 840c80476e4SDavid E. O'Brien break; 841c80476e4SDavid E. O'Brien --icnt; 842c80476e4SDavid E. O'Brien c = (*ip++ & TRIM); 843c80476e4SDavid E. O'Brien if (c == 0) 844c80476e4SDavid E. O'Brien break; 8453b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE 846c80476e4SDavid E. O'Brien if (c == '\r') 847c80476e4SDavid E. O'Brien c = ' '; 8483b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */ 849c80476e4SDavid E. O'Brien if (c == '\n') { 850c80476e4SDavid E. O'Brien /* 851c80476e4SDavid E. O'Brien * Continue around the loop one more time, so that we can eat 852c80476e4SDavid E. O'Brien * the last newline without terminating this word. 853c80476e4SDavid E. O'Brien */ 854c80476e4SDavid E. O'Brien hadnl = 1; 855c80476e4SDavid E. O'Brien continue; 856c80476e4SDavid E. O'Brien } 857c80476e4SDavid E. O'Brien if (!quoted && (c == ' ' || c == '\t')) 858c80476e4SDavid E. O'Brien break; 859c80476e4SDavid E. O'Brien cnt++; 86045e5710bSMark Peek Strbuf_append1(word, c | quoted); 861c80476e4SDavid E. O'Brien } 862c80476e4SDavid E. O'Brien /* 863c80476e4SDavid E. O'Brien * Unless at end-of-file, we will form a new word here if there were 864c80476e4SDavid E. O'Brien * characters in the word, or in any case when we take text literally. 865c80476e4SDavid E. O'Brien * If we didn't make empty words here when literal was set then we 866c80476e4SDavid E. O'Brien * would lose blank lines. 867c80476e4SDavid E. O'Brien */ 86823338178SMark Peek if (c != 0 && (cnt || literal)) 86945e5710bSMark Peek pword(bb, word); 870c80476e4SDavid E. O'Brien hadnl = 0; 87123338178SMark Peek } while (c > 0); 87223338178SMark Peek eof: 87345e5710bSMark Peek cleanup_until(&pvec[0]); 874c80476e4SDavid E. O'Brien pwait(); 87545e5710bSMark Peek cleanup_until(&faket); /* psavejob_cleanup(); */ 876c80476e4SDavid E. O'Brien } 877c80476e4SDavid E. O'Brien 878c80476e4SDavid E. O'Brien static void 87945e5710bSMark Peek pword(struct blk_buf *bb, struct Strbuf *word) 880c80476e4SDavid E. O'Brien { 88145e5710bSMark Peek Char *s; 882c80476e4SDavid E. O'Brien 88345e5710bSMark Peek s = Strbuf_finish(word); 88445e5710bSMark Peek bb_append(bb, s); 88545e5710bSMark Peek *word = Strbuf_init; 886c80476e4SDavid E. O'Brien } 887c80476e4SDavid E. O'Brien 888c80476e4SDavid E. O'Brien int 88945e5710bSMark Peek Gmatch(const Char *string, const Char *pattern) 890c80476e4SDavid E. O'Brien { 891c80476e4SDavid E. O'Brien return Gnmatch(string, pattern, NULL); 892c80476e4SDavid E. O'Brien } 893c80476e4SDavid E. O'Brien 894c80476e4SDavid E. O'Brien int 89545e5710bSMark Peek Gnmatch(const Char *string, const Char *pattern, const Char **endstr) 896c80476e4SDavid E. O'Brien { 89745e5710bSMark Peek Char ***fblk, **p; 89845e5710bSMark Peek const Char *tstring = string; 899c80476e4SDavid E. O'Brien int gpol = 1, gres = 0; 900c80476e4SDavid E. O'Brien 901c80476e4SDavid E. O'Brien if (*pattern == '^') { 902c80476e4SDavid E. O'Brien gpol = 0; 903c80476e4SDavid E. O'Brien pattern++; 904c80476e4SDavid E. O'Brien } 905c80476e4SDavid E. O'Brien 90645e5710bSMark Peek fblk = xmalloc(sizeof(Char ***)); 90745e5710bSMark Peek *fblk = xmalloc(GLOBSPACE * sizeof(Char *)); 90845e5710bSMark Peek (*fblk)[0] = Strsave(pattern); 90945e5710bSMark Peek (*fblk)[1] = NULL; 910c80476e4SDavid E. O'Brien 91145e5710bSMark Peek cleanup_push(fblk, blk_indirect_cleanup); 91245e5710bSMark Peek expbrace(fblk, NULL, GLOBSPACE); 913c80476e4SDavid E. O'Brien 914c80476e4SDavid E. O'Brien if (endstr == NULL) 915c80476e4SDavid E. O'Brien /* Exact matches only */ 91645e5710bSMark Peek for (p = *fblk; *p; p++) 91723338178SMark Peek gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0; 918c80476e4SDavid E. O'Brien else { 91945e5710bSMark Peek const Char *end; 92045e5710bSMark Peek 921c80476e4SDavid E. O'Brien /* partial matches */ 92245e5710bSMark Peek end = Strend(string); 92345e5710bSMark Peek for (p = *fblk; *p; p++) 92423338178SMark Peek if (t_pmatch(string, *p, &tstring, 1) != 0) { 925c80476e4SDavid E. O'Brien gres |= 1; 92645e5710bSMark Peek if (end > tstring) 92745e5710bSMark Peek end = tstring; 928c80476e4SDavid E. O'Brien } 92945e5710bSMark Peek *endstr = end; 930c80476e4SDavid E. O'Brien } 931c80476e4SDavid E. O'Brien 93245e5710bSMark Peek cleanup_until(fblk); 933c80476e4SDavid E. O'Brien return(gres == gpol); 934c80476e4SDavid E. O'Brien } 935c80476e4SDavid E. O'Brien 936b2d5d167SMark Peek /* t_pmatch(): 937c80476e4SDavid E. O'Brien * Return 2 on exact match, 938c80476e4SDavid E. O'Brien * Return 1 on substring match. 939c80476e4SDavid E. O'Brien * Return 0 on no match. 940c80476e4SDavid E. O'Brien * *estr will point to the end of the longest exact or substring match. 941c80476e4SDavid E. O'Brien */ 942b2d5d167SMark Peek int 94345e5710bSMark Peek t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs) 944c80476e4SDavid E. O'Brien { 94545e5710bSMark Peek Char stringc, patternc, rangec; 946c80476e4SDavid E. O'Brien int match, negate_range; 94745e5710bSMark Peek const Char *pestr, *nstring; 948c80476e4SDavid E. O'Brien 94923338178SMark Peek for (nstring = string;; string = nstring) { 95045e5710bSMark Peek stringc = *nstring++ & TRIM; 95145e5710bSMark Peek patternc = *pattern++ & TRIM; 952c80476e4SDavid E. O'Brien switch (patternc) { 95323338178SMark Peek case '\0': 954c80476e4SDavid E. O'Brien *estr = string; 95523338178SMark Peek return (stringc == '\0' ? 2 : 1); 956c80476e4SDavid E. O'Brien case '?': 957c80476e4SDavid E. O'Brien if (stringc == 0) 958c80476e4SDavid E. O'Brien return (0); 959c80476e4SDavid E. O'Brien break; 960c80476e4SDavid E. O'Brien case '*': 961c80476e4SDavid E. O'Brien if (!*pattern) { 96245e5710bSMark Peek *estr = Strend(string); 963c80476e4SDavid E. O'Brien return (2); 964c80476e4SDavid E. O'Brien } 965c80476e4SDavid E. O'Brien pestr = NULL; 966c80476e4SDavid E. O'Brien 96723338178SMark Peek for (;;) { 968b2d5d167SMark Peek switch(t_pmatch(string, pattern, estr, cs)) { 969c80476e4SDavid E. O'Brien case 0: 970c80476e4SDavid E. O'Brien break; 971c80476e4SDavid E. O'Brien case 1: 97245e5710bSMark Peek pestr = *estr;/*FIXME: does not guarantee longest match */ 973c80476e4SDavid E. O'Brien break; 974c80476e4SDavid E. O'Brien case 2: 975c80476e4SDavid E. O'Brien return 2; 976c80476e4SDavid E. O'Brien default: 977c80476e4SDavid E. O'Brien abort(); /* Cannot happen */ 978c80476e4SDavid E. O'Brien } 97945e5710bSMark Peek stringc = *string++ & TRIM; 98023338178SMark Peek if (!stringc) 98123338178SMark Peek break; 982c80476e4SDavid E. O'Brien } 983c80476e4SDavid E. O'Brien 984c80476e4SDavid E. O'Brien if (pestr) { 985c80476e4SDavid E. O'Brien *estr = pestr; 986c80476e4SDavid E. O'Brien return 1; 987c80476e4SDavid E. O'Brien } 98845e5710bSMark Peek else 989c80476e4SDavid E. O'Brien return 0; 990c80476e4SDavid E. O'Brien 991c80476e4SDavid E. O'Brien case '[': 992c80476e4SDavid E. O'Brien match = 0; 993c80476e4SDavid E. O'Brien if ((negate_range = (*pattern == '^')) != 0) 994c80476e4SDavid E. O'Brien pattern++; 99545e5710bSMark Peek while ((rangec = *pattern++ & TRIM) != '\0') { 996c80476e4SDavid E. O'Brien if (rangec == ']') 997c80476e4SDavid E. O'Brien break; 998c80476e4SDavid E. O'Brien if (match) 999c80476e4SDavid E. O'Brien continue; 100023338178SMark Peek if (*pattern == '-' && pattern[1] != ']') { 100145e5710bSMark Peek Char rangec2; 1002c80476e4SDavid E. O'Brien pattern++; 100345e5710bSMark Peek rangec2 = *pattern++ & TRIM; 100423338178SMark Peek match = (globcharcoll(stringc, rangec2, 0) <= 0 && 100523338178SMark Peek globcharcoll(rangec, stringc, 0) <= 0); 1006c80476e4SDavid E. O'Brien } 1007c80476e4SDavid E. O'Brien else 100823338178SMark Peek match = (stringc == rangec); 1009c80476e4SDavid E. O'Brien } 101023338178SMark Peek if (rangec == '\0') 1011c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_MISSING, ']'); 101223338178SMark Peek if ((!match) && (stringc == '\0')) 101323338178SMark Peek return (0); 1014c80476e4SDavid E. O'Brien if (match == negate_range) 1015c80476e4SDavid E. O'Brien return (0); 1016c80476e4SDavid E. O'Brien break; 1017c80476e4SDavid E. O'Brien default: 101823338178SMark Peek if (cs ? patternc != stringc 101923338178SMark Peek : Tolower(patternc) != Tolower(stringc)) 1020c80476e4SDavid E. O'Brien return (0); 1021c80476e4SDavid E. O'Brien break; 1022c80476e4SDavid E. O'Brien } 1023c80476e4SDavid E. O'Brien } 1024c80476e4SDavid E. O'Brien } 1025