summaryrefslogtreecommitdiffstats
path: root/bin/sh/expand.c
diff options
context:
space:
mode:
authorgrehan <grehan@FreeBSD.org>2011-06-28 06:26:03 +0000
committergrehan <grehan@FreeBSD.org>2011-06-28 06:26:03 +0000
commit2c6741be0f59191f2283eb268e4f7690399d578a (patch)
treeb139c8c6dcca4fa284815daade405b75886ee360 /bin/sh/expand.c
parent3c35264f695e0a1f8a04dbcca1c93bb5159b2274 (diff)
parent19ae02bba572390c7299166228d31e54003e094a (diff)
downloadFreeBSD-src-2c6741be0f59191f2283eb268e4f7690399d578a.zip
FreeBSD-src-2c6741be0f59191f2283eb268e4f7690399d578a.tar.gz
IFC @ r222830
Diffstat (limited to 'bin/sh/expand.c')
-rw-r--r--bin/sh/expand.c127
1 files changed, 48 insertions, 79 deletions
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index b3c4962..ea8d78d 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include <wchar.h>
+#include <wctype.h>
/*
* Routines to expand arguments to commands. We have to deal with
@@ -76,6 +77,7 @@ __FBSDID("$FreeBSD$");
#include "mystring.h"
#include "arith.h"
#include "show.h"
+#include "builtins.h"
/*
* Structure specifying which parts of the string should be searched
@@ -174,6 +176,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
ifslastp = NULL;
argstr(arg->narg.text, flag);
if (arglist == NULL) {
+ STACKSTRNUL(expdest);
return; /* here document expanded */
}
STPUTC('\0', expdest);
@@ -761,7 +764,8 @@ again: /* jump here after setting a variable with ${var=text} */
break;
record:
recordregion(startloc, expdest - stackblock(),
- varflags & VSQUOTE);
+ varflags & VSQUOTE || (ifsset() && ifsval()[0] == '\0' &&
+ (*var == '@' || *var == '*')));
break;
case VSPLUS:
@@ -947,7 +951,9 @@ numvar:
sep = ' ';
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
strtodest(p, flag, subtype, quoted);
- if (*ap && sep)
+ if (!*ap)
+ break;
+ if (sep || (flag & EXP_FULL && !quoted && **ap != '\0'))
STPUTC(sep, expdest);
}
break;
@@ -1396,13 +1402,43 @@ get_wc(const char **p)
/*
+ * See if a character matches a character class, starting at the first colon
+ * of "[:class:]".
+ * If a valid character class is recognized, a pointer to the next character
+ * after the final closing bracket is stored into *end, otherwise a null
+ * pointer is stored into *end.
+ */
+static int
+match_charclass(const char *p, wchar_t chr, const char **end)
+{
+ char name[20];
+ const char *nameend;
+ wctype_t cclass;
+
+ *end = NULL;
+ p++;
+ nameend = strstr(p, ":]");
+ if (nameend == NULL || nameend - p >= sizeof(name) || nameend == p)
+ return 0;
+ memcpy(name, p, nameend - p);
+ name[nameend - p] = '\0';
+ *end = nameend + 2;
+ cclass = wctype(name);
+ /* An unknown class matches nothing but is valid nevertheless. */
+ if (cclass == 0)
+ return 0;
+ return iswctype(chr, cclass);
+}
+
+
+/*
* Returns true if the pattern matches the string.
*/
int
patmatch(const char *pattern, const char *string, int squoted)
{
- const char *p, *q;
+ const char *p, *q, *end;
char c;
wchar_t wc, wc2;
@@ -1426,7 +1462,7 @@ patmatch(const char *pattern, const char *string, int squoted)
if (localeisutf8)
wc = get_wc(&q);
else
- wc = *q++;
+ wc = (unsigned char)*q++;
if (wc == '\0')
return 0;
break;
@@ -1483,13 +1519,18 @@ patmatch(const char *pattern, const char *string, int squoted)
if (localeisutf8)
chr = get_wc(&q);
else
- chr = *q++;
+ chr = (unsigned char)*q++;
if (chr == '\0')
return 0;
c = *p++;
do {
if (c == CTLQUOTEMARK)
continue;
+ if (c == '[' && *p == ':') {
+ found |= match_charclass(p, chr, &end);
+ if (end != NULL)
+ p = end;
+ }
if (c == CTLESC)
c = *p++;
if (localeisutf8 && c & 0x80) {
@@ -1498,7 +1539,7 @@ patmatch(const char *pattern, const char *string, int squoted)
if (wc == 0) /* bad utf-8 */
return 0;
} else
- wc = c;
+ wc = (unsigned char)c;
if (*p == '-' && p[1] != ']') {
p++;
while (*p == CTLQUOTEMARK)
@@ -1510,7 +1551,7 @@ patmatch(const char *pattern, const char *string, int squoted)
if (wc2 == 0) /* bad utf-8 */
return 0;
} else
- wc2 = *p++;
+ wc2 = (unsigned char)*p++;
if ( collate_range_cmp(chr, wc) >= 0
&& collate_range_cmp(chr, wc2) <= 0
)
@@ -1617,78 +1658,6 @@ cvtnum(int num, char *buf)
}
/*
- * Check statically if expanding a string may have side effects.
- */
-int
-expandhassideeffects(const char *p)
-{
- int c;
- int arinest;
-
- arinest = 0;
- while ((c = *p++) != '\0') {
- switch (c) {
- case CTLESC:
- p++;
- break;
- case CTLVAR:
- c = *p++;
- /* Expanding $! sets the job to remembered. */
- if (*p == '!')
- return 1;
- if ((c & VSTYPE) == VSASSIGN)
- return 1;
- /*
- * If we are in arithmetic, the parameter may contain
- * '=' which may cause side effects. Exceptions are
- * the length of a parameter and $$, $# and $? which
- * are always numeric.
- */
- if ((c & VSTYPE) == VSLENGTH) {
- while (*p != '=')
- p++;
- p++;
- break;
- }
- if ((*p == '$' || *p == '#' || *p == '?') &&
- p[1] == '=') {
- p += 2;
- break;
- }
- if (arinest > 0)
- return 1;
- break;
- case CTLBACKQ:
- case CTLBACKQ | CTLQUOTE:
- if (arinest > 0)
- return 1;
- break;
- case CTLARI:
- arinest++;
- break;
- case CTLENDARI:
- arinest--;
- break;
- case '=':
- if (*p == '=') {
- /* Allow '==' operator. */
- p++;
- continue;
- }
- if (arinest > 0)
- return 1;
- break;
- case '!': case '<': case '>':
- /* Allow '!=', '<=', '>=' operators. */
- if (*p == '=')
- p++;
- break;
- }
- }
- return 0;
-}
-
-/*
* Do most of the work for wordexp(3).
*/
OpenPOWER on IntegriCloud