Logo Search packages:      
Sourcecode: tcsh version File versions  Download package

sh.glob.c

/* $Header: /src/pub/tcsh/sh.glob.c,v 3.62 2004/12/25 21:15:07 christos Exp $ */
/*
 * sh.glob.c: Regular expression expansion
 */
/*-
 * Copyright (c) 1980, 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "sh.h"

RCSID("$Id: sh.glob.c,v 3.62 2004/12/25 21:15:07 christos Exp $")

#include "tc.h"
#include "tw.h"

#include "glob.h"

static int noglob;
static int pargsiz, gargsiz;

/*
 * Values for gflag
 */
#define     G_NONE      0           /* No globbing needed               */
#define     G_GLOB      1           /* string contains *?[] characters  */
#define     G_CSH 2           /* string contains ~`{ characters   */

#define     GLOBSPACE   100   /* Alloc increment                  */
#define LONGBSIZE 10240 /* Backquote expansion buffer size  */


#define LBRC '{'
#define RBRC '}'
#define LBRK '['
#define RBRK ']'
#define EOS '\0'

Char  **gargv = NULL;
int     gargc = 0;
Char  **pargv = NULL;
static int pargc = 0;

/*
 * globbing is now done in two stages. In the first pass we expand
 * csh globbing idioms ~`{ and then we proceed doing the normal
 * globbing if needed ?*[
 *
 * Csh type globbing is handled in globexpand() and the rest is
 * handled in glob() which is part of the 4.4BSD libc.
 *
 */
static      Char   *globtilde __P((Char **, Char *));
static      Char     *handleone     __P((Char *, Char **, int));
static      Char  **libglob   __P((Char **));
static      Char  **globexpand      __P((Char **));
static      int     globbrace __P((Char *, Char *, Char ***));
static  void        expbrace  __P((Char ***, Char ***, int));
static      void    pword           __P((int));
static      void    psave           __P((Char));
static      void    backeval  __P((Char *, int));

static Char *
globtilde(nv, s)
    Char  **nv, *s;
{
    Char    gbuf[BUFSIZE], *gstart, *b, *u, *e;
#ifdef apollo
    int slash;
#endif

    gstart = gbuf;
    *gstart++ = *s++;
    u = s;
    for (b = gstart, e = &gbuf[BUFSIZE - 1]; 
       *s && *s != '/' && *s != ':' && b < e;
       *b++ = *s++)
      continue;
    *b = EOS;
    if (gethdir(gstart)) {
      if (adrof(STRnonomatch))
          return (--u);
      blkfree(nv);
      if (*gstart)
          stderror(ERR_UNKUSER, short2str(gstart));
      else
          stderror(ERR_NOHOME);
    }
    b = &gstart[Strlen(gstart)];
#ifdef apollo
    slash = gstart[0] == '/' && gstart[1] == '\0';
#endif
    while (*s)
      *b++ = *s++;
    *b = EOS;
    --u;
    xfree((ptr_t) u);
#ifdef apollo
    if (slash && gstart[1] == '/')
      gstart++;
#endif
    return (Strsave(gstart));
}

Char *
globequal(new, old)
    Char *new, *old;
{
    int     dig;
    Char    *b, *d;

    /*
     * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
     * in stack. PWP: let =foobar pass through (for X windows)
     */
    if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
      /* =- */
      dig = -1;
      b = &old[2];
    }
    else if (Isdigit(old[1])) {
      /* =<number> */
      dig = old[1] - '0';
      for (b = &old[2]; Isdigit(*b); b++)
          dig = dig * 10 + (*b - '0');
      if (*b != '\0' && *b != '/')
          /* =<number>foobar */
          return old;
    }
    else
      /* =foobar */
      return old;

    if (!getstakd(new, dig))
      return NULL;

    /* Copy the rest of the string */
    for (d = &new[Strlen(new)]; 
       d < &new[BUFSIZE - 1] && (*d++ = *b++) != '\0';)
      continue;
    *d = '\0';

    return new;
}

