1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
31 # include "variables.h"
46 # define SHOPT_BRACEPAT 0
50 # define argbegin argnxt.cp
51 static const char *sufstr
;
53 static int scantree(Dt_t
*,const char*, struct argnod
**);
55 # define sh_sigcheck() (0)
56 # define sh_access access
62 * This routine builds a list of files that match a given pathname
63 * Uses external routine strgrpmatch() to match each component
64 * A leading . must match explicitly
68 #ifndef GLOB_AUGMENTED
69 # define GLOB_AUGMENTED 0
73 #define globptr() ((struct glob*)membase)
75 static struct glob
*membase
;
77 #if GLOB_VERSION >= 20010916L
78 static char *nextdir(glob_t
*gp
, char *dir
)
80 Pathcomp_t
*pp
= (Pathcomp_t
*)gp
->gl_handle
;
85 gp
->gl_handle
= (void*)pp
;
92 int path_expand(const char *pattern
, struct argnod
**arghead
)
96 register struct argnod
*ap
;
97 register glob_t
*gp
= &gdata
;
98 register int flags
,extra
=0;
101 register char *sp
, *cp
, *cp2
;
103 sh_stats(STAT_GLOBS
);
104 memset(gp
,0,sizeof(gdata
));
105 flags
= GLOB_AUGMENTED
|GLOB_NOCHECK
|GLOB_NOSORT
|GLOB_STACK
|GLOB_LIST
|GLOB_DISC
;
106 if(sh_isoption(SH_MARKDIRS
))
108 if(sh_isoption(SH_GLOBSTARS
))
109 flags
|= GLOB_STARSTAR
;
112 if(sh_isoption(SH_BASH
) && !sh_isoption(SH_EXTGLOB
))
113 flags
&= ~GLOB_AUGMENTED
;
115 if(sh_isoption(SH_NULLGLOB
))
116 flags
&= ~GLOB_NOCHECK
;
117 if(sh_isoption(SH_NOCASEGLOB
))
120 if(sh_isstate(SH_COMPLETE
))
123 extra
+= scantree(shp
->alias_tree
,pattern
,arghead
);
124 extra
+= scantree(shp
->fun_tree
,pattern
,arghead
);
125 # if GLOB_VERSION >= 20010916L
126 gp
->gl_nextdir
= nextdir
;
129 flags
|= GLOB_COMPLETE
;
130 flags
&= ~GLOB_NOCHECK
;
135 if(sh_isoption(SH_BASH
))
138 * For bash, FIGNORE is a colon separated list of suffixes to
139 * ignore when doing filename/command completion.
140 * GLOBIGNORE is similar to ksh FIGNORE, but colon separated
141 * instead of being an augmented shell pattern.
142 * Generate shell patterns out of those here.
144 if(sh_isstate(SH_FCOMPLETE
))
145 cp
=nv_getval(sh_scoped(shp
,FIGNORENOD
));
148 static Namval_t
*GLOBIGNORENOD
;
150 GLOBIGNORENOD
= nv_open("GLOBIGNORE",shp
->var_tree
,0);
151 cp
=nv_getval(sh_scoped(shp
,GLOBIGNORENOD
));
155 flags
|= GLOB_AUGMENTED
;
157 if(!sh_isstate(SH_FCOMPLETE
))
160 for(cp
=stakptr(off
); *cp
; cp
++)
166 cp2
= strtok(cp
, ":");
173 if(cp2
= strtok(NULL
, ":"))
181 gp
->gl_fignore
= stakfreeze(1);
183 else if(!sh_isstate(SH_FCOMPLETE
) && sh_isoption(SH_DOTGLOB
))
188 gp
->gl_fignore
= nv_getval(sh_scoped(shp
,FIGNORENOD
));
190 gp
->gl_suffix
= sufstr
;
191 gp
->gl_intr
= &shp
->trapnote
;
193 if(memcmp(pattern
,"~(N",3)==0)
194 flags
&= ~GLOB_NOCHECK
;
195 glob(pattern
, flags
, 0, gp
);
203 for(ap
= (struct argnod
*)gp
->gl_list
; ap
; ap
= ap
->argnxt
.ap
)
205 ap
->argchn
.ap
= ap
->argnxt
.ap
;
207 ap
->argchn
.ap
= *arghead
;
210 *arghead
= (struct argnod
*)gp
->gl_list
;
211 return(gp
->gl_pathc
+extra
);
217 * scan tree and add each name that matches the given pattern
219 static int scantree(Dt_t
*tree
, const char *pattern
, struct argnod
**arghead
)
221 register Namval_t
*np
;
222 register struct argnod
*ap
;
223 register int nmatch
=0;
225 np
= (Namval_t
*)dtfirst(tree
);
226 for(;np
&& !nv_isnull(np
);(np
= (Namval_t
*)dtnext(tree
,np
)))
228 if(strmatch(cp
=nv_name(np
),pattern
))
230 ap
= (struct argnod
*)stakseek(ARGVAL
);
232 ap
= (struct argnod
*)stakfreeze(1);
233 ap
->argbegin
= NIL(char*);
234 ap
->argchn
.ap
= *arghead
;
235 ap
->argflag
= ARG_RAW
|ARG_MAKE
;
244 * file name completion
245 * generate the list of files found by adding an suffix to end of name
246 * The number of matches is returned
249 int path_complete(const char *name
,register const char *suffix
, struct argnod
**arghead
)
252 suflen
= strlen(suffix
);
253 return(path_expand(name
,arghead
));
260 static int checkfmt(Sfio_t
* sp
, void* vp
, Sffmt_t
* fp
)
265 int path_generate(struct argnod
*todo
, struct argnod
**arghead
)
268 return count satisfying count>=1;
273 register struct argnod
*ap
;
274 struct argnod
*top
= 0;
279 int first
, last
, incr
, count
= 0;
280 char tmp
[32], end
[1];
284 todo
= ap
->argchn
.ap
;
286 range
= comma
= brace
= 0;
287 /* first search for {...,...} */
288 while(1) switch(*cp
++)
297 if(brace
==0 && comma
&& *cp
!='(')
302 if(brace
==1 && *cp
=='.')
306 if(isdigit(*pat
) || *pat
=='+' || *pat
=='-')
308 first
= strtol(pat
,&endc
,0);
311 last
= strtol(cp
+1,&endc
,0);
312 if(*endc
=='.' && endc
[1]=='.')
313 incr
= strtol(endc
+2,&endc
,0);
321 memset(&fmt
, 0, sizeof(fmt
));
322 fmt
.version
= SFIO_VERSION
;
325 sfprintf(sfstdout
, "%!", &fmt
);
326 if(!(fmt
.flags
&(SFFMT_LLONG
|SFFMT_LDOUBLE
)))
352 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')))
359 incr
= strtol(cp
+2,&endc
,0);
382 /* insert on stack */
389 apin
= ap
->argchn
.ap
;
390 if(!sh_isoption(SH_NOGLOB
))
391 brace
=path_expand(ap
->argval
,arghead
);
394 ap
->argchn
.ap
= *arghead
;
401 (*arghead
)->argflag
|= ARG_MAKE
;
423 sfsprintf(pat
=tmp
,sizeof(tmp
),format
,first
);
427 if(incr
*(first
+incr
) > last
*incr
)
432 /* generate each pattern and put on the todo list */
433 else while(1) switch(*++cp
)
453 ap
= (struct argnod
*)stakseek(ARGVAL
);
454 ap
->argflag
= ARG_RAW
;
455 ap
->argchn
.ap
= todo
;
456 stakputs(apin
->argval
);
459 todo
= ap
= (struct argnod
*)stakfreeze(1);
468 #endif /* SHOPT_BRACEPAT */