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

expand.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1982-2009 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                  David Korn <dgk@research.att.com>                   *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 *    File name expansion
 *
 *    David Korn
 *    AT&T Labs
 *
 */

#if KSHELL
#   include "defs.h"
#   include "variables.h"
#   include "test.h"
#else
#   include <ast.h>
#   include <ctype.h>
#   include <setjmp.h>
#endif /* KSHELL */
#include    <glob.h>
#include    <ls.h>
#include    <stak.h>
#include    <ast_dir.h>
#include    "io.h"
#include    "path.h"

#if !SHOPT_BRACEPAT
#   define SHOPT_BRACEPAT     0
#endif

#if KSHELL
#   define argbegin     argnxt.cp
    static  const char  *sufstr;
    static  int         suflen;
    static int scantree(Dt_t*,const char*, struct argnod**);
#else
#   define sh_sigcheck()      (0)
#   define sh_access          access
#   define suflen       0
#endif /* KSHELL */


/*
 * This routine builds a list of files that match a given pathname
 * Uses external routine strgrpmatch() to match each component
 * A leading . must match explicitly
 *
 */

#ifndef GLOB_AUGMENTED
#   define GLOB_AUGMENTED     0
#endif

#define GLOB_RESCAN 1
#define globptr() ((struct glob*)membase)

static struct glob       *membase;

#if GLOB_VERSION >= 20010916L
static char *nextdir(glob_t *gp, char *dir)
{
      Pathcomp_t *pp = (Pathcomp_t*)gp->gl_handle;
      if(!dir)
            pp = path_get("");
      else
            pp = pp->next;
      gp->gl_handle = (void*)pp;
      if(pp)
            return(pp->name);
      return(0);
}
#endif

int path_expand(const char *pattern, struct argnod **arghead)
{
      Shell_t     *shp = &sh;
      glob_t gdata;
      register struct argnod *ap;
      register glob_t *gp= &gdata;
      register int flags,extra=0;
#if SHOPT_BASH
      register int off;
      register char *sp, *cp, *cp2;
#endif
      sh_stats(STAT_GLOBS);
      memset(gp,0,sizeof(gdata));
      flags = GLOB_AUGMENTED|GLOB_NOCHECK|GLOB_NOSORT|GLOB_STACK|GLOB_LIST|GLOB_DISC;
      if(sh_isoption(SH_MARKDIRS))
            flags |= GLOB_MARK;
      if(sh_isoption(SH_GLOBSTARS))
            flags |= GLOB_STARSTAR;
#if SHOPT_BASH
#if 0
      if(sh_isoption(SH_BASH) && !sh_isoption(SH_EXTGLOB))
            flags &= ~GLOB_AUGMENTED;
#endif
      if(sh_isoption(SH_NULLGLOB))
            flags &= ~GLOB_NOCHECK;
      if(sh_isoption(SH_NOCASEGLOB))
            flags |= GLOB_ICASE;
#endif
      if(sh_isstate(SH_COMPLETE))
      {
#if KSHELL
            extra += scantree(shp->alias_tree,pattern,arghead); 
            extra += scantree(shp->fun_tree,pattern,arghead); 
#   if GLOB_VERSION >= 20010916L
            gp->gl_nextdir = nextdir;
#   endif
#endif /* KSHELL */
            flags |= GLOB_COMPLETE;
            flags &= ~GLOB_NOCHECK;
      }
#if SHOPT_BASH
      if(off = staktell())
            sp = stakfreeze(0);
      if(sh_isoption(SH_BASH))
      {
            /*
             * For bash, FIGNORE is a colon separated list of suffixes to
             * ignore when doing filename/command completion.
             * GLOBIGNORE is similar to ksh FIGNORE, but colon separated
             * instead of being an augmented shell pattern.
             * Generate shell patterns out of those here.
             */
            if(sh_isstate(SH_FCOMPLETE))
                  cp=nv_getval(sh_scoped(shp,FIGNORENOD));
            else
            {
                  static Namval_t *GLOBIGNORENOD;
                  if(!GLOBIGNORENOD)
                        GLOBIGNORENOD = nv_open("GLOBIGNORE",shp->var_tree,0);
                  cp=nv_getval(sh_scoped(shp,GLOBIGNORENOD));
            }
            if(cp)
            {
                  flags |= GLOB_AUGMENTED;
                  stakputs("@(");
                  if(!sh_isstate(SH_FCOMPLETE))
                  {
                        stakputs(cp);
                        for(cp=stakptr(off); *cp; cp++)
                              if(*cp == ':')
                                    *cp='|';
                  }
                  else
                  {
                        cp2 = strtok(cp, ":");
                        if(!cp2)
                              cp2=cp;
                        do
                        {
                              stakputc('*');
                              stakputs(cp2);
                              if(cp2 = strtok(NULL, ":"))
                              {
                                    *(cp2-1)=':';
                                    stakputc('|');
                              }
                        } while(cp2);
                  }
                  stakputc(')');
                  gp->gl_fignore = stakfreeze(1);
            }
            else if(!sh_isstate(SH_FCOMPLETE) && sh_isoption(SH_DOTGLOB))
                  gp->gl_fignore = "";
      }
      else
#endif
      gp->gl_fignore = nv_getval(sh_scoped(shp,FIGNORENOD));
      if(suflen)
            gp->gl_suffix = sufstr;
      gp->gl_intr = &shp->trapnote; 
      suflen = 0;
      if(memcmp(pattern,"~(N",3)==0)
            flags &= ~GLOB_NOCHECK;
      glob(pattern, flags, 0, gp);
#if SHOPT_BASH
      if(off)
            stakset(sp,off);
      else
            stakseek(0);
#endif
      sh_sigcheck();
      for(ap= (struct argnod*)gp->gl_list; ap; ap = ap->argnxt.ap)
      {
            ap->argchn.ap = ap->argnxt.ap;
            if(!ap->argnxt.ap)
                  ap->argchn.ap = *arghead;
      }
      if(gp->gl_list)
            *arghead = (struct argnod*)gp->gl_list;
      return(gp->gl_pathc+extra);
}