static int
globbrace(s, p, bl)
    Char   *s, *p, ***bl;
{
    int     i, len;
    Char   *pm, *pe, *lm, *pl;
    Char  **nv, **vl;
    Char    gbuf[BUFSIZE];
    int     size = GLOBSPACE;

    nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
    *vl = NULL;

    len = 0;
    /* copy part up to the brace */
    for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
      continue;

    /* check for balanced braces */
    for (i = 0, pe = ++p; *pe; pe++)
      if (*pe == LBRK) {
          /* Ignore everything between [] */
          for (++pe; *pe != RBRK && *pe != EOS; pe++)
            continue;
          if (*pe == EOS) {
            blkfree(nv);
            return (-RBRK);
          }
      }
      else if (*pe == LBRC)
          i++;
      else if (*pe == RBRC) {
          if (i == 0)
            break;
          i--;
      }

    if (i != 0 || *pe == '\0') {
      blkfree(nv);
      return (-RBRC);
    }

    for (i = 0, pl = pm = p; pm <= pe; pm++)
      switch (*pm) {
      case LBRK:
          for (++pm; *pm != RBRK && *pm != EOS; pm++)
            continue;
          if (*pm == EOS) {
            *vl = NULL;
            blkfree(nv);
            return (-RBRK);
          }
          break;
      case LBRC:
          i++;
          break;
      case RBRC:
          if (i) {
            i--;
            break;
          }
          /* FALLTHROUGH */
      case ',':
          if (i && *pm == ',')
            break;
          else {
            Char    savec = *pm;

            *pm = EOS;
            (void) Strcpy(lm, pl);
            (void) Strcat(gbuf, pe + 1);
            *pm = savec;
            *vl++ = Strsave(gbuf);
            len++;
            pl = pm + 1;
            if (vl == &nv[size]) {
                size += GLOBSPACE;
                nv = (Char **) xrealloc((ptr_t) nv, 
                                  (size_t) (size * sizeof(Char *)));
                vl = &nv[size - GLOBSPACE];
            }
          }
          break;
      default:
          break;
      }
    *vl = NULL;
    *bl = nv;
    return (len);
}


static void
expbrace(nvp, elp, size)
    Char ***nvp, ***elp;
    int size;
{
    Char **vl, **el, **nv, *s;

    vl = nv = *nvp;
    if (elp != NULL)
      el = *elp;
    else
      for (el = vl; *el; el++)
          continue;

    for (s = *vl; s; s = *++vl) {
      Char   *b;
      Char  **vp, **bp;

      /* leave {} untouched for find */
      if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
          continue;
      if ((b = Strchr(s, '{')) != NULL) {
          Char  **bl;
          int     len;

          if ((len = globbrace(s, b, &bl)) < 0) {
            xfree((ptr_t) nv);
            stderror(ERR_MISSING, -len);
          }
          xfree((ptr_t) s);
          if (len == 1) {
            *vl-- = *bl;
            xfree((ptr_t) bl);
            continue;
          }
          if (&el[len] >= &nv[size]) {
            int     l, e;
            l = (int) (&el[len] - &nv[size]);
            size += GLOBSPACE > l ? GLOBSPACE : l;
            l = (int) (vl - nv);
            e = (int) (el - nv);
            nv = (Char **) xrealloc((ptr_t) nv, 
                              (size_t) (size * sizeof(Char *)));
            vl = nv + l;
            el = nv + e;
          }
          /* nv vl   el     bl
           * |  |    |      |
           * -.--..--         x--
           *   |            len
           *   vp
           */
          vp = vl--;
          *vp = *bl;
          len--;
          for (bp = el; bp != vp; bp--)
            bp[len] = *bp;
          el += len;
          /* nv vl    el bl
           * |  |     |  |
           * -.-x  ---    --
           *   |len
           *   vp
           */
          vp++;
          for (bp = bl + 1; *bp; *vp++ = *bp++)
            continue;
          xfree((ptr_t) bl);
      }

    }
    if (elp != NULL)
      *elp = el;
    *nvp = nv;
}

