PageRenderTime 64ms CodeModel.GetById 12ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/tcsh/sh.glob.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1037 lines | 804 code | 95 blank | 138 comment | 321 complexity | f913745ac510fa5e429c5d4adb1567bf MD5 | raw file
   1/* $Header: /p/tcsh/cvsroot/tcsh/sh.glob.c,v 3.82 2011/02/27 00:15:17 christos Exp $ */
   2/*
   3 * sh.glob.c: Regular expression expansion
   4 */
   5/*-
   6 * Copyright (c) 1980, 1991 The Regents of the University of California.
   7 * All rights reserved.
   8 *
   9 * Redistribution and use in source and binary forms, with or without
  10 * modification, are permitted provided that the following conditions
  11 * are met:
  12 * 1. Redistributions of source code must retain the above copyright
  13 *    notice, this list of conditions and the following disclaimer.
  14 * 2. Redistributions in binary form must reproduce the above copyright
  15 *    notice, this list of conditions and the following disclaimer in the
  16 *    documentation and/or other materials provided with the distribution.
  17 * 3. Neither the name of the University nor the names of its contributors
  18 *    may be used to endorse or promote products derived from this software
  19 *    without specific prior written permission.
  20 *
  21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31 * SUCH DAMAGE.
  32 */
  33#include "sh.h"
  34
  35RCSID("$tcsh: sh.glob.c,v 3.82 2011/02/27 00:15:17 christos Exp $")
  36
  37#include "tc.h"
  38#include "tw.h"
  39
  40#include "glob.h"
  41
  42/*
  43 * Values for gflag
  44 */
  45#define	G_NONE	0		/* No globbing needed			*/
  46#define	G_GLOB	1		/* string contains *?[] characters	*/
  47#define	G_CSH	2		/* string contains ~`{ characters	*/
  48
  49#define	GLOBSPACE	100	/* Alloc increment			*/
  50
  51
  52#define LBRC '{'
  53#define RBRC '}'
  54#define LBRK '['
  55#define RBRK ']'
  56#define EOS '\0'
  57
  58/*
  59 * globbing is now done in two stages. In the first pass we expand
  60 * csh globbing idioms ~`{ and then we proceed doing the normal
  61 * globbing if needed ?*[
  62 *
  63 * Csh type globbing is handled in globexpand() and the rest is
  64 * handled in glob() which is part of the 4.4BSD libc.
  65 *
  66 */
  67static	Char	 *globtilde	(Char *);
  68static	Char     *handleone	(Char *, Char **, int);
  69static	Char	**libglob	(Char **);
  70static	Char	**globexpand	(Char **, int);
  71static	int	  globbrace	(const Char *, Char ***);
  72static  void	  expbrace	(Char ***, Char ***, int);
  73static	void	  pword		(struct blk_buf *, struct Strbuf *);
  74static	void	  backeval	(struct blk_buf *, struct Strbuf *, Char *,
  75				 int);
  76static Char *
  77globtilde(Char *s)
  78{
  79    Char *name, *u, *home, *res;
  80
  81    u = s;
  82    for (s++; *s && *s != '/' && *s != ':'; s++)
  83	continue;
  84    name = Strnsave(u + 1, s - (u + 1));
  85    cleanup_push(name, xfree);
  86    home = gethdir(name);
  87    if (home == NULL) {
  88	if (adrof(STRnonomatch)) {
  89	    cleanup_until(name);
  90	    return u;
  91	}
  92	if (*name)
  93	    stderror(ERR_UNKUSER, short2str(name));
  94	else
  95	    stderror(ERR_NOHOME);
  96    }
  97    cleanup_until(name);
  98    if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
  99	res = Strsave(s);
 100    else
 101	res = Strspl(home, s);
 102    xfree(home);
 103    xfree(u);
 104    return res;
 105}
 106
 107/* Returns a newly allocated string, old or NULL */
 108Char *
 109globequal(Char *old)
 110{
 111    int     dig;
 112    const Char *dir;
 113    Char    *b;
 114
 115    /*
 116     * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
 117     * in stack. PWP: let =foobar pass through (for X windows)
 118     */
 119    if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
 120	/* =- */
 121	const Char *olddir = varval (STRowd);
 122
 123	if (olddir && *olddir &&
 124	    !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
 125	    return Strspl(olddir, &old[2]);
 126	dig = -1;
 127	b = &old[2];
 128    }
 129    else if (Isdigit(old[1])) {
 130	/* =<number> */
 131	dig = old[1] - '0';
 132	for (b = &old[2]; Isdigit(*b); b++)
 133	    dig = dig * 10 + (*b - '0');
 134	if (*b != '\0' && *b != '/')
 135	    /* =<number>foobar */
 136	    return old;
 137    }
 138    else
 139	/* =foobar */
 140	return old;
 141
 142    dir = getstakd(dig);
 143    if (dir == NULL)
 144	return NULL;
 145    return Strspl(dir, b);
 146}
 147
 148static int
 149globbrace(const Char *s, Char ***bl)
 150{
 151    struct Strbuf gbuf = Strbuf_INIT;
 152    struct blk_buf bb = BLK_BUF_INIT;
 153    int     i;
 154    const Char *p, *pm, *pe, *pl;
 155    size_t prefix_len;
 156
 157    /* copy part up to the brace */
 158    for (p = s; *p != LBRC; p++)
 159	;
 160    prefix_len = p - s;
 161
 162    /* check for balanced braces */
 163    for (i = 0, pe = ++p; *pe; pe++)
 164	if (*pe == LBRK) {
 165	    /* Ignore everything between [] */
 166	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
 167		continue;
 168	    if (*pe == EOS)
 169		return (-RBRK);
 170	}
 171	else if (*pe == LBRC)
 172	    i++;
 173	else if (*pe == RBRC) {
 174	    if (i == 0)
 175		break;
 176	    i--;
 177	}
 178
 179    if (i != 0 || *pe == '\0')
 180	return (-RBRC);
 181
 182    Strbuf_appendn(&gbuf, s, prefix_len);
 183
 184    for (i = 0, pl = pm = p; pm <= pe; pm++)
 185	switch (*pm) {
 186	case LBRK:
 187	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
 188		continue;
 189	    if (*pm == EOS) {
 190		bb_cleanup(&bb);
 191		xfree(gbuf.s);
 192		return (-RBRK);
 193	    }
 194	    break;
 195	case LBRC:
 196	    i++;
 197	    break;
 198	case RBRC:
 199	    if (i) {
 200		i--;
 201		break;
 202	    }
 203	    /* FALLTHROUGH */
 204	case ',':
 205	    if (i && *pm == ',')
 206		break;
 207	    else {
 208		gbuf.len = prefix_len;
 209		Strbuf_appendn(&gbuf, pl, pm - pl);
 210		Strbuf_append(&gbuf, pe + 1);
 211		Strbuf_terminate(&gbuf);
 212		bb_append(&bb, Strsave(gbuf.s));
 213		pl = pm + 1;
 214	    }
 215	    break;
 216	default:
 217	    break;
 218	}
 219    *bl = bb_finish(&bb);
 220    xfree(gbuf.s);
 221    return bb.len;
 222}
 223
 224
 225static void
 226expbrace(Char ***nvp, Char ***elp, int size)
 227{
 228    Char **vl, **el, **nv, *s;
 229
 230    vl = nv = *nvp;
 231    if (elp != NULL)
 232	el = *elp;
 233    else
 234	el = vl + blklen(vl);
 235
 236    for (s = *vl; s; s = *++vl) {
 237	Char  **vp, **bp;
 238
 239	/* leave {} untouched for find */
 240	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
 241	    continue;
 242	if (Strchr(s, '{') != NULL) {
 243	    Char  **bl = NULL;
 244	    int     len;
 245
 246	    if ((len = globbrace(s, &bl)) < 0)
 247		stderror(ERR_MISSING, -len);
 248	    xfree(s);
 249	    if (len == 1) {
 250		*vl-- = *bl;
 251		xfree(bl);
 252		continue;
 253	    }
 254	    if (&el[len] >= &nv[size]) {
 255		size_t l, e;
 256		l = &el[len] - &nv[size];
 257		size += GLOBSPACE > l ? GLOBSPACE : l;
 258		l = vl - nv;
 259		e = el - nv;
 260		nv = xrealloc(nv, size * sizeof(Char *));
 261		*nvp = nv; /* To keep cleanups working */
 262		vl = nv + l;
 263		el = nv + e;
 264	    }
 265	    /* nv vl   el     bl
 266	     * |  |    |      |
 267	     * -.--..--	      x--
 268	     *   |            len
 269	     *   vp
 270	     */
 271	    vp = vl--;
 272	    *vp = *bl;
 273	    len--;
 274	    for (bp = el; bp != vp; bp--)
 275		bp[len] = *bp;
 276	    el += len;
 277	    /* nv vl    el bl
 278	     * |  |     |  |
 279	     * -.-x  ---    --
 280	     *   |len
 281	     *   vp
 282	     */
 283	    vp++;
 284	    for (bp = bl + 1; *bp; *vp++ = *bp++)
 285		continue;
 286	    xfree(bl);
 287	}
 288
 289    }
 290    if (elp != NULL)
 291	*elp = el;
 292}
 293
 294static Char **
 295globexpand(Char **v, int noglob)
 296{
 297    Char   *s;
 298    Char  ***fnv, **vl, **el;
 299    int     size = GLOBSPACE;
 300
 301
 302    fnv = xmalloc(sizeof(Char ***));
 303    *fnv = vl = xmalloc(sizeof(Char *) * size);
 304    *vl = NULL;
 305    cleanup_push(fnv, blk_indirect_cleanup);
 306
 307    /*
 308     * Step 1: expand backquotes.
 309     */
 310    while ((s = *v++) != '\0') {
 311	if (Strchr(s, '`')) {
 312	    int     i;
 313	    Char **expanded;
 314
 315	    expanded = dobackp(s, 0);
 316	    for (i = 0; expanded[i] != NULL; i++) {
 317		*vl++ = expanded[i];
 318		if (vl == &(*fnv)[size]) {
 319		    size += GLOBSPACE;
 320		    *fnv = xrealloc(*fnv, size * sizeof(Char *));
 321		    vl = &(*fnv)[size - GLOBSPACE];
 322		}
 323	    }
 324	    xfree(expanded);
 325	}
 326	else {
 327	    *vl++ = Strsave(s);
 328	    if (vl == &(*fnv)[size]) {
 329		size += GLOBSPACE;
 330		*fnv = xrealloc(*fnv, size * sizeof(Char *));
 331		vl = &(*fnv)[size - GLOBSPACE];
 332	    }
 333	}
 334	*vl = NULL;
 335    }
 336
 337    if (noglob)
 338	goto done;
 339
 340    /*
 341     * Step 2: expand braces
 342     */
 343    el = vl;
 344    expbrace(fnv, &el, size);
 345
 346
 347    /*
 348     * Step 3: expand ~ =
 349     */
 350    vl = *fnv;
 351    for (s = *vl; s; s = *++vl)
 352	switch (*s) {
 353	    Char *ns;
 354	case '~':
 355	    *vl = globtilde(s);
 356	    break;
 357	case '=':
 358	    if ((ns = globequal(s)) == NULL) {
 359		if (!adrof(STRnonomatch))
 360		    stderror(ERR_DEEP); /* Error */
 361	    }
 362	    if (ns && ns != s) {
 363		/* Expansion succeeded */
 364		xfree(s);
 365		*vl = ns;
 366	    }
 367	    break;
 368	default:
 369	    break;
 370	}
 371    vl = *fnv;
 372
 373    /*
 374     * Step 4: expand .. if the variable symlinks==expand is set
 375     */
 376    if (symlinks == SYM_EXPAND) {
 377	for (s = *vl; s; s = *++vl) {
 378	    *vl = dnormalize(s, 1);
 379	    xfree(s);
 380	}
 381    }
 382
 383 done:
 384    cleanup_ignore(fnv);
 385    cleanup_until(fnv);
 386    vl = *fnv;
 387    xfree(fnv);
 388    return vl;
 389}
 390
 391static Char *
 392handleone(Char *str, Char **vl, int action)
 393{
 394    size_t chars;
 395    Char **t, *p, *strp;
 396
 397    switch (action) {
 398    case G_ERROR:
 399	setname(short2str(str));
 400	blkfree(vl);
 401	stderror(ERR_NAME | ERR_AMBIG);
 402	break;
 403    case G_APPEND:
 404	chars = 0;
 405	for (t = vl; (p = *t++) != NULL; chars++)
 406	    chars += Strlen(p);
 407	str = xmalloc(chars * sizeof(Char));
 408	for (t = vl, strp = str; (p = *t++) != '\0'; chars++) {
 409	    while (*p)
 410		 *strp++ = *p++ & TRIM;
 411	    *strp++ = ' ';
 412	}
 413	*--strp = '\0';
 414	blkfree(vl);
 415	break;
 416    case G_IGNORE:
 417	str = Strsave(strip(*vl));
 418	blkfree(vl);
 419	break;
 420    default:
 421	break;
 422    }
 423    return (str);
 424}
 425
 426static Char **
 427libglob(Char **vl)
 428{
 429    int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
 430    glob_t  globv;
 431    char   *ptr;
 432    int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
 433
 434    if (adrof(STRglobdot))
 435       gflgs |= GLOB_DOT;
 436
 437    if (adrof(STRglobstar))
 438       gflgs |= GLOB_STAR;
 439
 440    if (!vl || !vl[0])
 441	return(vl);
 442
 443    globv.gl_offs = 0;
 444    globv.gl_pathv = 0;
 445    globv.gl_pathc = 0;
 446
 447    if (nonomatch)
 448	gflgs |= GLOB_NOCHECK;
 449
 450    do {
 451	ptr = short2qstr(*vl);
 452	switch (glob(ptr, gflgs, 0, &globv)) {
 453	case GLOB_ABEND:
 454	    globfree(&globv);
 455	    setname(ptr);
 456	    stderror(ERR_NAME | ERR_GLOB);
 457	    /* NOTREACHED */
 458	case GLOB_NOSPACE:
 459	    globfree(&globv);
 460	    stderror(ERR_NOMEM);
 461	    /* NOTREACHED */
 462	default:
 463	    break;
 464	}
 465	if (globv.gl_flags & GLOB_MAGCHAR) {
 466	    match |= (globv.gl_matchc != 0);
 467	    magic = 1;
 468	}
 469	gflgs |= GLOB_APPEND;
 470    }
 471    while (*++vl);
 472    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 
 473	NULL : blk2short(globv.gl_pathv);
 474    globfree(&globv);
 475    return (vl);
 476}
 477
 478Char   *
 479globone(Char *str, int action)
 480{
 481    Char   *v[2], **vl, **vo;
 482    int gflg, noglob;
 483
 484    noglob = adrof(STRnoglob) != 0;
 485    v[0] = str;
 486    v[1] = 0;
 487    gflg = tglob(v);
 488    if (gflg == G_NONE)
 489	return (strip(Strsave(str)));
 490
 491    if (gflg & G_CSH) {
 492	/*
 493	 * Expand back-quote, tilde and brace
 494	 */
 495	vo = globexpand(v, noglob);
 496	if (noglob || (gflg & G_GLOB) == 0) {
 497	    vl = vo;
 498	    goto result;
 499	}
 500	cleanup_push(vo, blk_cleanup);
 501    }
 502    else if (noglob || (gflg & G_GLOB) == 0)
 503	return (strip(Strsave(str)));
 504    else
 505	vo = v;
 506
 507    vl = libglob(vo);
 508    if (gflg & G_CSH) {
 509    	if (vl != vo)
 510	    cleanup_until(vo);
 511	else
 512	    cleanup_ignore(vo);
 513    }
 514    if (vl == NULL) {
 515	setname(short2str(str));
 516	stderror(ERR_NAME | ERR_NOMATCH);
 517    }
 518 result:
 519    if (vl && vl[0] == NULL) {
 520	xfree(vl);
 521	return (Strsave(STRNULL));
 522    }
 523    if (vl && vl[1]) 
 524	return (handleone(str, vl, action));
 525    else {
 526	str = strip(*vl);
 527	xfree(vl);
 528	return (str);
 529    }
 530}
 531
 532Char  **
 533globall(Char **v, int gflg)
 534{
 535    Char  **vl, **vo;
 536    int noglob;
 537
 538    if (!v || !v[0])
 539	return saveblk(v);
 540
 541    noglob = adrof(STRnoglob) != 0;
 542
 543    if (gflg & G_CSH)
 544	/*
 545	 * Expand back-quote, tilde and brace
 546	 */
 547	vl = vo = globexpand(v, noglob);
 548    else
 549	vl = vo = saveblk(v);
 550
 551    if (!noglob && (gflg & G_GLOB)) {
 552	cleanup_push(vo, blk_cleanup);
 553	vl = libglob(vo);
 554	if (vl == vo)
 555	    cleanup_ignore(vo);
 556	cleanup_until(vo);
 557    }
 558    else
 559	trim(vl);
 560
 561    return vl;
 562}
 563
 564Char **
 565glob_all_or_error(Char **v)
 566{
 567    int gflag;
 568
 569    gflag = tglob(v);
 570    if (gflag) {
 571	v = globall(v, gflag);
 572	if (v == NULL)
 573	    stderror(ERR_NAME | ERR_NOMATCH);
 574    } else {
 575	v = saveblk(v);
 576	trim(v);
 577    }
 578    return v;
 579}
 580
 581void
 582rscan(Char **t, void (*f) (Char))
 583{
 584    Char *p;
 585
 586    while ((p = *t++) != '\0')
 587	while (*p)
 588	    (*f) (*p++);
 589}
 590
 591void
 592trim(Char **t)
 593{
 594    Char *p;
 595
 596    while ((p = *t++) != '\0')
 597	while (*p)
 598	    *p++ &= TRIM;
 599}
 600
 601int
 602tglob(Char **t)
 603{
 604    int gflag;
 605    const Char *p;
 606
 607    gflag = 0;
 608    while ((p = *t++) != '\0') {
 609	if (*p == '~' || *p == '=')
 610	    gflag |= G_CSH;
 611	else if (*p == '{' &&
 612		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
 613	    continue;
 614	while (*p != '\0') {
 615	    if (*p == '`') {
 616		gflag |= G_CSH;
 617#ifdef notdef
 618		/*
 619		 * We do want to expand echo `echo '*'`, so we don't\
 620		 * use this piece of code anymore.
 621		 */
 622		p++;
 623		while (*p && *p != '`') 
 624		    if (*p++ == '\\') {
 625			if (*p)		/* Quoted chars */
 626			    p++;
 627			else
 628			    break;
 629		    }
 630		if (!*p)		/* The matching ` */
 631		    break;
 632#endif
 633	    }
 634	    else if (*p == '{')
 635		gflag |= G_CSH;
 636	    else if (isglob(*p))
 637		gflag |= G_GLOB;
 638	    else if (symlinks == SYM_EXPAND && 
 639		p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
 640	    	gflag |= G_CSH;
 641	    p++;
 642	}
 643    }
 644    return gflag;
 645}
 646
 647/*
 648 * Command substitute cp.  If literal, then this is a substitution from a
 649 * << redirection, and so we should not crunch blanks and tabs, separating
 650 * words only at newlines.
 651 */
 652Char  **
 653dobackp(Char *cp, int literal)
 654{
 655    struct Strbuf word = Strbuf_INIT;
 656    struct blk_buf bb = BLK_BUF_INIT;
 657    Char *lp, *rp, *ep;
 658
 659    cleanup_push(&bb, bb_cleanup);
 660    cleanup_push(&word, Strbuf_cleanup);
 661    for (;;) {
 662	for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
 663	    ;
 664	Strbuf_appendn(&word, cp, lp - cp);
 665	if (*lp == 0)
 666	    break;
 667	lp++;
 668	for (rp = lp; *rp && *rp != '`'; rp++)
 669	    if (*rp == '\\') {
 670		rp++;
 671		if (!*rp)
 672		    goto oops;
 673	    }
 674	if (!*rp) {
 675	oops:
 676	    cleanup_until(&bb);
 677	    stderror(ERR_UNMATCHED, '`');
 678	}
 679	ep = Strnsave(lp, rp - lp);
 680	cleanup_push(ep, xfree);
 681	backeval(&bb, &word, ep, literal);
 682	cleanup_until(ep);
 683	cp = rp + 1;
 684    }
 685    if (word.len != 0)
 686	pword(&bb, &word);
 687    cleanup_ignore(&bb);
 688    cleanup_until(&bb);
 689    return bb_finish(&bb);
 690}
 691
 692
 693static void
 694backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
 695{
 696    ssize_t icnt;
 697    Char c, *ip;
 698    struct command faket;
 699    int    hadnl;
 700    int     pvec[2], quoted;
 701    Char   *fakecom[2], ibuf[BUFSIZE];
 702    char    tibuf[BUFSIZE];
 703
 704    hadnl = 0;
 705    icnt = 0;
 706    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
 707    faket.t_dtyp = NODE_COMMAND;
 708    faket.t_dflg = F_BACKQ;
 709    faket.t_dlef = 0;
 710    faket.t_drit = 0;
 711    faket.t_dspr = 0;
 712    faket.t_dcom = fakecom;
 713    fakecom[0] = STRfakecom1;
 714    fakecom[1] = 0;
 715
 716    /*
 717     * We do the psave job to temporarily change the current job so that the
 718     * following fork is considered a separate job.  This is so that when
 719     * backquotes are used in a builtin function that calls glob the "current
 720     * job" is not corrupted.  We only need one level of pushed jobs as long as
 721     * we are sure to fork here.
 722     */
 723    psavejob();
 724    cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
 725
 726    /*
 727     * It would be nicer if we could integrate this redirection more with the
 728     * routines in sh.sem.c by doing a fake execute on a builtin function that
 729     * was piped out.
 730     */
 731    mypipe(pvec);
 732    cleanup_push(&pvec[0], open_cleanup);
 733    cleanup_push(&pvec[1], open_cleanup);
 734    if (pfork(&faket, -1) == 0) {
 735	jmp_buf_t osetexit;
 736	struct command *t;
 737	size_t omark;
 738
 739	xclose(pvec[0]);
 740	(void) dmove(pvec[1], 1);
 741	(void) dmove(SHDIAG,  2);
 742	initdesc();
 743	closem();
 744	arginp = cp;
 745	for (arginp = cp; *cp; cp++) {
 746	    *cp &= TRIM;
 747	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
 748		*cp = ' ';
 749	}
 750
 751        /*
 752	 * In the child ``forget'' everything about current aliases or
 753	 * eval vectors.
 754	 */
 755	alvec = NULL;
 756	evalvec = NULL;
 757	alvecp = NULL;
 758	evalp = NULL;
 759
 760	omark = cleanup_push_mark();
 761	getexit(osetexit);
 762	for (;;) {
 763	    (void) setexit();
 764	    justpr = 0;
 765	    
 766	    if (haderr) {
 767		/* unwind */
 768		doneinp = 0;
 769		cleanup_pop_mark(omark);
 770		resexit(osetexit);
 771		reset();
 772	    }
 773	    if (seterr) {
 774		xfree(seterr);
 775		seterr = NULL;
 776	    }
 777
 778	    (void) lex(&paraml);
 779	    cleanup_push(&paraml, lex_cleanup);
 780	    if (seterr)
 781		stderror(ERR_OLD);
 782	    alias(&paraml);
 783	    t = syntax(paraml.next, &paraml, 0);
 784	    if (t == NULL)
 785		return;
 786	    cleanup_push(t, syntax_cleanup);
 787	    /* The F_BACKQ flag must set so the job output is correct if
 788	     * printexitvalue is set.  If it's not set, the job output
 789	     * will have "Exit N" appended where N is the exit status. */
 790	    t->t_dflg = F_BACKQ|F_NOFORK;
 791	    if (seterr)
 792		stderror(ERR_OLD);
 793#ifdef SIGTSTP
 794	    signal(SIGTSTP, SIG_IGN);
 795#endif
 796#ifdef SIGTTIN
 797	    signal(SIGTTIN, SIG_IGN);
 798#endif
 799#ifdef SIGTTOU
 800	    signal(SIGTTOU, SIG_IGN);
 801#endif
 802	    execute(t, -1, NULL, NULL, TRUE);
 803
 804	    cleanup_until(&paraml);
 805	}
 806    }
 807    cleanup_until(&pvec[1]);
 808    c = 0;
 809    ip = NULL;
 810    do {
 811	ssize_t     cnt = 0;
 812	char   *tmp;
 813
 814	tmp = tibuf;
 815	for (;;) {
 816	    while (icnt == 0) {
 817		int     i, eof;
 818
 819		ip = ibuf;
 820		icnt = xread(pvec[0], tmp, tibuf + BUFSIZE - tmp);
 821		eof = 0;
 822		if (icnt <= 0) {
 823		    if (tmp == tibuf)
 824			goto eof;
 825		    icnt = 0;
 826		    eof = 1;
 827		}
 828		icnt += tmp - tibuf;
 829		i = 0;
 830		tmp = tibuf;
 831		while (tmp < tibuf + icnt) {
 832		    int len;
 833
 834		    len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp);
 835		    if (len == -1) {
 836		        reset_mbtowc();
 837		        if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) {
 838			    break; /* Maybe a partial character */
 839			}
 840			ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */
 841		    }
 842		    if (len <= 0)
 843		        len = 1;
 844		    i++;
 845		    tmp += len;
 846		}
 847		if (tmp != tibuf)
 848		    memmove (tibuf, tmp, tibuf + icnt - tmp);
 849		tmp = tibuf + (tibuf + icnt - tmp);
 850		icnt = i;
 851	    }
 852	    if (hadnl)
 853		break;
 854	    --icnt;
 855	    c = (*ip++ & TRIM);
 856	    if (c == 0)
 857		break;
 858#if defined(WINNT_NATIVE) || defined(__CYGWIN__)
 859	    if (c == '\r')
 860	    	c = ' ';
 861#endif /* WINNT_NATIVE || __CYGWIN__ */
 862	    if (c == '\n') {
 863		/*
 864		 * Continue around the loop one more time, so that we can eat
 865		 * the last newline without terminating this word.
 866		 */
 867		hadnl = 1;
 868		continue;
 869	    }
 870	    if (!quoted && (c == ' ' || c == '\t'))
 871		break;
 872	    cnt++;
 873	    Strbuf_append1(word, c | quoted);
 874	}
 875	/*
 876	 * Unless at end-of-file, we will form a new word here if there were
 877	 * characters in the word, or in any case when we take text literally.
 878	 * If we didn't make empty words here when literal was set then we
 879	 * would lose blank lines.
 880	 */
 881	if (c != 0 && (cnt || literal))
 882	    pword(bb, word);
 883	hadnl = 0;
 884    } while (c > 0);
 885 eof:
 886    cleanup_until(&pvec[0]);
 887    pwait();
 888    cleanup_until(&faket); /* psavejob_cleanup(); */
 889}
 890
 891static void
 892pword(struct blk_buf *bb, struct Strbuf *word)
 893{
 894    Char *s;
 895
 896    s = Strbuf_finish(word);
 897    bb_append(bb, s);
 898    *word = Strbuf_init;
 899}
 900
 901int
 902Gmatch(const Char *string, const Char *pattern)
 903{
 904    return Gnmatch(string, pattern, NULL);
 905}
 906
 907int
 908Gnmatch(const Char *string, const Char *pattern, const Char **endstr)
 909{
 910    Char ***fblk, **p;
 911    const Char *tstring = string;
 912    int	   gpol = 1, gres = 0;
 913
 914    if (*pattern == '^') {
 915	gpol = 0;
 916	pattern++;
 917    }
 918
 919    fblk = xmalloc(sizeof(Char ***));
 920    *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
 921    (*fblk)[0] = Strsave(pattern);
 922    (*fblk)[1] = NULL;
 923
 924    cleanup_push(fblk, blk_indirect_cleanup);
 925    expbrace(fblk, NULL, GLOBSPACE);
 926
 927    if (endstr == NULL)
 928	/* Exact matches only */
 929	for (p = *fblk; *p; p++) 
 930	    gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
 931    else {
 932	const Char *end;
 933
 934	/* partial matches */
 935        end = Strend(string);
 936	for (p = *fblk; *p; p++)
 937	    if (t_pmatch(string, *p, &tstring, 1) != 0) {
 938		gres |= 1;
 939		if (end > tstring)
 940		    end = tstring;
 941	    }
 942	*endstr = end;
 943    }
 944
 945    cleanup_until(fblk);
 946    return(gres == gpol);
 947} 
 948
 949/* t_pmatch():
 950 *	Return 2 on exact match, 	
 951 *	Return 1 on substring match.
 952 *	Return 0 on no match.
 953 *	*estr will point to the end of the longest exact or substring match.
 954 */
 955int
 956t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
 957{
 958    Char stringc, patternc, rangec;
 959    int     match, negate_range;
 960    const Char *pestr, *nstring;
 961
 962    for (nstring = string;; string = nstring) {
 963	stringc = *nstring++ & TRIM;
 964	patternc = *pattern++ & TRIM;
 965	switch (patternc) {
 966	case '\0':
 967	    *estr = string;
 968	    return (stringc == '\0' ? 2 : 1);
 969	case '?':
 970	    if (stringc == 0)
 971		return (0);
 972	    break;
 973	case '*':
 974	    if (!*pattern) {
 975		*estr = Strend(string);
 976		return (2);
 977	    }
 978	    pestr = NULL;
 979
 980	    for (;;) {
 981		switch(t_pmatch(string, pattern, estr, cs)) {
 982		case 0:
 983		    break;
 984		case 1:
 985		    pestr = *estr;/*FIXME: does not guarantee longest match */
 986		    break;
 987		case 2:
 988		    return 2;
 989		default:
 990		    abort();	/* Cannot happen */
 991		}
 992		stringc = *string++ & TRIM;
 993		if (!stringc)
 994		    break;
 995	    }
 996
 997	    if (pestr) {
 998		*estr = pestr;
 999		return 1;
1000	    }
1001	    else
1002		return 0;
1003
1004	case '[':
1005	    match = 0;
1006	    if ((negate_range = (*pattern == '^')) != 0)
1007		pattern++;
1008	    while ((rangec = *pattern++ & TRIM) != '\0') {
1009		if (rangec == ']')
1010		    break;
1011		if (match)
1012		    continue;
1013		if (*pattern == '-' && pattern[1] != ']') {
1014		    Char rangec2;
1015		    pattern++;
1016		    rangec2 = *pattern++ & TRIM;
1017		    match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
1018			globcharcoll(rangec, stringc, 0) <= 0);
1019		}
1020		else 
1021		    match = (stringc == rangec);
1022	    }
1023	    if (rangec == '\0')
1024		stderror(ERR_NAME | ERR_MISSING, ']');
1025	    if ((!match) && (stringc == '\0'))
1026		return (0);
1027	    if (match == negate_range)
1028		return (0);
1029	    break;
1030	default:
1031	    if (cs ? patternc  != stringc
1032		: Tolower(patternc) != Tolower(stringc))
1033		return (0);
1034	    break;
1035	}
1036    }
1037}