]>
git.saurik.com Git - apple/shell_cmds.git/blob - sh/expand.c
193d65177e74c81fb64fa7f5d04a00ed9bbeb7eb
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 * 4. 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
37 static char sccsid
[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95";
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
43 #include <sys/types.h>
59 * Routines to expand arguments to commands. We have to deal with
60 * backquotes, shell variables, and file metacharacters.
83 * Structure specifying which parts of the string should be searched
88 struct ifsregion
*next
; /* next region in list */
89 int begoff
; /* offset of start of region */
90 int endoff
; /* offset of end of region */
91 int inquotes
; /* search for nul bytes only */
95 static char *expdest
; /* output of current string */
96 static struct nodelist
*argbackq
; /* list of back quote expressions */
97 static struct ifsregion ifsfirst
; /* first struct in list of ifs regions */
98 static struct ifsregion
*ifslastp
; /* last struct in list */
99 static struct arglist exparg
; /* holds expanded arg list */
101 static char *argstr(char *, int);
102 static char *exptilde(char *, int);
103 static char *expari(char *);
104 static void expbackq(union node
*, int, int);
105 static int subevalvar(char *, char *, int, int, int, int, int);
106 static char *evalvar(char *, int);
107 static int varisset(const char *, int);
108 static void strtodest(const char *, int, int, int);
109 static void varvalue(const char *, int, int, int);
110 static void recordregion(int, int, int);
111 static void removerecordregions(int);
112 static void ifsbreakup(char *, struct arglist
*);
113 static void expandmeta(struct strlist
*);
114 static void expmeta(char *, char *);
115 static void addfname(char *);
116 static struct strlist
*expsort(struct strlist
*);
117 static struct strlist
*msort(struct strlist
*, int);
118 static int patmatch(const char *, const char *, int);
119 static char *cvtnum(int, char *);
120 static int collate_range_cmp(wchar_t, wchar_t);
123 collate_range_cmp(wchar_t c1
, wchar_t c2
)
125 static wchar_t s1
[2], s2
[2];
129 return (wcscoll(s1
, s2
));
133 stputs_quotes(const char *data
, const char *syntax
, char *p
)
137 if (syntax
[(int)*data
] == CCTL
)
143 #define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p)
146 * Perform expansions on an argument, placing the resulting list of arguments
147 * in arglist. Parameter expansion, command substitution and arithmetic
148 * expansion are always performed; additional expansions can be requested
150 * The result is left in the stack string.
151 * When arglist is NULL, perform here document expansion.
153 * Caution: this function uses global state and is not reentrant.
154 * However, a new invocation after an interrupted invocation is safe
155 * and will reset the global state for the new call.
158 expandarg(union node
*arg
, struct arglist
*arglist
, int flag
)
163 argbackq
= arg
->narg
.backquote
;
164 STARTSTACKSTR(expdest
);
165 ifsfirst
.next
= NULL
;
167 argstr(arg
->narg
.text
, flag
);
168 if (arglist
== NULL
) {
169 STACKSTRNUL(expdest
);
170 return; /* here document expanded */
172 STPUTC('\0', expdest
);
173 p
= grabstackstr(expdest
);
174 exparg
.lastp
= &exparg
.list
;
175 if (flag
& EXP_FULL
) {
176 ifsbreakup(p
, &exparg
);
177 *exparg
.lastp
= NULL
;
178 exparg
.lastp
= &exparg
.list
;
179 expandmeta(exparg
.list
);
181 sp
= (struct strlist
*)stalloc(sizeof (struct strlist
));
184 exparg
.lastp
= &sp
->next
;
186 while (ifsfirst
.next
!= NULL
) {
187 struct ifsregion
*ifsp
;
189 ifsp
= ifsfirst
.next
->next
;
190 ckfree(ifsfirst
.next
);
191 ifsfirst
.next
= ifsp
;
194 *exparg
.lastp
= NULL
;
196 *arglist
->lastp
= exparg
.list
;
197 arglist
->lastp
= exparg
.lastp
;
204 * Perform parameter expansion, command substitution and arithmetic
205 * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
206 * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
207 * This is used to expand word in ${var+word} etc.
208 * If EXP_FULL or EXP_CASE are set, keep and/or generate CTLESC
209 * characters to allow for further processing.
210 * If EXP_FULL is set, also preserve CTLQUOTEMARK characters.
213 argstr(char *p
, int flag
)
216 int quotes
= flag
& (EXP_FULL
| EXP_CASE
); /* do CTLESC */
221 split_lit
= flag
& EXP_SPLIT_LIT
;
222 lit_quoted
= flag
& EXP_LIT_QUOTED
;
223 flag
&= ~(EXP_SPLIT_LIT
| EXP_LIT_QUOTED
);
224 if (*p
== '~' && (flag
& (EXP_TILDE
| EXP_VARTILDE
)))
225 p
= exptilde(p
, flag
);
227 CHECKSTRSPACE(2, expdest
);
236 /* "$@" syntax adherence hack */
237 if (p
[0] == CTLVAR
&& p
[2] == '@' && p
[3] == '=')
239 if ((flag
& EXP_FULL
) != 0)
250 if (split_lit
&& !lit_quoted
)
251 recordregion(expdest
- stackblock() -
253 expdest
- stackblock(), 0);
256 p
= evalvar(p
, flag
);
259 case CTLBACKQ
|CTLQUOTE
:
260 expbackq(argbackq
->n
, c
& CTLQUOTE
, flag
);
261 argbackq
= argbackq
->next
;
269 * sort of a hack - expand tildes in variable
270 * assignments (after the first '=' and after ':'s).
273 if (split_lit
&& !lit_quoted
)
274 recordregion(expdest
- stackblock() - 1,
275 expdest
- stackblock(), 0);
276 if (flag
& EXP_VARTILDE
&& *p
== '~' &&
277 (c
!= '=' || firsteq
)) {
280 p
= exptilde(p
, flag
);
285 if (split_lit
&& !lit_quoted
)
286 recordregion(expdest
- stackblock() - 1,
287 expdest
- stackblock(), 0);
293 * Perform tilde expansion, placing the result in the stack string and
294 * returning the next position in the input string to process.
297 exptilde(char *p
, int flag
)
306 case CTLESC
: /* This means CTL* are always considered quoted. */
309 case CTLBACKQ
| CTLQUOTE
:
315 if ((flag
& EXP_VARTILDE
) == 0)
322 if (*(startp
+1) == '\0') {
323 home
= lookupvar("HOME");
325 pw
= getpwnam(startp
+1);
326 home
= pw
!= NULL
? pw
->pw_dir
: NULL
;
329 if (home
== NULL
|| *home
== '\0')
331 strtodest(home
, flag
, VSNORMAL
, 1);
340 removerecordregions(int endoff
)
342 if (ifslastp
== NULL
)
345 if (ifsfirst
.endoff
> endoff
) {
346 while (ifsfirst
.next
!= NULL
) {
347 struct ifsregion
*ifsp
;
349 ifsp
= ifsfirst
.next
->next
;
350 ckfree(ifsfirst
.next
);
351 ifsfirst
.next
= ifsp
;
354 if (ifsfirst
.begoff
> endoff
)
357 ifslastp
= &ifsfirst
;
358 ifsfirst
.endoff
= endoff
;
363 ifslastp
= &ifsfirst
;
364 while (ifslastp
->next
&& ifslastp
->next
->begoff
< endoff
)
365 ifslastp
=ifslastp
->next
;
366 while (ifslastp
->next
!= NULL
) {
367 struct ifsregion
*ifsp
;
369 ifsp
= ifslastp
->next
->next
;
370 ckfree(ifslastp
->next
);
371 ifslastp
->next
= ifsp
;
374 if (ifslastp
->endoff
> endoff
)
375 ifslastp
->endoff
= endoff
;
379 * Expand arithmetic expression.
380 * Note that flag is not required as digits never require CTLESC characters.
391 quoted
= *p
++ == '"';
392 begoff
= expdest
- stackblock();
394 removerecordregions(begoff
);
395 STPUTC('\0', expdest
);
396 start
= stackblock() + begoff
;
398 q
= grabstackstr(expdest
);
399 result
= arith(start
);
400 ungrabstackstr(q
, expdest
);
402 start
= stackblock() + begoff
;
403 adj
= start
- expdest
;
404 STADJUST(adj
, expdest
);
406 CHECKSTRSPACE((int)(DIGITS(result
) + 1), expdest
);
407 fmtstr(expdest
, DIGITS(result
), ARITH_FORMAT_STR
, result
);
408 adj
= strlen(expdest
);
409 STADJUST(adj
, expdest
);
411 recordregion(begoff
, expdest
- stackblock(), 0);
417 * Perform command substitution.
420 expbackq(union node
*cmd
, int quoted
, int flag
)
426 char *dest
= expdest
;
427 struct ifsregion saveifs
, *savelastp
;
428 struct nodelist
*saveargbackq
;
430 int startloc
= dest
- stackblock();
431 char const *syntax
= quoted
? DQSYNTAX
: BASESYNTAX
;
432 int quotes
= flag
& (EXP_FULL
| EXP_CASE
);
437 savelastp
= ifslastp
;
438 saveargbackq
= argbackq
;
439 p
= grabstackstr(dest
);
440 evalbackcmd(cmd
, &in
);
441 ungrabstackstr(p
, dest
);
443 ifslastp
= savelastp
;
444 argbackq
= saveargbackq
;
449 /* Don't copy trailing newlines */
451 if (--in
.nleft
< 0) {
454 while ((i
= read(in
.fd
, buf
, sizeof buf
)) < 0 && errno
== EINTR
);
455 TRACE(("expbackq: read returns %d\n", i
));
466 CHECKSTRSPACE(nnl
+ 2, dest
);
471 if (quotes
&& syntax
[(int)lastc
] == CCTL
)
472 USTPUTC(CTLESC
, dest
);
473 USTPUTC(lastc
, dest
);
483 exitstatus
= waitforjob(in
.jp
, (int *)NULL
);
485 recordregion(startloc
, dest
- stackblock(), 0);
486 TRACE(("expbackq: size=%td: \"%.*s\"\n",
487 ((dest
- stackblock()) - startloc
),
488 (int)((dest
- stackblock()) - startloc
),
489 stackblock() + startloc
));
497 recordleft(const char *str
, const char *loc
, char *startp
)
501 amount
= ((str
- 1) - (loc
- startp
)) - expdest
;
502 STADJUST(amount
, expdest
);
503 while (loc
!= str
- 1)
508 subevalvar(char *p
, char *str
, int strloc
, int subtype
, int startloc
,
509 int varflags
, int quotes
)
515 struct nodelist
*saveargbackq
= argbackq
;
518 argstr(p
, (subtype
== VSTRIMLEFT
|| subtype
== VSTRIMLEFTMAX
||
519 subtype
== VSTRIMRIGHT
|| subtype
== VSTRIMRIGHTMAX
?
520 EXP_CASE
: 0) | EXP_TILDE
);
521 STACKSTRNUL(expdest
);
522 argbackq
= saveargbackq
;
523 startp
= stackblock() + startloc
;
525 str
= stackblock() + strloc
;
529 setvar(str
, startp
, 0);
530 amount
= startp
- expdest
;
531 STADJUST(amount
, expdest
);
536 if (*p
!= CTLENDVAR
) {
537 outfmt(out2
, "%s\n", startp
);
540 error("%.*s: parameter %snot set", (int)(p
- str
- 1),
541 str
, (varflags
& VSNUL
) ? "null or " : "");
545 for (loc
= startp
; loc
< str
; loc
++) {
548 if (patmatch(str
, startp
, quotes
)) {
550 recordleft(str
, loc
, startp
);
554 if (quotes
&& *loc
== CTLESC
)
560 for (loc
= str
- 1; loc
>= startp
;) {
563 if (patmatch(str
, startp
, quotes
)) {
565 recordleft(str
, loc
, startp
);
570 if (quotes
&& loc
> startp
&& *(loc
- 1) == CTLESC
) {
571 for (q
= startp
; q
< loc
; q
++)
581 for (loc
= str
- 1; loc
>= startp
;) {
582 if (patmatch(str
, loc
, quotes
)) {
583 amount
= loc
- expdest
;
584 STADJUST(amount
, expdest
);
588 if (quotes
&& loc
> startp
&& *(loc
- 1) == CTLESC
) {
589 for (q
= startp
; q
< loc
; q
++)
599 for (loc
= startp
; loc
< str
- 1; loc
++) {
600 if (patmatch(str
, loc
, quotes
)) {
601 amount
= loc
- expdest
;
602 STADJUST(amount
, expdest
);
605 if (quotes
&& *loc
== CTLESC
)
618 * Expand a variable, and return a pointer to the next character in the
623 evalvar(char *p
, int flag
)
637 int quotes
= flag
& (EXP_FULL
| EXP_CASE
);
640 varflags
= (unsigned char)*p
++;
641 subtype
= varflags
& VSTYPE
;
646 p
= strchr(p
, '=') + 1;
647 again
: /* jump here after setting a variable with ${var=text} */
648 if (varflags
& VSLINENO
) {
652 } else if (special
) {
653 set
= varisset(var
, varflags
& VSNUL
);
656 val
= bltinlookup(var
, 1);
657 if (val
== NULL
|| ((varflags
& VSNUL
) && val
[0] == '\0')) {
664 startloc
= expdest
- stackblock();
665 if (!set
&& uflag
&& *var
!= '@' && *var
!= '*') {
673 error("%.*s: parameter not set", (int)(p
- var
- 1),
677 if (set
&& subtype
!= VSPLUS
) {
678 /* insert the value of the variable */
680 if (varflags
& VSLINENO
)
681 STPUTBIN(var
, p
- var
- 1, expdest
);
683 varvalue(var
, varflags
& VSQUOTE
, subtype
, flag
);
684 if (subtype
== VSLENGTH
) {
685 varlenb
= expdest
- stackblock() - startloc
;
688 val
= stackblock() + startloc
;
689 for (;val
!= expdest
; val
++)
690 if ((*val
& 0xC0) == 0x80)
693 STADJUST(-varlenb
, expdest
);
696 if (subtype
== VSLENGTH
) {
699 (*val
& 0xC0) != 0x80)
703 strtodest(val
, flag
, subtype
,
708 if (subtype
== VSPLUS
)
711 easy
= ((varflags
& VSQUOTE
) == 0 ||
712 (*var
== '@' && shellparam
.nparam
!= 1));
717 expdest
= cvtnum(varlen
, expdest
);
728 argstr(p
, flag
| (flag
& EXP_FULL
? EXP_SPLIT_LIT
: 0) |
729 (varflags
& VSQUOTE
? EXP_LIT_QUOTED
: 0));
742 * Terminate the string and start recording the pattern
745 STPUTC('\0', expdest
);
746 patloc
= expdest
- stackblock();
747 if (subevalvar(p
, NULL
, patloc
, subtype
,
748 startloc
, varflags
, quotes
) == 0) {
749 int amount
= (expdest
- stackblock() - patloc
) + 1;
750 STADJUST(-amount
, expdest
);
752 /* Remove any recorded regions beyond start of variable */
753 removerecordregions(startloc
);
760 if (subevalvar(p
, var
, 0, subtype
, startloc
, varflags
,
764 * Remove any recorded regions beyond
767 removerecordregions(startloc
);
777 error("${%.*s%s}: Bad substitution", c
, var
,
778 (c
> 0 && *p
!= CTLENDVAR
) ? "..." : "");
785 recordregion(startloc
, expdest
- stackblock(),
786 varflags
& VSQUOTE
|| (ifsset() && ifsval()[0] == '\0' &&
787 (*var
== '@' || *var
== '*')));
789 if (subtype
!= VSNORMAL
) { /* skip to end of alternative */
792 if ((c
= *p
++) == CTLESC
)
794 else if (c
== CTLBACKQ
|| c
== (CTLBACKQ
|CTLQUOTE
)) {
796 argbackq
= argbackq
->next
;
797 } else if (c
== CTLVAR
) {
798 if ((*p
++ & VSTYPE
) != VSNORMAL
)
800 } else if (c
== CTLENDVAR
) {
812 * Test whether a specialized variable is set.
816 varisset(const char *name
, int nulok
)
820 return backgndpidset();
821 else if (*name
== '@' || *name
== '*') {
822 if (*shellparam
.p
== NULL
)
828 for (av
= shellparam
.p
; *av
; av
++)
833 } else if (is_digit(*name
)) {
838 num
= strtol(name
, NULL
, 10);
839 if (errno
!= 0 || num
> shellparam
.nparam
)
845 ap
= shellparam
.p
[num
- 1];
847 if (nulok
&& (ap
== NULL
|| *ap
== '\0'))
854 strtodest(const char *p
, int flag
, int subtype
, int quoted
)
856 if (flag
& (EXP_FULL
| EXP_CASE
) && subtype
!= VSLENGTH
)
857 STPUTS_QUOTES(p
, quoted
? DQSYNTAX
: BASESYNTAX
, expdest
);
863 * Add the value of a specialized variable to the stack string.
867 varvalue(const char *name
, int quoted
, int subtype
, int flag
)
883 num
= shellparam
.nparam
;
886 num
= backgndpidval();
889 for (i
= 0 ; i
< NOPTS
; i
++) {
891 STPUTC(optlist
[i
].letter
, expdest
);
895 if (flag
& EXP_FULL
&& quoted
) {
896 for (ap
= shellparam
.p
; (p
= *ap
++) != NULL
; ) {
897 strtodest(p
, flag
, subtype
, quoted
);
899 STPUTC('\0', expdest
);
906 sep
[0] = ifsval()[0];
910 for (ap
= shellparam
.p
; (p
= *ap
++) != NULL
; ) {
911 strtodest(p
, flag
, subtype
, quoted
);
915 strtodest(sep
, flag
, subtype
, quoted
);
916 else if (flag
& EXP_FULL
&& !quoted
&& **ap
!= '\0')
917 STPUTC('\0', expdest
);
921 if (is_digit(*name
)) {
925 else if (num
> 0 && num
<= shellparam
.nparam
)
926 p
= shellparam
.p
[num
- 1];
929 strtodest(p
, flag
, subtype
, quoted
);
933 expdest
= cvtnum(num
, expdest
);
939 * Record the fact that we have to scan this region of the
940 * string for IFS characters.
944 recordregion(int start
, int end
, int inquotes
)
946 struct ifsregion
*ifsp
;
949 if (ifslastp
== NULL
) {
952 if (ifslastp
->endoff
== start
953 && ifslastp
->inquotes
== inquotes
) {
954 /* extend previous area */
955 ifslastp
->endoff
= end
;
959 ifsp
= (struct ifsregion
*)ckmalloc(sizeof (struct ifsregion
));
960 ifslastp
->next
= ifsp
;
963 ifslastp
->next
= NULL
;
964 ifslastp
->begoff
= start
;
965 ifslastp
->endoff
= end
;
966 ifslastp
->inquotes
= inquotes
;
973 * Break the argument string into pieces based upon IFS and add the
974 * strings to the argument list. The regions of the string to be
975 * searched for IFS characters have been stored by recordregion.
976 * CTLESC characters are preserved but have little effect in this pass
977 * other than escaping CTL* characters. In particular, they do not escape
978 * IFS characters: that should be done with the ifsregion mechanism.
979 * CTLQUOTEMARK characters are used to preserve empty quoted strings.
980 * This pass treats them as a regular character, making the string non-empty.
981 * Later, they are removed along with the other CTL* characters.
984 ifsbreakup(char *string
, struct arglist
*arglist
)
986 struct ifsregion
*ifsp
;
993 int had_param_ch
= 0;
997 if (ifslastp
== NULL
) {
998 /* Return entire argument, IFS doesn't apply to any of it */
999 sp
= (struct strlist
*)stalloc(sizeof *sp
);
1001 *arglist
->lastp
= sp
;
1002 arglist
->lastp
= &sp
->next
;
1006 ifs
= ifsset() ? ifsval() : " \t\n";
1008 for (ifsp
= &ifsfirst
; ifsp
!= NULL
; ifsp
= ifsp
->next
) {
1009 p
= string
+ ifsp
->begoff
;
1010 while (p
< string
+ ifsp
->endoff
) {
1014 if (ifsp
->inquotes
) {
1015 /* Only NULs (should be from "$@") end args */
1023 if (!strchr(ifs
, *p
)) {
1028 ifsspc
= strchr(" \t\n", *p
);
1030 /* Ignore IFS whitespace at start */
1031 if (q
== start
&& ifsspc
!= NULL
) {
1039 /* Save this argument... */
1041 sp
= (struct strlist
*)stalloc(sizeof *sp
);
1043 *arglist
->lastp
= sp
;
1044 arglist
->lastp
= &sp
->next
;
1047 if (ifsspc
!= NULL
) {
1048 /* Ignore further trailing IFS whitespace */
1049 for (; p
< string
+ ifsp
->endoff
; p
++) {
1053 if (strchr(ifs
, *p
) == NULL
) {
1057 if (strchr(" \t\n", *p
) == NULL
) {
1068 * Save anything left as an argument.
1069 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
1070 * generating 2 arguments, the second of which is empty.
1071 * Some recent clarification of the Posix spec say that it
1072 * should only generate one....
1074 if (had_param_ch
|| *start
!= 0) {
1075 sp
= (struct strlist
*)stalloc(sizeof *sp
);
1077 *arglist
->lastp
= sp
;
1078 arglist
->lastp
= &sp
->next
;
1083 static char expdir
[PATH_MAX
];
1084 #define expdir_end (expdir + sizeof(expdir))
1087 * Perform pathname generation and remove control characters.
1088 * At this point, the only control characters should be CTLESC and CTLQUOTEMARK.
1089 * The results are stored in the list exparg.
1092 expandmeta(struct strlist
*str
)
1095 struct strlist
**savelastp
;
1100 savelastp
= exparg
.lastp
;
1103 for (; (c
= *p
) != '\0'; p
++) {
1104 /* fast check for meta chars */
1105 if (c
== '*' || c
== '?' || c
== '[') {
1107 expmeta(expdir
, str
->text
);
1113 if (exparg
.lastp
== savelastp
) {
1117 *exparg
.lastp
= str
;
1118 rmescapes(str
->text
);
1119 exparg
.lastp
= &str
->next
;
1121 *exparg
.lastp
= NULL
;
1122 *savelastp
= sp
= expsort(*savelastp
);
1123 while (sp
->next
!= NULL
)
1125 exparg
.lastp
= &sp
->next
;
1133 * Do metacharacter (i.e. *, ?, [...]) expansion.
1137 expmeta(char *enddir
, char *name
)
1154 for (p
= name
; esc
= 0, *p
; p
+= esc
+ 1) {
1155 if (*p
== '*' || *p
== '?')
1157 else if (*p
== '[') {
1159 if (*q
== '!' || *q
== '^')
1162 while (*q
== CTLQUOTEMARK
)
1166 if (*q
== '/' || *q
== '\0')
1173 } else if (*p
== '\0')
1175 else if (*p
== CTLQUOTEMARK
)
1180 if (p
[esc
] == '/') {
1183 start
= p
+ esc
+ 1;
1187 if (metaflag
== 0) { /* we've reached the end of the file name */
1188 if (enddir
!= expdir
)
1190 for (p
= name
; ; p
++) {
1191 if (*p
== CTLQUOTEMARK
)
1198 if (enddir
== expdir_end
)
1201 if (metaflag
== 0 || lstat(expdir
, &statb
) >= 0)
1205 endname
= name
+ (p
- name
);
1206 if (start
!= name
) {
1209 while (*p
== CTLQUOTEMARK
)
1214 if (enddir
== expdir_end
)
1218 if (enddir
== expdir
) {
1220 } else if (enddir
== expdir
+ 1 && *expdir
== '/') {
1226 if ((dirp
= opendir(p
)) == NULL
)
1228 if (enddir
!= expdir
)
1230 if (*endname
== 0) {
1239 while (*p
== CTLQUOTEMARK
)
1245 while (! int_pending() && (dp
= readdir(dirp
)) != NULL
) {
1246 if (dp
->d_name
[0] == '.' && ! matchdot
)
1248 if (patmatch(start
, dp
->d_name
, 0)) {
1249 namlen
= dp
->d_namlen
;
1250 if (enddir
+ namlen
+ 1 > expdir_end
)
1252 memcpy(enddir
, dp
->d_name
, namlen
+ 1);
1256 if (dp
->d_type
!= DT_UNKNOWN
&&
1257 dp
->d_type
!= DT_DIR
&&
1258 dp
->d_type
!= DT_LNK
)
1260 if (enddir
+ namlen
+ 2 > expdir_end
)
1262 enddir
[namlen
] = '/';
1263 enddir
[namlen
+ 1] = '\0';
1264 expmeta(enddir
+ namlen
+ 1, endname
);
1270 endname
[-esc
- 1] = esc
? CTLESC
: '/';
1275 * Add a file name to the list.
1279 addfname(char *name
)
1284 p
= stsavestr(name
);
1285 sp
= (struct strlist
*)stalloc(sizeof *sp
);
1288 exparg
.lastp
= &sp
->next
;
1293 * Sort the results of file name expansion. It calculates the number of
1294 * strings to sort and then calls msort (short for merge sort) to do the
1298 static struct strlist
*
1299 expsort(struct strlist
*str
)
1305 for (sp
= str
; sp
; sp
= sp
->next
)
1307 return msort(str
, len
);
1311 static struct strlist
*
1312 msort(struct strlist
*list
, int len
)
1314 struct strlist
*p
, *q
= NULL
;
1315 struct strlist
**lpp
;
1323 for (n
= half
; --n
>= 0 ; ) {
1327 q
->next
= NULL
; /* terminate first half of list */
1328 q
= msort(list
, half
); /* sort first half of list */
1329 p
= msort(p
, len
- half
); /* sort second half */
1332 if (strcmp(p
->text
, q
->text
) < 0) {
1335 if ((p
= *lpp
) == NULL
) {
1342 if ((q
= *lpp
) == NULL
) {
1354 get_wc(const char **p
)
1359 chrlen
= mbtowc(&c
, *p
, 4);
1362 else if (chrlen
== -1)
1371 * See if a character matches a character class, starting at the first colon
1373 * If a valid character class is recognized, a pointer to the next character
1374 * after the final closing bracket is stored into *end, otherwise a null
1375 * pointer is stored into *end.
1378 match_charclass(const char *p
, wchar_t chr
, const char **end
)
1381 const char *nameend
;
1386 nameend
= strstr(p
, ":]");
1387 if (nameend
== NULL
|| (size_t)(nameend
- p
) >= sizeof(name
) ||
1390 memcpy(name
, p
, nameend
- p
);
1391 name
[nameend
- p
] = '\0';
1393 cclass
= wctype(name
);
1394 /* An unknown class matches nothing but is valid nevertheless. */
1397 return iswctype(chr
, cclass
);
1402 * Returns true if the pattern matches the string.
1406 patmatch(const char *pattern
, const char *string
, int squoted
)
1408 const char *p
, *q
, *end
;
1409 const char *bt_p
, *bt_q
;
1424 if (squoted
&& *q
== CTLESC
)
1432 if (squoted
&& *q
== CTLESC
)
1439 * A '?' does not match invalid UTF-8 but a
1440 * '*' does, so backtrack.
1445 wc
= (unsigned char)*q
++;
1449 while (c
== CTLQUOTEMARK
|| c
== '*')
1452 * If the pattern ends here, we know the string
1453 * matches without needing to look at the rest of it.
1458 * First try the shortest match for the '*' that
1459 * could work. We can forget any earlier '*' since
1460 * there is no way having it match more characters
1461 * can help us, given that we are already here.
1472 if (*endp
== '!' || *endp
== '^')
1475 while (*endp
== CTLQUOTEMARK
)
1478 goto dft
; /* no matching ] */
1479 if (*endp
== CTLESC
)
1481 } while (*++endp
!= ']');
1483 if (*p
== '!' || *p
== '^') {
1488 if (squoted
&& *q
== CTLESC
)
1497 chr
= (unsigned char)*q
++;
1500 if (c
== CTLQUOTEMARK
)
1502 if (c
== '[' && *p
== ':') {
1503 found
|= match_charclass(p
, chr
, &end
);
1509 if (localeisutf8
&& c
& 0x80) {
1512 if (wc
== 0) /* bad utf-8 */
1515 wc
= (unsigned char)c
;
1516 if (*p
== '-' && p
[1] != ']') {
1518 while (*p
== CTLQUOTEMARK
)
1524 if (wc2
== 0) /* bad utf-8 */
1527 wc2
= (unsigned char)*p
++;
1528 if ( collate_range_cmp(chr
, wc
) >= 0
1529 && collate_range_cmp(chr
, wc2
) <= 0
1536 } while ((c
= *p
++) != ']');
1537 if (found
== invert
)
1542 if (squoted
&& *q
== CTLESC
)
1550 * If we have a mismatch (other than hitting the end
1551 * of the string), go back to the last '*' seen and
1552 * have it match one additional character.
1556 if (squoted
&& *bt_q
== CTLESC
)
1571 * Remove any CTLESC and CTLQUOTEMARK characters from a string.
1575 rmescapes(char *str
)
1580 while (*p
!= CTLESC
&& *p
!= CTLQUOTEMARK
&& *p
!= CTLQUOTEEND
) {
1586 if (*p
== CTLQUOTEMARK
|| *p
== CTLQUOTEEND
) {
1600 * See if a pattern matches in a case statement.
1604 casematch(union node
*pattern
, const char *val
)
1606 struct stackmark smark
;
1610 setstackmark(&smark
);
1611 argbackq
= pattern
->narg
.backquote
;
1612 STARTSTACKSTR(expdest
);
1614 argstr(pattern
->narg
.text
, EXP_TILDE
| EXP_CASE
);
1615 STPUTC('\0', expdest
);
1616 p
= grabstackstr(expdest
);
1617 result
= patmatch(p
, val
, 0);
1618 popstackmark(&smark
);
1627 cvtnum(int num
, char *buf
)
1631 char *p
= temp
+ 31;
1636 *--p
= num
% 10 + '0';
1637 } while ((num
/= 10) != 0);
1647 * Do most of the work for wordexp(3).
1651 wordexpcmd(int argc
, char **argv
)
1656 out1fmt("%08x", argc
- 1);
1657 for (i
= 1, len
= 0; i
< argc
; i
++)
1658 len
+= strlen(argv
[i
]);
1659 out1fmt("%08x", (int)len
);
1660 for (i
= 1; i
< argc
; i
++)
1661 outbin(argv
[i
], strlen(argv
[i
]) + 1, out1
);