static Char **
globexpand(v)
    Char  **v;
{
    Char   *s;
    Char  **nv, **vl, **el;
    int     size = GLOBSPACE;


    nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
    *vl = NULL;

    /*
     * Step 1: expand backquotes.
     */
    while ((s = *v++) != '\0') {
      if (Strchr(s, '`')) {
          int     i;

          (void) dobackp(s, 0);
          for (i = 0; i < pargc; i++) {
            *vl++ = pargv[i];
            if (vl == &nv[size]) {
                size += GLOBSPACE;
                nv = (Char **) xrealloc((ptr_t) nv,
                                  (size_t) (size * sizeof(Char *)));
                vl = &nv[size - GLOBSPACE];
            }
          }
          xfree((ptr_t) pargv);
          pargv = NULL;
      }
      else {
          *vl++ = Strsave(s);
          if (vl == &nv[size]) {
            size += GLOBSPACE;
            nv = (Char **) xrealloc((ptr_t) nv, 
                              (size_t) (size * sizeof(Char *)));
            vl = &nv[size - GLOBSPACE];
          }
      }
    }
    *vl = NULL;

    if (noglob)
      return (nv);

    /*
     * Step 2: expand braces
     */
    el = vl;
    expbrace(&nv, &el, size);


    /*
     * Step 3: expand ~ =
     */
    vl = nv;
    for (s = *vl; s; s = *++vl)
      switch (*s) {
          Char gp[BUFSIZE], *ns;
      case '~':
          *vl = globtilde(nv, s);
          break;
      case '=':
          if ((ns = globequal(gp, s)) == NULL) {
            if (!adrof(STRnonomatch)) {
                /* Error */
                blkfree(nv);
                stderror(ERR_DEEP);
            }
          }
          if (ns && ns != s) {
            /* Expansion succeeded */
            xfree((ptr_t) s);
            *vl = Strsave(gp);
          }
          break;
      default:
          break;
      }
    vl = nv;

    /*
     * Step 4: expand .. if the variable symlinks==expand is set
     */
    if (symlinks == SYM_EXPAND) {
      for (s = *vl; s; s = *++vl) {
          *vl = dnormalize(s, 1);
          xfree((ptr_t) s);
      }
    }
    vl = nv;

    return (vl);
}

static Char *
handleone(str, vl, action)
    Char   *str, **vl;
    int     action;
{

    Char   **vlp = vl;
    int chars;
    Char **t, *p, *strp;

    switch (action) {
    case G_ERROR:
      setname(short2str(str));
      blkfree(vl);
      stderror(ERR_NAME | ERR_AMBIG);
      break;
    case G_APPEND:
      chars = 0;
      for (t = vlp; (p = *t++) != '\0'; chars++)
          while (*p++)
            chars++;
      str = (Char *)xmalloc((size_t)(chars * sizeof(Char)));
      for (t = vlp, strp = str; (p = *t++) != '\0'; chars++) {
          while (*p)
             *strp++ = *p++ & TRIM;
          *strp++ = ' ';
      }
      *--strp = '\0';
      blkfree(vl);
      break;
    case G_IGNORE:
      str = Strsave(strip(*vlp));
      blkfree(vl);
      break;
    default:
      break;
    }
    return (str);
}

static Char **
libglob(vl)
    Char  **vl;
{
    int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
    glob_t  globv;
    char   *ptr;
    int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;

    if (!vl || !vl[0])
      return(vl);

    globv.gl_offs = 0;
    globv.gl_pathv = 0;
    globv.gl_pathc = 0;

    if (nonomatch)
      gflgs |= GLOB_NOCHECK;

    do {
      ptr = short2qstr(*vl);
      switch (glob(ptr, gflgs, 0, &globv)) {
      case GLOB_ABEND:
          globfree(&globv);
          setname(ptr);
          stderror(ERR_NAME | ERR_GLOB);
          /* NOTREACHED */
      case GLOB_NOSPACE:
          globfree(&globv);
          stderror(ERR_NOMEM);
          /* NOTREACHED */
      default:
          break;
      }
      if (globv.gl_flags & GLOB_MAGCHAR) {
          match |= (globv.gl_matchc != 0);
          magic = 1;
      }
      gflgs |= GLOB_APPEND;
    }
    while (*++vl);
    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 
      NULL : blk2short(globv.gl_pathv);
    globfree(&globv);
    return (vl);
}