#if KSHELL

/*
 * scan tree and add each name that matches the given pattern
 */
static int scantree(Dt_t *tree, const char *pattern, struct argnod **arghead)
{
      register Namval_t *np;
      register struct argnod *ap;
      register int nmatch=0;
      register char *cp;
      np = (Namval_t*)dtfirst(tree);
      for(;np && !nv_isnull(np);(np = (Namval_t*)dtnext(tree,np)))
      {
            if(strmatch(cp=nv_name(np),pattern))
            {
                  ap = (struct argnod*)stakseek(ARGVAL);
                  stakputs(cp);
                  ap = (struct argnod*)stakfreeze(1);
                  ap->argbegin = NIL(char*);
                  ap->argchn.ap = *arghead;
                  ap->argflag = ARG_RAW|ARG_MAKE;
                  *arghead = ap;
                  nmatch++;
            }
      }
      return(nmatch);
}

/*
 * file name completion
 * generate the list of files found by adding an suffix to end of name
 * The number of matches is returned
 */

int path_complete(const char *name,register const char *suffix, struct argnod **arghead)
{
      sufstr = suffix;
      suflen = strlen(suffix);
      return(path_expand(name,arghead));
}

#endif

#if SHOPT_BRACEPAT

static int checkfmt(Sfio_t* sp, void* vp, Sffmt_t* fp)
{
      return -1;
}

