2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1997-2005
5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 #include <sys/types.h>
59 * Routines to expand arguments to commands. We have to deal with
60 * backquotes, shell variables, and file metacharacters.
83 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
84 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
85 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
86 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
88 /* Add CTLESC when necessary. */
89 #define QUOTES_ESC (EXP_FULL | EXP_CASE)
92 * Structure specifying which parts of the string should be searched
97 struct ifsregion
*next
; /* next region in list */
98 int begoff
; /* offset of start of region */
99 int endoff
; /* offset of end of region */
100 int nulonly
; /* search for nul bytes only */
103 /* output of current string */
104 static char *expdest
;
105 /* list of back quote expressions */
106 static struct nodelist
*argbackq
;
107 /* first struct in list of ifs regions */
108 static struct ifsregion ifsfirst
;
109 /* last struct in list */
110 static struct ifsregion
*ifslastp
;
111 /* holds expanded arg list */
112 static struct arglist exparg
;
114 static char *argstr(char *p
, int flag
);
115 static char *exptilde(char *startp
, int flag
);
116 static char *expari(char *start
, int flag
);
117 STATIC
void expbackq(union node
*, int);
118 STATIC
char *evalvar(char *, int);
119 static size_t strtodest(const char *p
, int flags
);
120 static size_t memtodest(const char *p
, size_t len
, int flags
);
121 STATIC ssize_t
varvalue(char *, int, int, int);
122 STATIC
void expandmeta(struct strlist
*);
123 static void addglob(const glob64_t
*);
124 static char *expmeta(char *, unsigned, size_t);
125 STATIC
struct strlist
*expsort(struct strlist
*);
126 STATIC
struct strlist
*msort(struct strlist
*, int);
127 STATIC
void addfname(char *);
128 STATIC
int patmatch(char *, const char *);
129 STATIC
int pmatch(const char *, const char *);
130 static size_t cvtnum(intmax_t num
, int flags
);
131 STATIC
size_t esclen(const char *, const char *);
132 STATIC
void varunset(const char *, const char *, const char *, int)
133 __attribute__((__noreturn__
));
137 * Prepare a pattern for a glob(3) call.
139 * Returns an stalloced string.
143 preglob(const char *pattern
, int flag
) {
144 flag
|= RMESCAPE_GLOB
;
145 return _rmescapes((char *)pattern
, flag
);
150 esclen(const char *start
, const char *p
) {
153 while (p
> start
&& *--p
== (char)CTLESC
) {
160 static inline const char *getpwhome(const char *name
)
163 struct passwd
*pw
= getpwnam(name
);
164 return pw
? pw
->pw_dir
: 0;
172 * Perform variable substitution and command substitution on an argument,
173 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
174 * perform splitting and file name expansion. When arglist is NULL, perform
175 * here document expansion.
179 expandarg(union node
*arg
, struct arglist
*arglist
, int flag
)
184 argbackq
= arg
->narg
.backquote
;
185 STARTSTACKSTR(expdest
);
186 argstr(arg
->narg
.text
, flag
);
187 if (arglist
== NULL
) {
188 /* here document expanded */
191 p
= grabstackstr(expdest
);
192 exparg
.lastp
= &exparg
.list
;
196 if (flag
& EXP_FULL
) {
197 ifsbreakup(p
, -1, &exparg
);
198 *exparg
.lastp
= NULL
;
199 exparg
.lastp
= &exparg
.list
;
200 expandmeta(exparg
.list
);
202 sp
= (struct strlist
*)stalloc(sizeof (struct strlist
));
205 exparg
.lastp
= &sp
->next
;
207 *exparg
.lastp
= NULL
;
209 *arglist
->lastp
= exparg
.list
;
210 arglist
->lastp
= exparg
.lastp
;
220 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
221 * characters to allow for further processing. Otherwise treat
222 * $@ like $* since no splitting will be performed.
225 static char *argstr(char *p
, int flag
)
227 static const char spclchars
[] = {
239 const char *reject
= spclchars
;
241 int breakall
= (flag
& (EXP_WORD
| EXP_QUOTED
)) == EXP_WORD
;
246 reject
+= !!(flag
& EXP_VARTILDE2
);
247 reject
+= flag
& EXP_VARTILDE
? 0 : 2;
250 if (flag
& EXP_TILDE
) {
254 p
= exptilde(p
, flag
);
257 startloc
= expdest
- (char *)stackblock();
261 length
+= strcspn(p
+ length
, reject
);
263 c
= (signed char)p
[length
];
264 if (!(c
& 0x80) || c
== CTLENDARI
|| c
== CTLENDVAR
) {
266 * c == '=' || c == ':' || c == '\0' ||
267 * c == CTLENDARI || c == CTLENDVAR
270 /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */
271 end
= !!((c
- 1) & 0x80);
273 if (length
> 0 && !(flag
& EXP_DISCARD
)) {
277 q
= stnputs(p
, length
, expdest
);
279 expdest
= q
- (flag
& EXP_WORD
? end
: 0);
280 newloc
= q
- (char *)stackblock() - end
;
281 if (breakall
&& !inquotes
&& newloc
> startloc
) {
282 recordregion(startloc
, newloc
, 0);
294 flag
|= EXP_VARTILDE2
;
299 * sort of a hack - expand tildes in variable
300 * assignments (after the first '=' and after ':'s).
307 /* "$@" syntax adherence hack */
308 if (!inquotes
&& !memcmp(p
, dolatstr
+ 1,
310 p
= evalvar(p
+ 1, flag
| EXP_QUOTED
) + 1;
313 inquotes
^= EXP_QUOTED
;
315 if (flag
& QUOTES_ESC
) {
326 p
= evalvar(p
, flag
| inquotes
);
329 expbackq(argbackq
->n
, flag
| inquotes
);
332 p
= expari(p
, flag
| inquotes
);
339 static char *exptilde(char *startp
, int flag
)
349 while ((c
= *++p
) != '\0') {
356 if (flag
& EXP_VARTILDE
)
365 if (flag
& EXP_DISCARD
)
369 home
= lookupvar(homestr
);
371 home
= getpwhome(name
);
376 strtodest(home
, flag
| EXP_QUOTED
);
385 removerecordregions(int endoff
)
387 if (ifslastp
== NULL
)
390 if (ifsfirst
.endoff
> endoff
) {
391 while (ifsfirst
.next
!= NULL
) {
392 struct ifsregion
*ifsp
;
394 ifsp
= ifsfirst
.next
->next
;
395 ckfree(ifsfirst
.next
);
396 ifsfirst
.next
= ifsp
;
399 if (ifsfirst
.begoff
> endoff
)
402 ifslastp
= &ifsfirst
;
403 ifsfirst
.endoff
= endoff
;
408 ifslastp
= &ifsfirst
;
409 while (ifslastp
->next
&& ifslastp
->next
->begoff
< endoff
)
410 ifslastp
=ifslastp
->next
;
411 while (ifslastp
->next
!= NULL
) {
412 struct ifsregion
*ifsp
;
414 ifsp
= ifslastp
->next
->next
;
415 ckfree(ifslastp
->next
);
416 ifslastp
->next
= ifsp
;
419 if (ifslastp
->endoff
> endoff
)
420 ifslastp
->endoff
= endoff
;
425 * Expand arithmetic expression. Backup to start of expression,
426 * evaluate, place result in (backed up) result, adjust string position.
428 static char *expari(char *start
, int flag
)
438 begoff
= expdest
- p
;
439 p
= argstr(start
, flag
& EXP_DISCARD
);
441 if (flag
& EXP_DISCARD
)
444 start
= stackblock();
445 endoff
= expdest
- start
;
447 STADJUST(start
- expdest
, expdest
);
449 removerecordregions(begoff
);
451 if (likely(flag
& QUOTES_ESC
))
454 pushstackmark(&sm
, endoff
);
455 result
= arith(start
);
458 len
= cvtnum(result
, flag
);
460 if (likely(!(flag
& EXP_QUOTED
)))
461 recordregion(begoff
, begoff
+ len
, 0);
469 * Expand stuff in backwards quotes.
473 expbackq(union node
*cmd
, int flag
)
481 struct stackmark smark
;
483 if (flag
& EXP_DISCARD
)
487 startloc
= expdest
- (char *)stackblock();
488 pushstackmark(&smark
, startloc
);
489 evalbackcmd(cmd
, (struct backcmd
*) &in
);
490 popstackmark(&smark
);
497 memtodest(p
, i
, flag
);
502 i
= read(in
.fd
, buf
, sizeof buf
);
503 } while (i
< 0 && errno
== EINTR
);
504 TRACE(("expbackq: read returns %d\n", i
));
514 back_exitstatus
= waitforjob(in
.jp
);
518 /* Eat all trailing newlines */
520 for (; dest
> ((char *)stackblock() + startloc
) && dest
[-1] == '\n';)
524 if (!(flag
& EXP_QUOTED
))
525 recordregion(startloc
, dest
- (char *)stackblock(), 0);
526 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
527 (dest
- (char *)stackblock()) - startloc
,
528 (dest
- (char *)stackblock()) - startloc
,
529 stackblock() + startloc
));
532 argbackq
= argbackq
->next
;
536 static char *scanleft(char *startp
, char *endp
, char *rmesc
, char *rmescend
,
537 char *str
, int quotes
, int zero
547 const char *s
= loc2
;
553 match
= pmatch(str
, s
);
557 if (quotes
&& *loc
== (char)CTLESC
)
566 static char *scanright(char *startp
, char *endp
, char *rmesc
, char *rmescend
,
567 char *str
, int quotes
, int zero
573 for (loc
= endp
, loc2
= rmescend
; loc
>= startp
; loc2
--) {
576 const char *s
= loc2
;
581 match
= pmatch(str
, s
);
588 esc
= esclen(startp
, loc
);
599 static char *subevalvar(char *start
, char *str
, int strloc
, int startloc
,
600 int varflags
, int flag
)
602 int subtype
= varflags
& VSTYPE
;
603 int quotes
= flag
& QUOTES_ESC
;
607 char *rmesc
, *rmescend
;
609 char *(*scan
)(char *, char *, char *, char *, char *, int , int);
610 int nstrloc
= strloc
;
614 p
= argstr(start
, (flag
& EXP_DISCARD
) | EXP_TILDE
|
615 (str
? 0 : EXP_CASE
));
616 if (flag
& EXP_DISCARD
)
619 startp
= stackblock() + startloc
;
623 setvar(str
, startp
, 0);
629 varunset(start
, str
, startp
, varflags
);
633 subtype
-= VSTRIMRIGHT
;
635 if (subtype
< 0 || subtype
> 3)
639 rmescend
= stackblock() + strloc
;
640 str
= preglob(rmescend
, FNMATCH_IS_ENABLED
?
641 RMESCAPE_ALLOC
| RMESCAPE_GROW
: 0);
642 if (FNMATCH_IS_ENABLED
) {
643 startp
= stackblock() + startloc
;
644 rmescend
= stackblock() + strloc
;
645 nstrloc
= str
- (char *)stackblock();
650 rmesc
= _rmescapes(startp
, RMESCAPE_ALLOC
| RMESCAPE_GROW
);
653 startp
= stackblock() + startloc
;
654 str
= stackblock() + nstrloc
;
658 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
660 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
661 scan
= (subtype
& 1) ^ zero
? scanleft
: scanright
;
663 endp
= stackblock() + strloc
- 1;
664 loc
= scan(startp
, endp
, rmesc
, rmescend
, str
, quotes
, zero
);
667 memmove(startp
, loc
, endp
- loc
);
668 loc
= startp
+ (endp
- loc
);
675 amount
= loc
- expdest
;
676 STADJUST(amount
, expdest
);
678 /* Remove any recorded regions beyond start of variable */
679 removerecordregions(startloc
);
686 * Expand a variable, and return a pointer to the next character in the
690 evalvar(char *p
, int flag
)
701 varflags
= *p
++ & ~VSBIT
;
702 subtype
= varflags
& VSTYPE
;
704 quoted
= flag
& EXP_QUOTED
;
706 startloc
= expdest
- (char *)stackblock();
707 p
= strchr(p
, '=') + 1;
710 varlen
= varvalue(var
, varflags
, flag
, quoted
);
711 if (varflags
& VSNUL
)
714 discard
= varlen
< 0 ? EXP_DISCARD
: 0;
718 discard
^= EXP_DISCARD
;
723 p
= argstr(p
, flag
| EXP_TILDE
| EXP_WORD
|
724 (discard
^ EXP_DISCARD
));
729 p
= subevalvar(p
, var
, 0, startloc
, varflags
,
730 (flag
& ~QUOTES_ESC
) |
731 (discard
^ EXP_DISCARD
));
733 if ((flag
| ~discard
) & EXP_DISCARD
)
741 if ((discard
& ~flag
) && uflag
)
742 varunset(p
, var
, 0, 0);
744 if (subtype
== VSLENGTH
) {
746 if (flag
& EXP_DISCARD
)
748 cvtnum(varlen
> 0 ? varlen
: 0, flag
);
752 if (subtype
== VSNORMAL
)
768 if (!(flag
& EXP_DISCARD
)) {
770 * Terminate the string and start recording the pattern
773 STPUTC('\0', expdest
);
776 patloc
= expdest
- (char *)stackblock();
777 p
= subevalvar(p
, NULL
, patloc
, startloc
, varflags
, flag
);
780 if ((flag
| discard
) & EXP_DISCARD
)
785 quoted
= *var
== '@' && shellparam
.nparam
;
789 recordregion(startloc
, expdest
- (char *)stackblock(), quoted
);
795 * Put a string on the stack.
798 static size_t memtodest(const char *p
, size_t len
, int flags
)
800 const char *syntax
= flags
& EXP_QUOTED
? DQSYNTAX
: BASESYNTAX
;
807 q
= makestrspace(len
* 2, expdest
);
811 int c
= (signed char)*p
++;
813 if ((flags
& QUOTES_ESC
) &&
814 ((syntax
[c
] == CCTL
) ||
815 (flags
& EXP_QUOTED
&& syntax
[c
] == CBACK
)))
817 } else if (!(flags
& EXP_KEEPNUL
))
827 static size_t strtodest(const char *p
, int flags
)
829 size_t len
= strlen(p
);
830 memtodest(p
, len
, flags
);
837 * Add the value of a specialized variable to the stack string.
841 varvalue(char *name
, int varflags
, int flags
, int quoted
)
849 int subtype
= varflags
& VSTYPE
;
850 int discard
= (subtype
== VSPLUS
|| subtype
== VSLENGTH
) |
851 (flags
& EXP_DISCARD
);
859 sh_error("Bad substitution");
862 flags
|= EXP_KEEPNUL
;
863 flags
&= discard
? ~QUOTES_ESC
: ~0;
864 sep
= (flags
& EXP_FULL
) << CHAR_BIT
;
874 num
= shellparam
.nparam
;
881 len
= cvtnum(num
, flags
);
884 p
= makestrspace(NOPTS
, expdest
);
885 for (i
= NOPTS
- 1; i
>= 0; i
--) {
886 if (optlist
[i
] && optletters
[i
]) {
887 USTPUTC(optletters
[i
], p
);
898 /* We will set c to 0 or ~0 depending on whether
899 * we're doing field splitting. We won't do field
900 * splitting if either we're quoted or sep is zero.
902 * Instead of testing (quoted || !sep) the following
903 * trick optimises away any branches by using the
904 * fact that EXP_QUOTED (which is the only bit that
905 * can be set in quoted) is the same as EXP_FULL <<
906 * CHAR_BIT (which is the only bit that can be set
909 #if EXP_QUOTED >> CHAR_BIT != EXP_FULL
910 #error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
912 c
= !((quoted
| ~sep
) & EXP_QUOTED
) - 1;
914 sep
|= ifsset() ? (unsigned char)(c
& ifsval()[0]) : ' ';
917 if (!(ap
= shellparam
.p
))
919 while ((p
= *ap
++)) {
920 len
+= strtodest(p
, flags
);
924 memtodest(&sepc
, 1, flags
);
939 if (num
< 0 || num
> shellparam
.nparam
)
941 p
= num
? shellparam
.p
[num
- 1] : arg0
;
949 len
= strtodest(p
, flags
);
954 STADJUST(-len
, expdest
);
962 * Record the fact that we have to scan this region of the
963 * string for IFS characters.
967 recordregion(int start
, int end
, int nulonly
)
969 struct ifsregion
*ifsp
;
971 if (ifslastp
== NULL
) {
975 ifsp
= (struct ifsregion
*)ckmalloc(sizeof (struct ifsregion
));
977 ifslastp
->next
= ifsp
;
981 ifslastp
->begoff
= start
;
982 ifslastp
->endoff
= end
;
983 ifslastp
->nulonly
= nulonly
;
989 * Break the argument string into pieces based upon IFS and add the
990 * strings to the argument list. The regions of the string to be
991 * searched for IFS characters have been stored by recordregion.
992 * If maxargs is non-negative, at most maxargs arguments will be created, by
993 * joining together the last arguments.
996 ifsbreakup(char *string
, int maxargs
, struct arglist
*arglist
)
998 struct ifsregion
*ifsp
;
1004 const char *ifs
, *realifs
;
1010 if (ifslastp
!= NULL
) {
1013 realifs
= ifsset() ? ifsval() : defifs
;
1018 p
= string
+ ifsp
->begoff
;
1020 nulonly
= ifsp
->nulonly
;
1021 ifs
= nulonly
? nullstr
: realifs
;
1023 while (p
< string
+ ifsp
->endoff
) {
1030 if (c
== (char)CTLESC
)
1033 isifs
= strchr(ifs
, c
);
1036 isdefifs
= strchr(defifs
, c
);
1038 /* If only reading one more argument:
1039 * If we have exactly one field,
1040 * read that field without its terminator.
1041 * If we have more than one field,
1042 * read all fields including their terminators,
1043 * except for trailing IFS whitespace.
1045 * This means that if we have only IFS
1046 * characters left, and at most one
1047 * of them is non-whitespace, we stop
1049 * Otherwise, we read all the remaining
1050 * characters except for trailing
1053 * In any case, r indicates the start
1054 * of the characters to remove, or NULL
1055 * if no characters should be removed.
1064 if (!(isifs
&& ifsspc
))
1084 if (!(afternul
|| nulonly
))
1086 /* Ignore IFS whitespace at start */
1087 if (q
== start
&& ifsspc
) {
1092 if (maxargs
> 0 && !--maxargs
) {
1097 sp
= (struct strlist
*)stalloc(sizeof *sp
);
1099 *arglist
->lastp
= sp
;
1100 arglist
->lastp
= &sp
->next
;
1107 } while ((ifsp
= ifsp
->next
) != NULL
);
1119 sp
= (struct strlist
*)stalloc(sizeof *sp
);
1121 *arglist
->lastp
= sp
;
1122 arglist
->lastp
= &sp
->next
;
1127 struct ifsregion
*p
= ifsfirst
.next
;
1134 struct ifsregion
*ifsp
;
1139 ifsfirst
.next
= NULL
;
1149 * Expand shell metacharacters. At this point, the only control characters
1150 * should be escapes. The results are stored in the list exparg.
1154 static void *opendir_interruptible(const char *pathname
)
1156 if (int_pending()) {
1161 return opendir(pathname
);
1164 #define GLOB_ALTDIRFUNC 0
1167 static void expandmeta_glob(struct strlist
*str
)
1178 pglob
.gl_closedir
= (void *)closedir
;
1179 pglob
.gl_readdir
= (void *)readdir64
;
1180 pglob
.gl_opendir
= opendir_interruptible
;
1181 pglob
.gl_lstat
= lstat64
;
1182 pglob
.gl_stat
= stat64
;
1186 p
= preglob(str
->text
, RMESCAPE_ALLOC
| RMESCAPE_HEAP
);
1187 i
= glob64(p
, GLOB_ALTDIRFUNC
| GLOB_NOMAGIC
, 0, &pglob
);
1192 if ((pglob
.gl_flags
& (GLOB_NOMAGIC
| GLOB_NOCHECK
)) ==
1193 (GLOB_NOMAGIC
| GLOB_NOCHECK
))
1204 *exparg
.lastp
= str
;
1205 rmescapes(str
->text
);
1206 exparg
.lastp
= &str
->next
;
1208 default: /* GLOB_NOSPACE */
1209 sh_error("Out of space");
1217 * Add the result of glob(3) to the list.
1220 static void addglob(const glob64_t
*pglob
)
1222 char **p
= pglob
->gl_pathv
;
1230 expandmeta(struct strlist
*str
)
1232 static const char metachars
[] = {
1235 /* TODO - EXP_REDIR */
1237 if (GLOB_IS_ENABLED
)
1238 return expandmeta_glob(str
);
1241 struct strlist
**savelastp
;
1248 if (!strpbrk(str
->text
, metachars
))
1250 savelastp
= exparg
.lastp
;
1253 p
= preglob(str
->text
, RMESCAPE_ALLOC
| RMESCAPE_HEAP
);
1260 if (exparg
.lastp
== savelastp
) {
1265 *exparg
.lastp
= str
;
1266 rmescapes(str
->text
);
1267 exparg
.lastp
= &str
->next
;
1269 *exparg
.lastp
= NULL
;
1270 *savelastp
= sp
= expsort(*savelastp
);
1271 while (sp
->next
!= NULL
)
1273 exparg
.lastp
= &sp
->next
;
1279 static void addfname_common(char *name
)
1283 sp
= (struct strlist
*)stalloc(sizeof *sp
);
1286 exparg
.lastp
= &sp
->next
;
1289 static char *addfnamealt(char *enddir
, size_t expdir_len
)
1293 name
= grabstackstr(enddir
);
1294 addfname_common(name
);
1296 STARTSTACKSTR(enddir
);
1297 return stnputs(name
, expdir_len
, enddir
) - expdir_len
;
1301 * Do metacharacter (i.e. *, ?, [...]) expansion.
1304 static char *expmeta(char *name
, unsigned name_len
, size_t expdir_len
)
1306 struct jmploc
*volatile savehandler
;
1307 struct jmploc jmploc
;
1308 struct stat64 statb
;
1309 struct dirent64
*dp
;
1323 *(DIR *volatile *)&dirp
= NULL
;
1324 savehandler
= handler
;
1325 if (unlikely(err
= setjmp(jmploc
.loc
)))
1328 len
= expdir_len
+ name_len
+ 1;
1329 cp
= growstackto(len
);
1330 enddir
= cp
+ expdir_len
;
1334 for (p
= name
; esc
= 0, *p
; p
+= esc
+ 1) {
1335 if (*p
== '*' || *p
== '?')
1337 else if (*p
== '[') {
1344 if (*q
== '/' || *q
== '\0')
1352 if (*p
== '\\' && p
[1])
1354 if (p
[esc
] == '/') {
1357 start
= p
+ esc
+ 1;
1361 if (metaflag
== 0) { /* we've reached the end of the file name */
1366 if (*p
== '\\' && p
[1])
1370 if (lstat64(cp
, &statb
) >= 0)
1371 cp
= addfnamealt(enddir
, expdir_len
);
1378 if (*p
== '\\' && p
[1])
1381 } while (p
< start
);
1384 expdir_len
= enddir
- cp
;
1386 *(DIR *volatile *)&dirp
= opendir(expdir_len
? cp
: dotdir
);
1389 if (*endname
== 0) {
1396 name_len
-= endname
- name
;
1403 while (! int_pending() && (dp
= readdir64(dirp
)) != NULL
) {
1404 if (dp
->d_name
[0] == '.' && ! matchdot
)
1406 if (pmatch(start
, dp
->d_name
)) {
1407 len
= strlen(dp
->d_name
) + 1;
1409 enddir
= cp
+ expdir_len
;
1410 enddir
= stnputs(dp
->d_name
, len
, enddir
);
1412 cp
= addfnamealt(enddir
, expdir_len
);
1416 cp
= expmeta(endname
, name_len
, len
);
1421 endname
[-esc
- 1] = esc
? '\\' : '/';
1424 closedir(*(DIR *volatile *)&dirp
);
1426 handler
= savehandler
;
1428 longjmp(handler
->loc
, 1);
1434 * Add a file name to the list.
1438 addfname(char *name
)
1440 addfname_common(sstrdup(name
));
1445 * Sort the results of file name expansion. It calculates the number of
1446 * strings to sort and then calls msort (short for merge sort) to do the
1450 STATIC
struct strlist
*
1451 expsort(struct strlist
*str
)
1457 for (sp
= str
; sp
; sp
= sp
->next
)
1459 return msort(str
, len
);
1463 STATIC
struct strlist
*
1464 msort(struct strlist
*list
, int len
)
1466 struct strlist
*p
, *q
= NULL
;
1467 struct strlist
**lpp
;
1475 for (n
= half
; --n
>= 0 ; ) {
1479 q
->next
= NULL
; /* terminate first half of list */
1480 q
= msort(list
, half
); /* sort first half of list */
1481 p
= msort(p
, len
- half
); /* sort second half */
1484 if (strcoll(p
->text
, q
->text
) < 0) {
1487 if ((p
= *lpp
) == NULL
) {
1494 if ((q
= *lpp
) == NULL
) {
1505 * Returns true if the pattern matches the string.
1509 patmatch(char *pattern
, const char *string
)
1511 return pmatch(preglob(pattern
, FNMATCH_IS_ENABLED
?
1512 RMESCAPE_ALLOC
| RMESCAPE_GROW
: 0),
1517 STATIC
int ccmatch(const char *p
, int chr
, const char **r
)
1519 static const struct class {
1523 { .name
= ":alnum:]", .fn
= isalnum
},
1524 { .name
= ":cntrl:]", .fn
= iscntrl
},
1525 { .name
= ":lower:]", .fn
= islower
},
1526 { .name
= ":space:]", .fn
= isspace
},
1527 { .name
= ":alpha:]", .fn
= isalpha
},
1528 { .name
= ":digit:]", .fn
= isdigit
},
1529 { .name
= ":print:]", .fn
= isprint
},
1530 { .name
= ":upper:]", .fn
= isupper
},
1531 { .name
= ":blank:]", .fn
= isblank
},
1532 { .name
= ":graph:]", .fn
= isgraph
},
1533 { .name
= ":punct:]", .fn
= ispunct
},
1534 { .name
= ":xdigit:]", .fn
= isxdigit
},
1536 const struct class *class, *end
;
1538 end
= classes
+ sizeof(classes
) / sizeof(classes
[0]);
1539 for (class = classes
; class < end
; class++) {
1542 q
= prefix(p
, class->name
);
1546 return class->fn(chr
);
1554 pmatch(const char *pattern
, const char *string
)
1559 if (FNMATCH_IS_ENABLED
)
1560 return !fnmatch(pattern
, string
, 0);
1581 if (c
!= '\\' && c
!= '?' && c
!= '*' && c
!= '[') {
1591 } while (*q
++ != '\0');
1600 if (*p
== '!' || *p
== '^') {
1618 found
|= !!ccmatch(p
, chr
, &r
);
1623 } else if (c
== '\\')
1625 if (*p
== '-' && p
[1] != ']') {
1629 if (chr
>= c
&& chr
<= *p
)
1636 } while ((c
= *p
++) != ']');
1637 if (found
== invert
)
1657 * Remove any CTLESC characters from a string.
1661 _rmescapes(char *str
, int flag
)
1668 p
= strpbrk(str
, cqchars
);
1674 globbing
= flag
& RMESCAPE_GLOB
;
1676 if (flag
& RMESCAPE_ALLOC
) {
1677 size_t len
= p
- str
;
1678 size_t fulllen
= strlen(p
);
1680 if (FNMATCH_IS_ENABLED
&& globbing
)
1685 if (flag
& RMESCAPE_GROW
) {
1686 int strloc
= str
- (char *)stackblock();
1688 r
= makestrspace(fulllen
, expdest
);
1689 str
= (char *)stackblock() + strloc
;
1691 } else if (flag
& RMESCAPE_HEAP
) {
1692 r
= ckmalloc(fulllen
);
1694 r
= stalloc(fulllen
);
1698 q
= mempcpy(q
, str
, len
);
1702 notescaped
= globbing
;
1704 if (*p
== (char)CTLQUOTEMARK
) {
1706 inquotes
^= globbing
;
1710 /* naked back slash */
1711 notescaped
^= globbing
;
1714 if (*p
== (char)CTLESC
) {
1718 else if (inquotes
) {
1723 notescaped
= globbing
;
1728 if (flag
& RMESCAPE_GROW
) {
1730 STADJUST(q
- r
+ 1, expdest
);
1738 * See if a pattern matches in a case statement.
1742 casematch(union node
*pattern
, char *val
)
1744 struct stackmark smark
;
1747 setstackmark(&smark
);
1748 argbackq
= pattern
->narg
.backquote
;
1749 STARTSTACKSTR(expdest
);
1750 argstr(pattern
->narg
.text
, EXP_TILDE
| EXP_CASE
);
1752 result
= patmatch(stackblock(), val
);
1753 popstackmark(&smark
);
1761 static size_t cvtnum(intmax_t num
, int flags
)
1763 int len
= max_int_length(sizeof(num
));
1766 len
= fmtstr(buf
, len
, "%" PRIdMAX
, num
);
1767 return memtodest(buf
, len
, flags
);
1771 varunset(const char *end
, const char *var
, const char *umsg
, int varflags
)
1777 msg
= "parameter not set";
1779 if (*end
== (char)CTLENDVAR
) {
1780 if (varflags
& VSNUL
)
1785 sh_error("%.*s: %s%s", end
- var
- 1, var
, msg
, tail
);
1788 void restore_handler_expandarg(struct jmploc
*savehandler
, int err
)
1790 handler
= savehandler
;
1792 if (exception
!= EXERROR
)
1793 longjmp(handler
->loc
, 1);