Char   *
globone(str, action)
    Char   *str;
    int     action;
{

    Char   *v[2], **vl, **vo;
    int gflg;

    noglob = adrof(STRnoglob) != 0;
    gflag = 0;
    v[0] = str;
    v[1] = 0;
    tglob(v);
    gflg = gflag;
    if (gflg == G_NONE)
      return (strip(Strsave(str)));

    if (gflg & G_CSH) {
      /*
       * Expand back-quote, tilde and brace
       */
      vo = globexpand(v);
      if (noglob || (gflg & G_GLOB) == 0) {
          if (vo[0] == NULL) {
            xfree((ptr_t) vo);
            return (Strsave(STRNULL));
          }
          if (vo[1] != NULL) 
            return (handleone(str, vo, action));
          else {
            str = strip(vo[0]);
            xfree((ptr_t) vo);
            return (str);
          }
      }
    }
    else if (noglob || (gflg & G_GLOB) == 0)
      return (strip(Strsave(str)));
    else
      vo = v;

    vl = libglob(vo);
    if ((gflg & G_CSH) && vl != vo)
      blkfree(vo);
    if (vl == NULL) {
      setname(short2str(str));
      stderror(ERR_NAME | ERR_NOMATCH);
    }
    if (vl[0] == NULL) {
      xfree((ptr_t) vl);
      return (Strsave(STRNULL));
    }
    if (vl[1]) 
      return (handleone(str, vl, action));
    else {
      str = strip(*vl);
      xfree((ptr_t) vl);
      return (str);
    }
}

Char  **
globall(v)
    Char  **v;
{
    Char  **vl, **vo;
    int gflg = gflag;

    if (!v || !v[0]) {
      gargv = saveblk(v);
      gargc = blklen(gargv);
      return (gargv);
    }

    noglob = adrof(STRnoglob) != 0;

    if (gflg & G_CSH)
      /*
       * Expand back-quote, tilde and brace
       */
      vl = vo = globexpand(v);
    else
      vl = vo = saveblk(v);

    if (!noglob && (gflg & G_GLOB)) {
      vl = libglob(vo);
      if (vl != vo)
          blkfree(vo);
    }
    else
      trim(vl);

    gargc = vl ? blklen(vl) : 0;
    return (gargv = vl);
}

void
ginit()
{
    gargsiz = GLOBSPACE;
    gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz));
    gargv[0] = 0;
    gargc = 0;
}

void
rscan(t, f)
    Char **t;
    void    (*f) __P((Char));
{
    Char *p;

    while ((p = *t++) != '\0')
      while (*p)
          (*f) (*p++);
}

void
trim(t)
    Char **t;
{
    Char *p;

    while ((p = *t++) != '\0')
      while (*p)
          *p++ &= TRIM;
}

