42 |
#endif |
#endif |
43 |
#include <stdlib.h> |
#include <stdlib.h> |
44 |
#include <stdio.h> |
#include <stdio.h> |
45 |
|
#include <stdint.h> |
46 |
#include <limits.h> |
#include <limits.h> |
47 |
#include <string.h> |
#include <string.h> |
|
#if defined(__GLIBC__) |
|
|
#if !defined(FNMATCH_BROKEN) |
|
48 |
#include <fnmatch.h> |
#include <fnmatch.h> |
49 |
#if !defined(GLOB_BROKEN) |
#ifdef HAVE_GLOB |
50 |
#include <glob.h> |
#include <glob.h> |
51 |
#endif |
#endif |
|
#else |
|
52 |
#include <ctype.h> |
#include <ctype.h> |
|
#endif |
|
|
#endif |
|
53 |
|
|
54 |
/* |
/* |
55 |
* Routines to expand arguments to commands. We have to deal with |
* Routines to expand arguments to commands. We have to deal with |
78 |
*/ |
*/ |
79 |
#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ |
#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ |
80 |
#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ |
#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ |
|
#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ |
|
81 |
#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ |
#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ |
82 |
#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ |
#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ |
83 |
|
|
84 |
/* Add CTLESC when necessary. */ |
/* Add CTLESC when necessary. */ |
85 |
#define QUOTES_ESC (EXP_FULL | EXP_CASE) |
#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT) |
86 |
/* Do not skip NUL characters. */ |
/* Do not skip NUL characters. */ |
87 |
#define QUOTES_KEEPNUL EXP_TILDE |
#define QUOTES_KEEPNUL EXP_TILDE |
88 |
|
|
111 |
|
|
112 |
STATIC void argstr(char *, int); |
STATIC void argstr(char *, int); |
113 |
STATIC char *exptilde(char *, char *, int); |
STATIC char *exptilde(char *, char *, int); |
114 |
STATIC void expbackq(union node *, int, int); |
STATIC void expbackq(union node *, int); |
115 |
STATIC const char *subevalvar(char *, char *, int, int, int, int, int); |
STATIC const char *subevalvar(char *, char *, int, int, int, int, int); |
116 |
STATIC char *evalvar(char *, int); |
STATIC char *evalvar(char *, int); |
117 |
STATIC size_t strtodest(const char *, const char *, int); |
STATIC size_t strtodest(const char *, const char *, int); |
118 |
STATIC void memtodest(const char *, size_t, const char *, int); |
STATIC void memtodest(const char *, size_t, const char *, int); |
119 |
STATIC ssize_t varvalue(char *, int, int); |
STATIC ssize_t varvalue(char *, int, int); |
|
STATIC void recordregion(int, int, int); |
|
|
STATIC void removerecordregions(int); |
|
|
STATIC void ifsbreakup(char *, struct arglist *); |
|
120 |
STATIC void ifsfree(void); |
STATIC void ifsfree(void); |
121 |
STATIC void expandmeta(struct strlist *, int); |
STATIC void expandmeta(struct strlist *, int); |
122 |
#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) |
#ifdef HAVE_GLOB |
123 |
STATIC void addglob(const glob_t *); |
STATIC void addglob(const glob_t *); |
124 |
#else |
#else |
125 |
STATIC void expmeta(char *, char *); |
STATIC void expmeta(char *, char *); |
|
#endif |
|
|
STATIC void addfname(char *); |
|
|
#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) |
|
126 |
STATIC struct strlist *expsort(struct strlist *); |
STATIC struct strlist *expsort(struct strlist *); |
127 |
STATIC struct strlist *msort(struct strlist *, int); |
STATIC struct strlist *msort(struct strlist *, int); |
128 |
#endif |
#endif |
129 |
|
STATIC void addfname(char *); |
130 |
STATIC int patmatch(char *, const char *); |
STATIC int patmatch(char *, const char *); |
131 |
#if !defined(__GLIBC__) || defined(FNMATCH_BROKEN) |
#ifndef HAVE_FNMATCH |
132 |
STATIC int pmatch(const char *, const char *); |
STATIC int pmatch(const char *, const char *); |
133 |
#else |
#else |
134 |
#define pmatch(a, b) !fnmatch((a), (b), 0) |
#define pmatch(a, b) !fnmatch((a), (b), 0) |
135 |
#endif |
#endif |
136 |
STATIC int cvtnum(long); |
STATIC int cvtnum(intmax_t); |
137 |
STATIC size_t esclen(const char *, const char *); |
STATIC size_t esclen(const char *, const char *); |
138 |
STATIC char *scanleft(char *, char *, char *, char *, int, int); |
STATIC char *scanleft(char *, char *, char *, char *, int, int); |
139 |
STATIC char *scanright(char *, char *, char *, char *, int, int); |
STATIC char *scanright(char *, char *, char *, char *, int, int); |
148 |
*/ |
*/ |
149 |
|
|
150 |
STATIC inline char * |
STATIC inline char * |
151 |
preglob(const char *pattern, int quoted, int flag) { |
preglob(const char *pattern, int flag) { |
152 |
flag |= RMESCAPE_GLOB; |
flag |= RMESCAPE_GLOB; |
|
if (quoted) { |
|
|
flag |= RMESCAPE_QUOTED; |
|
|
} |
|
153 |
return _rmescapes((char *)pattern, flag); |
return _rmescapes((char *)pattern, flag); |
154 |
} |
} |
155 |
|
|
177 |
|
|
178 |
|
|
179 |
/* |
/* |
|
* Expand shell variables and backquotes inside a here document. |
|
|
*/ |
|
|
|
|
|
void |
|
|
expandhere(union node *arg, int fd) |
|
|
{ |
|
|
herefd = fd; |
|
|
expandarg(arg, (struct arglist *)NULL, 0); |
|
|
xwrite(fd, stackblock(), expdest - (char *)stackblock()); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
180 |
* Perform variable substitution and command substitution on an argument, |
* Perform variable substitution and command substitution on an argument, |
181 |
* placing the resulting list of arguments in arglist. If EXP_FULL is true, |
* placing the resulting list of arguments in arglist. If EXP_FULL is true, |
182 |
* perform splitting and file name expansion. When arglist is NULL, perform |
* perform splitting and file name expansion. When arglist is NULL, perform |
245 |
CTLESC, |
CTLESC, |
246 |
CTLVAR, |
CTLVAR, |
247 |
CTLBACKQ, |
CTLBACKQ, |
|
CTLBACKQ | CTLQUOTE, |
|
248 |
CTLENDARI, |
CTLENDARI, |
249 |
0 |
0 |
250 |
}; |
}; |
251 |
const char *reject = spclchars; |
const char *reject = spclchars; |
252 |
int c; |
int c; |
253 |
int quotes = flag & QUOTES_ESC; |
int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; |
|
int breakall = flag & EXP_WORD; |
|
254 |
int inquotes; |
int inquotes; |
255 |
size_t length; |
size_t length; |
256 |
int startloc; |
int startloc; |
268 |
flag &= ~EXP_TILDE; |
flag &= ~EXP_TILDE; |
269 |
tilde: |
tilde: |
270 |
q = p; |
q = p; |
|
if (*q == (char)CTLESC && (flag & EXP_QWORD)) |
|
|
q++; |
|
271 |
if (*q == '~') |
if (*q == '~') |
272 |
p = exptilde(p, q, flag); |
p = exptilde(p, q, flag); |
273 |
} |
} |
318 |
case CTLENDVAR: /* ??? */ |
case CTLENDVAR: /* ??? */ |
319 |
goto breakloop; |
goto breakloop; |
320 |
case CTLQUOTEMARK: |
case CTLQUOTEMARK: |
321 |
|
inquotes ^= EXP_QUOTED; |
322 |
/* "$@" syntax adherence hack */ |
/* "$@" syntax adherence hack */ |
323 |
if ( |
if (inquotes && !memcmp(p, dolatstr + 1, |
324 |
!inquotes && |
DOLATSTRLEN - 1)) { |
325 |
!memcmp(p, dolatstr, DOLATSTRLEN) && |
p = evalvar(p + 1, flag | inquotes) + 1; |
|
(p[4] == (char)CTLQUOTEMARK || ( |
|
|
p[4] == (char)CTLENDVAR && |
|
|
p[5] == (char)CTLQUOTEMARK |
|
|
)) |
|
|
) { |
|
|
p = evalvar(p + 1, flag) + 1; |
|
326 |
goto start; |
goto start; |
327 |
} |
} |
|
inquotes = !inquotes; |
|
328 |
addquote: |
addquote: |
329 |
if (quotes) { |
if (flag & QUOTES_ESC) { |
330 |
p--; |
p--; |
331 |
length++; |
length++; |
332 |
startloc++; |
startloc++; |
335 |
case CTLESC: |
case CTLESC: |
336 |
startloc++; |
startloc++; |
337 |
length++; |
length++; |
338 |
|
|
339 |
|
/* |
340 |
|
* Quoted parameter expansion pattern: remove quote |
341 |
|
* unless inside inner quotes or we have a literal |
342 |
|
* backslash. |
343 |
|
*/ |
344 |
|
if (((flag | inquotes) & (EXP_QPAT | EXP_QUOTED)) == |
345 |
|
EXP_QPAT && *p != '\\') |
346 |
|
break; |
347 |
|
|
348 |
goto addquote; |
goto addquote; |
349 |
case CTLVAR: |
case CTLVAR: |
350 |
p = evalvar(p, flag); |
p = evalvar(p, flag | inquotes); |
351 |
goto start; |
goto start; |
352 |
case CTLBACKQ: |
case CTLBACKQ: |
353 |
c = 0; |
expbackq(argbackq->n, flag | inquotes); |
|
case CTLBACKQ|CTLQUOTE: |
|
|
expbackq(argbackq->n, c, quotes); |
|
354 |
argbackq = argbackq->next; |
argbackq = argbackq->next; |
355 |
goto start; |
goto start; |
356 |
case CTLENDARI: |
case CTLENDARI: |
357 |
p--; |
p--; |
358 |
expari(quotes); |
expari(flag | inquotes); |
359 |
goto start; |
goto start; |
360 |
} |
} |
361 |
} |
} |
409 |
} |
} |
410 |
|
|
411 |
|
|
412 |
STATIC void |
void |
413 |
removerecordregions(int endoff) |
removerecordregions(int endoff) |
414 |
{ |
{ |
415 |
if (ifslastp == NULL) |
if (ifslastp == NULL) |
454 |
* evaluate, place result in (backed up) result, adjust string position. |
* evaluate, place result in (backed up) result, adjust string position. |
455 |
*/ |
*/ |
456 |
void |
void |
457 |
expari(int quotes) |
expari(int flag) |
458 |
{ |
{ |
459 |
|
struct stackmark sm; |
460 |
char *p, *start; |
char *p, *start; |
461 |
int begoff; |
int begoff; |
|
int flag; |
|
462 |
int len; |
int len; |
463 |
|
intmax_t result; |
464 |
|
|
465 |
/* ifsfree(); */ |
/* ifsfree(); */ |
466 |
|
|
470 |
* start of arithmetic. |
* start of arithmetic. |
471 |
*/ |
*/ |
472 |
start = stackblock(); |
start = stackblock(); |
473 |
p = expdest - 1; |
p = expdest; |
474 |
*p = '\0'; |
pushstackmark(&sm, p - start); |
475 |
|
*--p = '\0'; |
476 |
p--; |
p--; |
477 |
do { |
do { |
478 |
int esc; |
int esc; |
498 |
|
|
499 |
removerecordregions(begoff); |
removerecordregions(begoff); |
500 |
|
|
|
flag = p[1]; |
|
|
|
|
501 |
expdest = p; |
expdest = p; |
502 |
|
|
503 |
if (quotes) |
if (likely(flag & QUOTES_ESC)) |
504 |
rmescapes(p + 2); |
rmescapes(p + 1); |
505 |
|
|
506 |
|
result = arith(p + 1); |
507 |
|
popstackmark(&sm); |
508 |
|
|
509 |
len = cvtnum(arith(p + 2)); |
len = cvtnum(result); |
510 |
|
|
511 |
if (flag != '"') |
if (likely(!(flag & EXP_QUOTED))) |
512 |
recordregion(begoff, begoff + len, 0); |
recordregion(begoff, begoff + len, 0); |
513 |
} |
} |
514 |
|
|
518 |
*/ |
*/ |
519 |
|
|
520 |
STATIC void |
STATIC void |
521 |
expbackq(union node *cmd, int quoted, int quotes) |
expbackq(union node *cmd, int flag) |
522 |
{ |
{ |
523 |
struct backcmd in; |
struct backcmd in; |
524 |
int i; |
int i; |
526 |
char *p; |
char *p; |
527 |
char *dest; |
char *dest; |
528 |
int startloc; |
int startloc; |
529 |
char const *syntax = quoted? DQSYNTAX : BASESYNTAX; |
char const *syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; |
530 |
struct stackmark smark; |
struct stackmark smark; |
531 |
|
|
532 |
INTOFF; |
INTOFF; |
533 |
setstackmark(&smark); |
startloc = expdest - (char *)stackblock(); |
534 |
dest = expdest; |
pushstackmark(&smark, startloc); |
|
startloc = dest - (char *)stackblock(); |
|
|
grabstackstr(dest); |
|
535 |
evalbackcmd(cmd, (struct backcmd *) &in); |
evalbackcmd(cmd, (struct backcmd *) &in); |
536 |
popstackmark(&smark); |
popstackmark(&smark); |
537 |
|
|
540 |
if (i == 0) |
if (i == 0) |
541 |
goto read; |
goto read; |
542 |
for (;;) { |
for (;;) { |
543 |
memtodest(p, i, syntax, quotes); |
memtodest(p, i, syntax, flag & QUOTES_ESC); |
544 |
read: |
read: |
545 |
if (in.fd < 0) |
if (in.fd < 0) |
546 |
break; |
break; |
567 |
STUNPUTC(dest); |
STUNPUTC(dest); |
568 |
expdest = dest; |
expdest = dest; |
569 |
|
|
570 |
if (quoted == 0) |
if (!(flag & EXP_QUOTED)) |
571 |
recordregion(startloc, dest - (char *)stackblock(), 0); |
recordregion(startloc, dest - (char *)stackblock(), 0); |
572 |
TRACE(("evalbackq: size=%d: \"%.*s\"\n", |
TRACE(("evalbackq: size=%d: \"%.*s\"\n", |
573 |
(dest - (char *)stackblock()) - startloc, |
(dest - (char *)stackblock()) - startloc, |
644 |
} |
} |
645 |
|
|
646 |
STATIC const char * |
STATIC const char * |
647 |
subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) |
subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int flag) |
648 |
{ |
{ |
649 |
|
int quotes = flag & QUOTES_ESC; |
650 |
char *startp; |
char *startp; |
651 |
char *loc; |
char *loc; |
|
int saveherefd = herefd; |
|
652 |
struct nodelist *saveargbackq = argbackq; |
struct nodelist *saveargbackq = argbackq; |
653 |
int amount; |
int amount; |
654 |
char *rmesc, *rmescend; |
char *rmesc, *rmescend; |
655 |
int zero; |
int zero; |
656 |
char *(*scan)(char *, char *, char *, char *, int , int); |
char *(*scan)(char *, char *, char *, char *, int , int); |
657 |
|
|
658 |
herefd = -1; |
argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? |
659 |
argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); |
(flag & EXP_QUOTED ? EXP_QPAT : EXP_CASE) : 0)); |
660 |
STPUTC('\0', expdest); |
STPUTC('\0', expdest); |
|
herefd = saveherefd; |
|
661 |
argbackq = saveargbackq; |
argbackq = saveargbackq; |
662 |
startp = stackblock() + startloc; |
startp = stackblock() + startloc; |
663 |
|
|
690 |
} |
} |
691 |
rmescend--; |
rmescend--; |
692 |
str = stackblock() + strloc; |
str = stackblock() + strloc; |
693 |
preglob(str, varflags & VSQUOTE, 0); |
preglob(str, 0); |
694 |
|
|
695 |
/* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ |
/* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ |
696 |
zero = subtype >> 1; |
zero = subtype >> 1; |
726 |
int startloc; |
int startloc; |
727 |
ssize_t varlen; |
ssize_t varlen; |
728 |
int easy; |
int easy; |
|
int quotes; |
|
729 |
int quoted; |
int quoted; |
730 |
|
|
|
quotes = flag & QUOTES_ESC; |
|
731 |
varflags = *p++; |
varflags = *p++; |
732 |
subtype = varflags & VSTYPE; |
subtype = varflags & VSTYPE; |
733 |
quoted = varflags & VSQUOTE; |
|
734 |
|
if (!subtype) |
735 |
|
sh_error("Bad substitution"); |
736 |
|
|
737 |
|
quoted = flag & EXP_QUOTED; |
738 |
var = p; |
var = p; |
739 |
easy = (!quoted || (*var == '@' && shellparam.nparam)); |
easy = (!quoted || (*var == '@' && shellparam.nparam)); |
740 |
startloc = expdest - (char *)stackblock(); |
startloc = expdest - (char *)stackblock(); |
753 |
if (subtype == VSMINUS) { |
if (subtype == VSMINUS) { |
754 |
vsplus: |
vsplus: |
755 |
if (varlen < 0) { |
if (varlen < 0) { |
756 |
argstr( |
argstr(p, flag | EXP_TILDE | EXP_WORD); |
|
p, flag | EXP_TILDE | |
|
|
(quoted ? EXP_QWORD : EXP_WORD) |
|
|
); |
|
757 |
goto end; |
goto end; |
758 |
} |
} |
759 |
if (easy) |
if (easy) |
764 |
if (subtype == VSASSIGN || subtype == VSQUESTION) { |
if (subtype == VSASSIGN || subtype == VSQUESTION) { |
765 |
if (varlen < 0) { |
if (varlen < 0) { |
766 |
if (subevalvar(p, var, 0, subtype, startloc, |
if (subevalvar(p, var, 0, subtype, startloc, |
767 |
varflags, 0)) { |
varflags, flag & ~QUOTES_ESC)) { |
768 |
varflags &= ~VSNUL; |
varflags &= ~VSNUL; |
769 |
/* |
/* |
770 |
* Remove any recorded regions beyond |
* Remove any recorded regions beyond |
816 |
STPUTC('\0', expdest); |
STPUTC('\0', expdest); |
817 |
patloc = expdest - (char *)stackblock(); |
patloc = expdest - (char *)stackblock(); |
818 |
if (subevalvar(p, NULL, patloc, subtype, |
if (subevalvar(p, NULL, patloc, subtype, |
819 |
startloc, varflags, quotes) == 0) { |
startloc, varflags, flag) == 0) { |
820 |
int amount = expdest - ( |
int amount = expdest - ( |
821 |
(char *)stackblock() + patloc - 1 |
(char *)stackblock() + patloc - 1 |
822 |
); |
); |
833 |
for (;;) { |
for (;;) { |
834 |
if ((c = (signed char)*p++) == CTLESC) |
if ((c = (signed char)*p++) == CTLESC) |
835 |
p++; |
p++; |
836 |
else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { |
else if (c == CTLBACKQ) { |
837 |
if (varlen >= 0) |
if (varlen >= 0) |
838 |
argbackq = argbackq->next; |
argbackq = argbackq->next; |
839 |
} else if (c == CTLVAR) { |
} else if (c == CTLVAR) { |
866 |
int c = (signed char)*p++; |
int c = (signed char)*p++; |
867 |
if (c) { |
if (c) { |
868 |
if ((quotes & QUOTES_ESC) && |
if ((quotes & QUOTES_ESC) && |
869 |
(syntax[c] == CCTL || syntax[c] == CBACK)) |
((syntax[c] == CCTL) || |
870 |
|
(((quotes & EXP_FULL) || syntax != BASESYNTAX) && |
871 |
|
syntax[c] == CBACK))) |
872 |
USTPUTC(CTLESC, q); |
USTPUTC(CTLESC, q); |
873 |
} else if (!(quotes & QUOTES_KEEPNUL)) |
} else if (!(quotes & QUOTES_KEEPNUL)) |
874 |
continue; |
continue; |
906 |
char sepc; |
char sepc; |
907 |
char **ap; |
char **ap; |
908 |
char const *syntax; |
char const *syntax; |
909 |
int quoted = varflags & VSQUOTE; |
int quoted = flags & EXP_QUOTED; |
910 |
int subtype = varflags & VSTYPE; |
int subtype = varflags & VSTYPE; |
911 |
int discard = subtype == VSPLUS || subtype == VSLENGTH; |
int discard = subtype == VSPLUS || subtype == VSLENGTH; |
912 |
int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; |
int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; |
998 |
* string for IFS characters. |
* string for IFS characters. |
999 |
*/ |
*/ |
1000 |
|
|
1001 |
STATIC void |
void |
1002 |
recordregion(int start, int end, int nulonly) |
recordregion(int start, int end, int nulonly) |
1003 |
{ |
{ |
1004 |
struct ifsregion *ifsp; |
struct ifsregion *ifsp; |
1025 |
* strings to the argument list. The regions of the string to be |
* strings to the argument list. The regions of the string to be |
1026 |
* searched for IFS characters have been stored by recordregion. |
* searched for IFS characters have been stored by recordregion. |
1027 |
*/ |
*/ |
1028 |
STATIC void |
void |
1029 |
ifsbreakup(char *string, struct arglist *arglist) |
ifsbreakup(char *string, struct arglist *arglist) |
1030 |
{ |
{ |
1031 |
struct ifsregion *ifsp; |
struct ifsregion *ifsp; |
1135 |
* should be escapes. The results are stored in the list exparg. |
* should be escapes. The results are stored in the list exparg. |
1136 |
*/ |
*/ |
1137 |
|
|
1138 |
#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) |
#ifdef HAVE_GLOB |
1139 |
STATIC void |
STATIC void |
1140 |
expandmeta(str, flag) |
expandmeta(str, flag) |
1141 |
struct strlist *str; |
struct strlist *str; |
1151 |
if (fflag) |
if (fflag) |
1152 |
goto nometa; |
goto nometa; |
1153 |
INTOFF; |
INTOFF; |
1154 |
p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
1155 |
i = glob(p, GLOB_NOMAGIC, 0, &pglob); |
i = glob(p, GLOB_NOMAGIC, 0, &pglob); |
1156 |
if (p != str->text) |
if (p != str->text) |
1157 |
ckfree(p); |
ckfree(p); |
1196 |
} |
} |
1197 |
|
|
1198 |
|
|
1199 |
#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ |
#else /* HAVE_GLOB */ |
1200 |
STATIC char *expdir; |
STATIC char *expdir; |
1201 |
|
|
1202 |
|
|
1220 |
savelastp = exparg.lastp; |
savelastp = exparg.lastp; |
1221 |
|
|
1222 |
INTOFF; |
INTOFF; |
1223 |
p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
1224 |
{ |
{ |
1225 |
int i = strlen(str->text); |
int i = strlen(str->text); |
1226 |
expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ |
expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ |
1268 |
struct dirent *dp; |
struct dirent *dp; |
1269 |
int atend; |
int atend; |
1270 |
int matchdot; |
int matchdot; |
1271 |
|
int esc; |
1272 |
|
|
1273 |
metaflag = 0; |
metaflag = 0; |
1274 |
start = name; |
start = name; |
1275 |
for (p = name; *p; p++) { |
for (p = name; esc = 0, *p; p += esc + 1) { |
1276 |
if (*p == '*' || *p == '?') |
if (*p == '*' || *p == '?') |
1277 |
metaflag = 1; |
metaflag = 1; |
1278 |
else if (*p == '[') { |
else if (*p == '[') { |
1289 |
break; |
break; |
1290 |
} |
} |
1291 |
} |
} |
1292 |
} else if (*p == '\\') |
} else { |
1293 |
p++; |
if (*p == '\\') |
1294 |
else if (*p == '/') { |
esc++; |
1295 |
if (metaflag) |
if (p[esc] == '/') { |
1296 |
goto out; |
if (metaflag) |
1297 |
start = p + 1; |
break; |
1298 |
|
start = p + esc + 1; |
1299 |
|
} |
1300 |
} |
} |
1301 |
} |
} |
|
out: |
|
1302 |
if (metaflag == 0) { /* we've reached the end of the file name */ |
if (metaflag == 0) { /* we've reached the end of the file name */ |
1303 |
if (enddir != expdir) |
if (enddir != expdir) |
1304 |
metaflag++; |
metaflag++; |
1337 |
atend = 1; |
atend = 1; |
1338 |
} else { |
} else { |
1339 |
atend = 0; |
atend = 0; |
1340 |
*endname++ = '\0'; |
*endname = '\0'; |
1341 |
|
endname += esc + 1; |
1342 |
} |
} |
1343 |
matchdot = 0; |
matchdot = 0; |
1344 |
p = start; |
p = start; |
1364 |
} |
} |
1365 |
closedir(dirp); |
closedir(dirp); |
1366 |
if (! atend) |
if (! atend) |
1367 |
endname[-1] = '/'; |
endname[-esc - 1] = esc ? '\\' : '/'; |
1368 |
} |
} |
1369 |
#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ |
#endif /* HAVE_GLOB */ |
1370 |
|
|
1371 |
|
|
1372 |
/* |
/* |
1385 |
} |
} |
1386 |
|
|
1387 |
|
|
1388 |
#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) |
#ifndef HAVE_GLOB |
1389 |
/* |
/* |
1390 |
* Sort the results of file name expansion. It calculates the number of |
* Sort the results of file name expansion. It calculates the number of |
1391 |
* strings to sort and then calls msort (short for merge sort) to do the |
* strings to sort and then calls msort (short for merge sort) to do the |
1454 |
STATIC inline int |
STATIC inline int |
1455 |
patmatch(char *pattern, const char *string) |
patmatch(char *pattern, const char *string) |
1456 |
{ |
{ |
1457 |
return pmatch(preglob(pattern, 0, 0), string); |
return pmatch(preglob(pattern, 0), string); |
1458 |
} |
} |
1459 |
|
|
1460 |
|
|
1461 |
#if !defined(__GLIBC__) || defined(FNMATCH_BROKEN) |
#ifndef HAVE_FNMATCH |
1462 |
STATIC int ccmatch(const char *p, int chr, const char **r) |
STATIC int ccmatch(const char *p, int chr, const char **r) |
1463 |
{ |
{ |
1464 |
static const struct class { |
static const struct class { |
1619 |
size_t fulllen = len + strlen(p) + 1; |
size_t fulllen = len + strlen(p) + 1; |
1620 |
|
|
1621 |
if (flag & RMESCAPE_GROW) { |
if (flag & RMESCAPE_GROW) { |
1622 |
|
int strloc = str - (char *)stackblock(); |
1623 |
|
|
1624 |
r = makestrspace(fulllen, expdest); |
r = makestrspace(fulllen, expdest); |
1625 |
|
str = (char *)stackblock() + strloc; |
1626 |
|
p = str + len; |
1627 |
} else if (flag & RMESCAPE_HEAP) { |
} else if (flag & RMESCAPE_HEAP) { |
1628 |
r = ckmalloc(fulllen); |
r = ckmalloc(fulllen); |
1629 |
} else { |
} else { |
1634 |
q = mempcpy(q, str, len); |
q = mempcpy(q, str, len); |
1635 |
} |
} |
1636 |
} |
} |
1637 |
inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; |
inquotes = 0; |
1638 |
globbing = flag & RMESCAPE_GLOB; |
globbing = flag & RMESCAPE_GLOB; |
1639 |
notescaped = globbing; |
notescaped = globbing; |
1640 |
while (*p) { |
while (*p) { |
1644 |
notescaped = globbing; |
notescaped = globbing; |
1645 |
continue; |
continue; |
1646 |
} |
} |
|
if (*p == '\\') { |
|
|
/* naked back slash */ |
|
|
notescaped = 0; |
|
|
goto copy; |
|
|
} |
|
1647 |
if (*p == (char)CTLESC) { |
if (*p == (char)CTLESC) { |
1648 |
p++; |
p++; |
1649 |
if (notescaped && inquotes && *p != '/') { |
if (notescaped) |
1650 |
*q++ = '\\'; |
*q++ = '\\'; |
1651 |
} |
} else if (*p == '\\' && !inquotes) { |
1652 |
|
/* naked back slash */ |
1653 |
|
notescaped = 0; |
1654 |
|
goto copy; |
1655 |
} |
} |
1656 |
notescaped = globbing; |
notescaped = globbing; |
1657 |
copy: |
copy: |
1693 |
*/ |
*/ |
1694 |
|
|
1695 |
STATIC int |
STATIC int |
1696 |
cvtnum(long num) |
cvtnum(intmax_t num) |
1697 |
{ |
{ |
1698 |
int len; |
int len = max_int_length(sizeof(num)); |
1699 |
|
|
1700 |
expdest = makestrspace(32, expdest); |
expdest = makestrspace(len, expdest); |
1701 |
len = fmtstr(expdest, 32, "%ld", num); |
len = fmtstr(expdest, len, "%jd", num); |
1702 |
STADJUST(len, expdest); |
STADJUST(len, expdest); |
1703 |
return len; |
return len; |
1704 |
} |
} |