Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/expand.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1982-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* David Korn <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* File name expansion
23
*
24
* David Korn
25
* AT&T Labs
26
*
27
*/
28
29
#if KSHELL
30
# include "defs.h"
31
# include "variables.h"
32
# include "test.h"
33
#else
34
# include <ast.h>
35
# include <ctype.h>
36
# include <setjmp.h>
37
#endif /* KSHELL */
38
#include <glob.h>
39
#include <ls.h>
40
#include <stak.h>
41
#include <ast_dir.h>
42
#include "io.h"
43
#include "path.h"
44
45
#if !SHOPT_BRACEPAT
46
# define SHOPT_BRACEPAT 0
47
#endif
48
49
#if KSHELL
50
# define argbegin argnxt.cp
51
static const char *sufstr;
52
static int suflen;
53
static int scantree(Dt_t*,const char*, struct argnod**);
54
#else
55
# define sh_sigcheck(sig) (0)
56
# define sh_access access
57
# define suflen 0
58
#endif /* KSHELL */
59
60
61
/*
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
65
*
66
*/
67
68
#ifndef GLOB_AUGMENTED
69
# define GLOB_AUGMENTED 0
70
#endif
71
72
#define GLOB_RESCAN 1
73
#define globptr() ((struct glob*)membase)
74
75
static struct glob *membase;
76
77
#if GLOB_VERSION >= 20010916L
78
static char *nextdir(glob_t *gp, char *dir)
79
{
80
Shell_t *shp = sh_getinterp();
81
Pathcomp_t *pp = (Pathcomp_t*)gp->gl_handle;
82
if(!dir)
83
pp = path_get(shp,"");
84
else
85
pp = pp->next;
86
gp->gl_handle = (void*)pp;
87
if(pp)
88
return(pp->name);
89
return(0);
90
}
91
#endif
92
93
int path_expand(Shell_t *shp,const char *pattern, struct argnod **arghead)
94
{
95
glob_t gdata;
96
register struct argnod *ap;
97
register glob_t *gp= &gdata;
98
register int flags,extra=0;
99
#if SHOPT_BASH
100
register int off;
101
register char *sp, *cp, *cp2;
102
#endif
103
sh_stats(STAT_GLOBS);
104
memset(gp,0,sizeof(gdata));
105
flags = GLOB_GROUP|GLOB_AUGMENTED|GLOB_NOCHECK|GLOB_NOSORT|GLOB_STACK|GLOB_LIST|GLOB_DISC;
106
if(sh_isoption(SH_MARKDIRS))
107
flags |= GLOB_MARK;
108
if(sh_isoption(SH_GLOBSTARS))
109
flags |= GLOB_STARSTAR;
110
#if SHOPT_BASH
111
#if 0
112
if(sh_isoption(SH_BASH) && !sh_isoption(SH_EXTGLOB))
113
flags &= ~GLOB_AUGMENTED;
114
#endif
115
if(sh_isoption(SH_NULLGLOB))
116
flags &= ~GLOB_NOCHECK;
117
if(sh_isoption(SH_NOCASEGLOB))
118
flags |= GLOB_ICASE;
119
#endif
120
if(sh_isstate(SH_COMPLETE))
121
{
122
#if KSHELL
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;
127
# endif
128
#endif /* KSHELL */
129
flags |= GLOB_COMPLETE;
130
flags &= ~GLOB_NOCHECK;
131
}
132
#if SHOPT_BASH
133
if(off = staktell())
134
sp = stakfreeze(0);
135
if(sh_isoption(SH_BASH))
136
{
137
/*
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.
143
*/
144
if(sh_isstate(SH_FCOMPLETE))
145
cp=nv_getval(sh_scoped(shp,FIGNORENOD));
146
else
147
{
148
static Namval_t *GLOBIGNORENOD;
149
if(!GLOBIGNORENOD)
150
GLOBIGNORENOD = nv_open("GLOBIGNORE",shp->var_tree,0);
151
cp=nv_getval(sh_scoped(shp,GLOBIGNORENOD));
152
}
153
if(cp)
154
{
155
flags |= GLOB_AUGMENTED;
156
stakputs("@(");
157
if(!sh_isstate(SH_FCOMPLETE))
158
{
159
stakputs(cp);
160
for(cp=stakptr(off); *cp; cp++)
161
if(*cp == ':')
162
*cp='|';
163
}
164
else
165
{
166
cp2 = strtok(cp, ":");
167
if(!cp2)
168
cp2=cp;
169
do
170
{
171
stakputc('*');
172
stakputs(cp2);
173
if(cp2 = strtok(NULL, ":"))
174
{
175
*(cp2-1)=':';
176
stakputc('|');
177
}
178
} while(cp2);
179
}
180
stakputc(')');
181
gp->gl_fignore = stakfreeze(1);
182
}
183
else if(!sh_isstate(SH_FCOMPLETE) && sh_isoption(SH_DOTGLOB))
184
gp->gl_fignore = "";
185
}
186
else
187
#endif
188
gp->gl_fignore = nv_getval(sh_scoped(shp,FIGNORENOD));
189
if(suflen)
190
gp->gl_suffix = sufstr;
191
gp->gl_intr = &shp->trapnote;
192
suflen = 0;
193
if(memcmp(pattern,"~(N",3)==0)
194
flags &= ~GLOB_NOCHECK;
195
glob(pattern, flags, 0, gp);
196
#if SHOPT_BASH
197
if(off)
198
stakset(sp,off);
199
else
200
stakseek(0);
201
#endif
202
sh_sigcheck(shp);
203
for(ap= (struct argnod*)gp->gl_list; ap; ap = ap->argnxt.ap)
204
{
205
ap->argchn.ap = ap->argnxt.ap;
206
if(!ap->argnxt.ap)
207
ap->argchn.ap = *arghead;
208
}
209
if(gp->gl_list)
210
*arghead = (struct argnod*)gp->gl_list;
211
return(gp->gl_pathc+extra);
212
}
213
214
#if KSHELL
215
216
/*
217
* scan tree and add each name that matches the given pattern
218
*/
219
static int scantree(Dt_t *tree, const char *pattern, struct argnod **arghead)
220
{
221
register Namval_t *np;
222
register struct argnod *ap;
223
register int nmatch=0;
224
register char *cp;
225
np = (Namval_t*)dtfirst(tree);
226
for(;np && !nv_isnull(np);(np = (Namval_t*)dtnext(tree,np)))
227
{
228
if(strmatch(cp=nv_name(np),pattern))
229
{
230
ap = (struct argnod*)stakseek(ARGVAL);
231
stakputs(cp);
232
ap = (struct argnod*)stakfreeze(1);
233
ap->argbegin = NIL(char*);
234
ap->argchn.ap = *arghead;
235
ap->argflag = ARG_RAW|ARG_MAKE;
236
*arghead = ap;
237
nmatch++;
238
}
239
}
240
return(nmatch);
241
}
242
243
/*
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
247
*/
248
249
int path_complete(Shell_t *shp,const char *name,register const char *suffix, struct argnod **arghead)
250
{
251
sufstr = suffix;
252
suflen = strlen(suffix);
253
return(path_expand(shp,name,arghead));
254
}
255
256
#endif
257
258
#if SHOPT_BRACEPAT
259
260
static int checkfmt(Sfio_t* sp, void* vp, Sffmt_t* fp)
261
{
262
return -1;
263
}
264
265
int path_generate(Shell_t *shp,struct argnod *todo, struct argnod **arghead)
266
/*@
267
assume todo!=0;
268
return count satisfying count>=1;
269
@*/
270
{
271
register char *cp;
272
register int brace;
273
register struct argnod *ap;
274
struct argnod *top = 0;
275
struct argnod *apin;
276
char *pat, *rescan;
277
char *format;
278
char comma, range=0;
279
int first, last, incr, count = 0;
280
char tmp[32], end[1];
281
todo->argchn.ap = 0;
282
again:
283
apin = ap = todo;
284
todo = ap->argchn.ap;
285
cp = ap->argval;
286
range = comma = brace = 0;
287
/* first search for {...,...} */
288
while(1) switch(*cp++)
289
{
290
case '{':
291
if(brace++==0)
292
pat = cp;
293
break;
294
case '}':
295
if(--brace>0)
296
break;
297
if(brace==0 && comma && *cp!='(')
298
goto endloop1;
299
comma = brace = 0;
300
break;
301
case '.':
302
if(brace==1 && *cp=='.')
303
{
304
char *endc;
305
incr = 1;
306
if(isdigit(*pat) || *pat=='+' || *pat=='-')
307
{
308
first = strtol(pat,&endc,0);
309
if(endc==(cp-1))
310
{
311
last = strtol(cp+1,&endc,0);
312
if(*endc=='.' && endc[1]=='.')
313
incr = strtol(endc+2,&endc,0);
314
else if(last<first)
315
incr = -1;
316
if(incr)
317
{
318
if(*endc=='%')
319
{
320
Sffmt_t fmt;
321
memset(&fmt, 0, sizeof(fmt));
322
fmt.version = SFIO_VERSION;
323
fmt.form = endc;
324
fmt.extf = checkfmt;
325
sfprintf(sfstdout, "%!", &fmt);
326
if(!(fmt.flags&(SFFMT_LLONG|SFFMT_LDOUBLE)))
327
switch (fmt.fmt)
328
{
329
case 'c':
330
case 'd':
331
case 'i':
332
case 'o':
333
case 'u':
334
case 'x':
335
case 'X':
336
format = endc;
337
endc = fmt.form;
338
break;
339
}
340
}
341
else
342
format = "%d";
343
if(*endc=='}')
344
{
345
cp = endc+1;
346
range = 2;
347
goto endloop1;
348
}
349
}
350
}
351
}
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')))
353
{
354
first = *pat;
355
last = cp[1];
356
cp += 2;
357
if(*cp=='.')
358
{
359
incr = strtol(cp+2,&endc,0);
360
cp = endc;
361
}
362
else if(first>last)
363
incr = -1;
364
if(incr && *cp=='}')
365
{
366
cp++;
367
range = 1;
368
goto endloop1;
369
}
370
}
371
cp++;
372
}
373
break;
374
case ',':
375
if(brace==1)
376
comma = 1;
377
break;
378
case '\\':
379
cp++;
380
break;
381
case 0:
382
/* insert on stack */
383
ap->argchn.ap = top;
384
top = ap;
385
if(todo)
386
goto again;
387
for(; ap; ap=apin)
388
{
389
apin = ap->argchn.ap;
390
if(!sh_isoption(SH_NOGLOB))
391
brace=path_expand(shp,ap->argval,arghead);
392
else
393
{
394
ap->argchn.ap = *arghead;
395
*arghead = ap;
396
brace=1;
397
}
398
if(brace)
399
{
400
count += brace;
401
(*arghead)->argflag |= ARG_MAKE;
402
}
403
}
404
return(count);
405
}
406
endloop1:
407
rescan = cp;
408
cp = pat-1;
409
*cp = 0;
410
while(1)
411
{
412
brace = 0;
413
if(range)
414
{
415
if(range==1)
416
{
417
pat[0] = first;
418
cp = &pat[1];
419
}
420
else
421
{
422
*(rescan - 1) = 0;
423
sfsprintf(pat=tmp,sizeof(tmp),format,first);
424
*(rescan - 1) = '}';
425
*(cp = end) = 0;
426
}
427
if(incr*(first+incr) > last*incr)
428
*cp = '}';
429
else
430
first += incr;
431
}
432
/* generate each pattern and put on the todo list */
433
else while(1) switch(*++cp)
434
{
435
case '\\':
436
cp++;
437
break;
438
case '{':
439
brace++;
440
break;
441
case ',':
442
if(brace==0)
443
goto endloop2;
444
break;
445
case '}':
446
if(--brace<0)
447
goto endloop2;
448
}
449
endloop2:
450
brace = *cp;
451
*cp = 0;
452
sh_sigcheck(shp);
453
ap = (struct argnod*)stakseek(ARGVAL);
454
ap->argflag = ARG_RAW;
455
ap->argchn.ap = todo;
456
stakputs(apin->argval);
457
stakputs(pat);
458
stakputs(rescan);
459
todo = ap = (struct argnod*)stakfreeze(1);
460
if(brace == '}')
461
break;
462
if(!range)
463
pat = cp+1;
464
}
465
goto again;
466
}
467
468
#endif /* SHOPT_BRACEPAT */
469
470