void
tglob(t)
    Char **t;
{
    Char *p, *c;

    while ((p = *t++) != '\0') {
      if (*p == '~' || *p == '=')
          gflag |= G_CSH;
      else if (*p == '{' &&
             (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
          continue;
      /*
       * The following line used to be *(c = p++), but hp broke their
       * optimizer in 9.01, so we break the assignment into two pieces
       * The careful reader here will note that *most* compiler workarounds
       * in tcsh are either for apollo/DomainOS or hpux. Is it a coincidence?
       */
      while ( *(c = p) != '\0') {
          p++;
          if (*c == '`') {
            gflag |= G_CSH;
#ifdef notdef
            /*
             * We do want to expand echo `echo '*'`, so we don't\
             * use this piece of code anymore.
             */
            while (*p && *p != '`') 
                if (*p++ == '\\') {
                  if (*p)           /* Quoted chars */
                      p++;
                  else
                      break;
                }
            if (*p)                 /* The matching ` */
                p++;
            else
                break;
#endif
          }
          else if (*c == '{')
            gflag |= G_CSH;
          else if (isglob(*c))
            gflag |= G_GLOB;
          else if (symlinks == SYM_EXPAND && 
            *p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') )
            gflag |= G_CSH;
      }
    }
}

/*
 * Command substitute cp.  If literal, then this is a substitution from a
 * << redirection, and so we should not crunch blanks and tabs, separating
 * words only at newlines.
 */
Char  **
dobackp(cp, literal)
    Char   *cp;
    int    literal;
{
    Char *lp, *rp;
    Char   *ep, word[LONGBSIZE];

    if (pargv) {
#ifdef notdef
      abort();
#endif
      blkfree(pargv);
    }
    pargsiz = GLOBSPACE;
    pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz));
    pargv[0] = NULL;
    pargcp = pargs = word;
    pargc = 0;
    pnleft = LONGBSIZE - 4;
    for (;;) {
      for (lp = cp; *lp != '`'; lp++) {
          if (*lp == 0) {
            if (pargcp != pargs)
                pword(LONGBSIZE);
            return (pargv);
          }
          psave(*lp);
      }
      lp++;
      for (rp = lp; *rp && *rp != '`'; rp++)
          if (*rp == '\\') {
            rp++;
            if (!*rp)
                goto oops;
          }
      if (!*rp)
    oops:  stderror(ERR_UNMATCHED, '`');
      ep = Strsave(lp);
      ep[rp - lp] = 0;
      backeval(ep, literal);
      cp = rp + 1;
    }
}


static void
backeval(cp, literal)
    Char   *cp;
    int    literal;
{
    int icnt;
    Char c, *ip;
    struct command faket;
    int    hadnl;
    int     pvec[2], quoted;
    Char   *fakecom[2], ibuf[BUFSIZE];
    char    tibuf[BUFSIZE];

    hadnl = 0;
    icnt = 0;
    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
    faket.t_dtyp = NODE_COMMAND;
    faket.t_dflg = F_BACKQ;
    faket.t_dlef = 0;
    faket.t_drit = 0;
    faket.t_dspr = 0;
    faket.t_dcom = fakecom;
    fakecom[0] = STRfakecom1;
    fakecom[1] = 0;

    /*
     * We do the psave job to temporarily change the current job so that the
     * following fork is considered a separate job.  This is so that when
     * backquotes are used in a builtin function that calls glob the "current
     * job" is not corrupted.  We only need one level of pushed jobs as long as
     * we are sure to fork here.
     */
    psavejob();

    /*
     * It would be nicer if we could integrate this redirection more with the
     * routines in sh.sem.c by doing a fake execute on a builtin function that
     * was piped out.
     */
    mypipe(pvec);
    if (pfork(&faket, -1) == 0) {
      jmp_buf_t osetexit;
      struct command *volatile t;

      (void) close(pvec[0]);
      (void) dmove(pvec[1], 1);
      (void) dmove(SHDIAG,  2);
      initdesc();
      closem();
      /*
       * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
       * posted to comp.bugs.4bsd 12 Sep. 1989.
       */
      if (pargv)        /* mg, 21.dec.88 */
          blkfree(pargv), pargv = 0, pargsiz = 0;
      /* mg, 21.dec.88 */
      arginp = cp;
      for (arginp = cp; *cp; cp++) {
          *cp &= TRIM;
          if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
            *cp = ' ';
      }

        /*
       * In the child ``forget'' everything about current aliases or
       * eval vectors.
       */
      alvec = NULL;
      evalvec = NULL;
      alvecp = NULL;
      evalp = NULL;

      t = NULL;
      getexit(osetexit);
      for (;;) {

          if (paraml.next && paraml.next != &paraml)
            freelex(&paraml);
          
          paraml.next = paraml.prev = &paraml;
          paraml.word = STRNULL;
          (void) setexit();
          justpr = 0;
          
          /*
           * For the sake of reset()
           */
          freelex(&paraml);
          if (t)
            freesyn(t), t = NULL;

          if (haderr) {
            /* unwind */
            doneinp = 0;
            resexit(osetexit);
            reset();
          }
          if (seterr) {
            xfree((ptr_t) seterr);
            seterr = NULL;
          }

          (void) lex(&paraml);
          if (seterr)
            stderror(ERR_OLD);
          alias(&paraml);
          t = syntax(paraml.next, &paraml, 0);
          if (seterr)
            stderror(ERR_OLD);
#ifdef SIGTSTP
          (void) sigignore(SIGTSTP);
#endif
#ifdef SIGTTIN
          (void) sigignore(SIGTTIN);
#endif
#ifdef SIGTTOU
          (void) sigignore(SIGTTOU);
#endif
          execute(t, -1, NULL, NULL, TRUE);

          freelex(&paraml);
          freesyn(t), t = NULL;
      }
    }
    xfree((ptr_t) cp);
    (void) close(pvec[1]);
    c = 0;
    ip = NULL;
    do {
      int     cnt = 0;
      char   *tmp;

      tmp = tibuf;
      for (;;) {
          while (icnt == 0) {
            int     i, eof;

            ip = ibuf;
            do
                icnt = read(pvec[0], tmp, tibuf + BUFSIZE - tmp);
            while (icnt == -1 && errno == EINTR);
            eof = 0;
            if (icnt <= 0) {
                if (tmp == tibuf)
                  goto eof;
                icnt = 0;
                eof = 1;
            }
            icnt += tmp - tibuf;
            i = 0;
            tmp = tibuf;
            while (tmp < tibuf + icnt) {
                int len;

                len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp);
                if (len == -1) {
                    reset_mbtowc();
                    if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) {
                      break; /* Maybe a partial character */
                  }
                  ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */
                }
                if (len <= 0)
                    len = 1;
                i++;
                tmp += len;
            }
            if (tmp != tibuf)
                memmove (tibuf, tmp, tibuf + icnt - tmp);
            tmp = tibuf + (tibuf + icnt - tmp);
            icnt = i;
          }
          if (hadnl)
            break;
          --icnt;
          c = (*ip++ & TRIM);
          if (c == 0)
            break;
#ifdef WINNT_NATIVE
          if (c == '\r')
            c = ' ';
#endif /* WINNT_NATIVE */
          if (c == '\n') {
            /*
             * Continue around the loop one more time, so that we can eat
             * the last newline without terminating this word.
             */
            hadnl = 1;
            continue;
          }
          if (!quoted && (c == ' ' || c == '\t'))
            break;
          cnt++;
          psave(c | quoted);
      }
      /*
       * Unless at end-of-file, we will form a new word here if there were
       * characters in the word, or in any case when we take text literally.
       * If we didn't make empty words here when literal was set then we
       * would lose blank lines.
       */
      if (c != 0 && (cnt || literal))
          pword(BUFSIZE);
      hadnl = 0;
    } while (c > 0);
 eof:
    (void) close(pvec[0]);
    pwait();
    prestjob();
}