int path_generate(struct argnod *todo, struct argnod **arghead)
/*@
      assume todo!=0;
      return count satisfying count>=1;
@*/
{
      register char *cp;
      register int brace;
      register struct argnod *ap;
      struct argnod *top = 0;
      struct argnod *apin;
      char *pat, *rescan;
      char *format;
      char comma, range=0;
      int first, last, incr, count = 0;
      char tmp[32], end[1];
      todo->argchn.ap = 0;
again:
      apin = ap = todo;
      todo = ap->argchn.ap;
      cp = ap->argval;
      range = comma = brace = 0;
      /* first search for {...,...} */
      while(1) switch(*cp++)
      {
            case '{':
                  if(brace++==0)
                        pat = cp;
                  break;
            case '}':
                  if(--brace>0)
                        break;
                  if(brace==0 && comma && *cp!='(')
                        goto endloop1;
                  comma = brace = 0;
                  break;
            case '.':
                  if(brace==1 && *cp=='.')
                  {
                        char *endc;
                        incr = 1;
                        if(isdigit(*pat) || *pat=='+' || *pat=='-')
                        {
                              first = strtol(pat,&endc,0);
                              if(endc==(cp-1))
                              {
                                    last = strtol(cp+1,&endc,0);
                                    if(*endc=='.' && endc[1]=='.')
                                          incr = strtol(endc+2,&endc,0);
                                    else if(last<first)
                                          incr = -1;
                                    if(incr)
                                    {
                                          if(*endc=='%')
                                          {
                                                Sffmt_t     fmt;
                                                memset(&fmt, 0, sizeof(fmt));
                                                fmt.version = SFIO_VERSION;
                                                fmt.form = endc;
                                                fmt.extf = checkfmt;
                                                sfprintf(sfstdout, "%!", &fmt);
                                                if(!(fmt.flags&(SFFMT_LLONG|SFFMT_LDOUBLE)))
                                                      switch (fmt.fmt)
                                                      {
                                                      case 'c':
                                                      case 'd':
                                                      case 'i':
                                                      case 'o':
                                                      case 'u':
                                                      case 'x':
                                                      case 'X':
                                                            format = endc;
                                                            endc = fmt.form;
                                                            break;
                                                      }
                                          }
                                          else
                                                format = "%d";
                                          if(*endc=='}')
                                          {
                                                cp = endc+1;
                                                range = 2;
                                                goto endloop1;
                                          }
                                    }
                              }
                        }
                        else if((cp[2]=='}' || cp[2]=='.' && cp[3]=='.') && ((*pat>='a'  && *pat<='z' && cp[1]>='a' && cp[1]<='z') || (*pat>='A'  && *pat<='Z' && cp[1]>='A' && cp[1]<='Z')))
                        {
                              first = *pat;
                              last = cp[1];
                              cp += 2;
                              if(*cp=='.')
                              {
                                    incr = strtol(cp+2,&endc,0);
                                    cp = endc;
                              }
                              else if(first>last)
                                    incr = -1;
                              if(incr && *cp=='}')
                              {
                                    cp++;
                                    range = 1;
                                    goto endloop1;
                              }
                        }
                        cp++;
                  }
                  break;
            case ',':
                  if(brace==1)
                        comma = 1;
                  break;
            case '\\':
                  cp++;
                  break;
            case 0:
                  /* insert on stack */
                  ap->argchn.ap = top;
                  top = ap;
                  if(todo)
                        goto again;
                  for(; ap; ap=apin)
                  {
                        apin = ap->argchn.ap;
                        if(!sh_isoption(SH_NOGLOB))
                              brace=path_expand(ap->argval,arghead);
                        else
                        {
                              ap->argchn.ap = *arghead;
                              *arghead = ap;
                              brace=1;
                        }
                        if(brace)
                        {
                              count += brace;
                              (*arghead)->argflag |= ARG_MAKE;
                        }
                  }
                  return(count);
      }
endloop1:
      rescan = cp;
      cp = pat-1;
      *cp = 0;
      while(1)
      {
            brace = 0;
            if(range)
            {
                  if(range==1)
                  {
                        pat[0] = first;
                        cp = &pat[1];
                  }
                  else
                  {
                        *(rescan - 1) = 0;
                        sfsprintf(pat=tmp,sizeof(tmp),format,first);
                        *(rescan - 1) = '}';
                        *(cp = end) = 0;
                  }
                  if(incr*(first+incr) > last*incr)
                        *cp = '}';
                  else
                        first += incr;
            }
            /* generate each pattern and put on the todo list */
            else while(1) switch(*++cp)
            {
                  case '\\':
                        cp++;
                        break;
                  case '{':
                        brace++;
                        break;
                  case ',':
                        if(brace==0)
                              goto endloop2;
                        break;
                  case '}':
                        if(--brace<0)
                              goto endloop2;
            }
      endloop2:
            brace = *cp;
            *cp = 0;
            sh_sigcheck();
            ap = (struct argnod*)stakseek(ARGVAL);
            ap->argflag = ARG_RAW;
            ap->argchn.ap = todo;
            stakputs(apin->argval);
            stakputs(pat);
            stakputs(rescan);
            todo = ap = (struct argnod*)stakfreeze(1);
            if(brace == '}')
                  break;
            if(!range)
                  pat = cp+1;
      }
      goto again;
}

#endif /* SHOPT_BRACEPAT */

Generated by  Doxygen 1.6.0   Back to index