static void
psave(c)
    Char   c;
{
    if (--pnleft <= 0)
      stderror(ERR_WTOOLONG);
    *pargcp++ = (Char) c;
}

static void
pword(bufsiz)
    int    bufsiz;
{
    psave(0);
    if (pargc == pargsiz - 1) {
      pargsiz += GLOBSPACE;
      pargv = (Char **) xrealloc((ptr_t) pargv,
                           (size_t) (pargsiz * sizeof(Char *)));
    }
    NLSQuote(pargs);
    pargv[pargc++] = Strsave(pargs);
    pargv[pargc] = NULL;
    pargcp = pargs;
    pnleft = bufsiz - 4;
}

int
Gmatch(string, pattern)
    Char *string, *pattern;
{
    return Gnmatch(string, pattern, NULL);
}

int 
Gnmatch(string, pattern, endstr)
    Char *string, *pattern, **endstr;
{
    Char **blk, **p, *tstring = string;
    int        gpol = 1, gres = 0;

    if (*pattern == '^') {
      gpol = 0;
      pattern++;
    }

    blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *)));
    blk[0] = Strsave(pattern);
    blk[1] = NULL;

    expbrace(&blk, NULL, GLOBSPACE);

    if (endstr == NULL)
      /* Exact matches only */
      for (p = blk; *p; p++) 
          gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
    else {
      /* partial matches */
      int minc = 0x7fffffff;
      for (p = blk; *p; p++) 
          if (t_pmatch(string, *p, &tstring, 1) != 0) {
            int t = (int) (tstring - string);
            gres |= 1;
            if (minc == -1 || minc > t)
                minc = t;
          }
      *endstr = string + minc;
    }

    blkfree(blk);
    return(gres == gpol);
} 

/* t_pmatch():
 *    Return 2 on exact match,      
 *    Return 1 on substring match.
 *    Return 0 on no match.
 *    *estr will point to the end of the longest exact or substring match.
 */
int
t_pmatch(string, pattern, estr, cs)
    Char *string, *pattern, **estr;
    int cs;
{
    NLSChar stringc, patternc, rangec;
    int     match, negate_range;
    Char    *oestr, *pestr, *nstring;

    for (nstring = string;; string = nstring) {
      stringc = *nstring++;
      TRIM_AND_EXTEND(nstring, stringc);
      /*
       * apollo compiler bug: switch (patternc = *pattern++) dies
       */
      patternc = *pattern++;
      TRIM_AND_EXTEND(pattern, patternc);
      switch (patternc) {
      case '\0':
          *estr = string;
          return (stringc == '\0' ? 2 : 1);
      case '?':
          if (stringc == 0)
            return (0);
          *estr = string;
          break;
      case '*':
          if (!*pattern) {
            while (*string) string++;
            *estr = string;
            return (2);
          }
          oestr = *estr;
          pestr = NULL;

          for (;;) {
            switch(t_pmatch(string, pattern, estr, cs)) {
            case 0:
                break;
            case 1:
                pestr = *estr;
                break;
            case 2:
                return 2;
            default:
                abort();      /* Cannot happen */
            }
            *estr = string;
            stringc = *string++;
            if (!stringc)
                break;
            TRIM_AND_EXTEND(string, stringc);
          }

          if (pestr) {
            *estr = pestr;
            return 1;
          }
          else {
            *estr = oestr;
            return 0;
          }

      case '[':
          match = 0;
          if ((negate_range = (*pattern == '^')) != 0)
            pattern++;
          while ((rangec = *pattern++) != '\0') {
            if (rangec == ']')
                break;
            if (match)
                continue;
            TRIM_AND_EXTEND(pattern, rangec);
            if (*pattern == '-' && pattern[1] != ']') {
                NLSChar rangec2;
                pattern++;
                rangec2 = *pattern++;
                TRIM_AND_EXTEND(pattern, rangec2);
                match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
                  globcharcoll(rangec, stringc, 0) <= 0);
            }
            else 
                match = (stringc == rangec);
          }
          if (rangec == '\0')
            stderror(ERR_NAME | ERR_MISSING, ']');
          if ((!match) && (stringc == '\0'))
            return (0);
          if (match == negate_range)
            return (0);
          *estr = string;
          break;
      default:
          TRIM_AND_EXTEND(pattern, patternc);
          if (cs ? patternc  != stringc
#if defined (NLS) && defined (SHORT_STRINGS)
            : towlower(patternc) != towlower(stringc))
#else
            : Tolower(patternc) != Tolower(stringc))
#endif
            return (0);
          *estr = string;
          break;
      }
    }
}

void
Gcat(s1, s2)
    Char   *s1, *s2;
{
    Char *p, *q;
    int     n;

    for (p = s1; *p++;)
      continue;
    for (q = s2; *q++;)
      continue;
    n = (int) ((p - s1) + (q - s2) - 1);
    if (++gargc >= gargsiz) {
      gargsiz += GLOBSPACE;
      gargv = (Char **) xrealloc((ptr_t) gargv,
                           (size_t) (gargsiz * sizeof(Char *)));
    }
    gargv[gargc] = 0;
    p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char)));
    for (q = s1; (*p++ = *q++) != '\0';)
      continue;
    for (p--, q = s2; (*p++ = *q++) != '\0';)
      continue;
}

#if defined(FILEC) && defined(TIOCSTI)
int
sortscmp(a, b)
    Char **a, **b;
{
    if (!a)             /* check for NULL */
      return (b ? 1 : 0);
    if (!b)
      return (-1);

    if (!*a)                  /* check for NULL */
      return (*b ? 1 : 0);
    if (!*b)
      return (-1);

    return (int) collate(*a, *b);
}

#endif

Generated by  Doxygen 1.6.0   Back to index