summaryrefslogtreecommitdiffstats
path: root/bin/sh/expand.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/sh/expand.c')
-rw-r--r--bin/sh/expand.c215
1 files changed, 74 insertions, 141 deletions
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index 88d80ea..567b8a4 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -96,7 +96,6 @@ static char *expdest; /* output of current string */
static struct nodelist *argbackq; /* list of back quote expressions */
static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
static struct ifsregion *ifslastp; /* last struct in list */
-static struct arglist exparg; /* holds expanded arg list */
static char *argstr(char *, int);
static char *exptilde(char *, int);
@@ -110,15 +109,43 @@ static void varvalue(const char *, int, int, int);
static void recordregion(int, int, int);
static void removerecordregions(int);
static void ifsbreakup(char *, struct arglist *);
-static void expandmeta(struct strlist *);
-static void expmeta(char *, char *);
-static void addfname(char *);
-static struct strlist *expsort(struct strlist *);
-static struct strlist *msort(struct strlist *, int);
+static void expandmeta(struct arglist *, struct arglist *);
+static void expmeta(char *, char *, struct arglist *);
+static int expsortcmp(const void *, const void *);
static int patmatch(const char *, const char *, int);
static char *cvtnum(int, char *);
+static void appendarglist(struct arglist *, char *);
static int collate_range_cmp(wchar_t, wchar_t);
+void
+emptyarglist(struct arglist *list)
+{
+
+ list->args = list->smallarg;
+ list->count = 0;
+ list->capacity = sizeof(list->smallarg) / sizeof(list->smallarg[0]);
+}
+
+static void
+appendarglist(struct arglist *list, char *str)
+{
+ char **newargs;
+ int newcapacity;
+
+ if (list->count >= list->capacity) {
+ newcapacity = list->capacity * 2;
+ if (newcapacity < 16)
+ newcapacity = 16;
+ if (newcapacity > INT_MAX / (int)sizeof(newargs[0]))
+ error("Too many entries in arglist");
+ newargs = stalloc(newcapacity * sizeof(newargs[0]));
+ memcpy(newargs, list->args, list->count * sizeof(newargs[0]));
+ list->args = newargs;
+ list->capacity = newcapacity;
+ }
+ list->args[list->count++] = str;
+}
+
static int
collate_range_cmp(wchar_t c1, wchar_t c2)
{
@@ -157,7 +184,7 @@ stputs_quotes(const char *data, const char *syntax, char *p)
void
expandarg(union node *arg, struct arglist *arglist, int flag)
{
- struct strlist *sp;
+ struct arglist exparg;
char *p;
argbackq = arg->narg.backquote;
@@ -171,18 +198,12 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
}
STPUTC('\0', expdest);
p = grabstackstr(expdest);
- exparg.lastp = &exparg.list;
+ emptyarglist(&exparg);
if (flag & EXP_FULL) {
ifsbreakup(p, &exparg);
- *exparg.lastp = NULL;
- exparg.lastp = &exparg.list;
- expandmeta(exparg.list);
- } else {
- sp = (struct strlist *)stalloc(sizeof (struct strlist));
- sp->text = p;
- *exparg.lastp = sp;
- exparg.lastp = &sp->next;
- }
+ expandmeta(&exparg, arglist);
+ } else
+ appendarglist(arglist, p);
while (ifsfirst.next != NULL) {
struct ifsregion *ifsp;
INTOFF;
@@ -191,11 +212,6 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
ifsfirst.next = ifsp;
INTON;
}
- *exparg.lastp = NULL;
- if (exparg.list) {
- *arglist->lastp = exparg.list;
- arglist->lastp = exparg.lastp;
- }
}
@@ -984,7 +1000,6 @@ static void
ifsbreakup(char *string, struct arglist *arglist)
{
struct ifsregion *ifsp;
- struct strlist *sp;
char *start;
char *p;
char *q;
@@ -996,10 +1011,7 @@ ifsbreakup(char *string, struct arglist *arglist)
if (ifslastp == NULL) {
/* Return entire argument, IFS doesn't apply to any of it */
- sp = (struct strlist *)stalloc(sizeof *sp);
- sp->text = start;
- *arglist->lastp = sp;
- arglist->lastp = &sp->next;
+ appendarglist(arglist, start);
return;
}
@@ -1038,10 +1050,7 @@ ifsbreakup(char *string, struct arglist *arglist)
/* Save this argument... */
*q = '\0';
- sp = (struct strlist *)stalloc(sizeof *sp);
- sp->text = start;
- *arglist->lastp = sp;
- arglist->lastp = &sp->next;
+ appendarglist(arglist, start);
p++;
if (ifsspc != NULL) {
@@ -1071,12 +1080,8 @@ ifsbreakup(char *string, struct arglist *arglist)
* Some recent clarification of the Posix spec say that it
* should only generate one....
*/
- if (had_param_ch || *start != 0) {
- sp = (struct strlist *)stalloc(sizeof *sp);
- sp->text = start;
- *arglist->lastp = sp;
- arglist->lastp = &sp->next;
- }
+ if (had_param_ch || *start != 0)
+ appendarglist(arglist, start);
}
@@ -1086,45 +1091,42 @@ static char expdir[PATH_MAX];
/*
* Perform pathname generation and remove control characters.
* At this point, the only control characters should be CTLESC and CTLQUOTEMARK.
- * The results are stored in the list exparg.
+ * The results are stored in the list dstlist.
*/
static void
-expandmeta(struct strlist *str)
+expandmeta(struct arglist *srclist, struct arglist *dstlist)
{
char *p;
- struct strlist **savelastp;
- struct strlist *sp;
+ int firstmatch;
+ int i;
char c;
- while (str) {
- savelastp = exparg.lastp;
+ for (i = 0; i < srclist->count; i++) {
+ firstmatch = dstlist->count;
if (!fflag) {
- p = str->text;
+ p = srclist->args[i];
for (; (c = *p) != '\0'; p++) {
/* fast check for meta chars */
if (c == '*' || c == '?' || c == '[') {
INTOFF;
- expmeta(expdir, str->text);
+ expmeta(expdir, srclist->args[i],
+ dstlist);
INTON;
break;
}
}
}
- if (exparg.lastp == savelastp) {
+ if (dstlist->count == firstmatch) {
/*
* no matches
*/
- *exparg.lastp = str;
- rmescapes(str->text);
- exparg.lastp = &str->next;
+ rmescapes(srclist->args[i]);
+ appendarglist(dstlist, srclist->args[i]);
} else {
- *exparg.lastp = NULL;
- *savelastp = sp = expsort(*savelastp);
- while (sp->next != NULL)
- sp = sp->next;
- exparg.lastp = &sp->next;
+ qsort(&dstlist->args[firstmatch],
+ dstlist->count - firstmatch,
+ sizeof(dstlist->args[0]), expsortcmp);
}
- str = str->next;
}
}
@@ -1134,7 +1136,7 @@ expandmeta(struct strlist *str)
*/
static void
-expmeta(char *enddir, char *name)
+expmeta(char *enddir, char *name, struct arglist *arglist)
{
const char *p;
const char *q;
@@ -1199,7 +1201,7 @@ expmeta(char *enddir, char *name)
return;
}
if (metaflag == 0 || lstat(expdir, &statb) >= 0)
- addfname(expdir);
+ appendarglist(arglist, stsavestr(expdir));
return;
}
endname = name + (p - name);
@@ -1251,7 +1253,7 @@ expmeta(char *enddir, char *name)
continue;
memcpy(enddir, dp->d_name, namlen + 1);
if (atend)
- addfname(expdir);
+ appendarglist(arglist, stsavestr(expdir));
else {
if (dp->d_type != DT_UNKNOWN &&
dp->d_type != DT_DIR &&
@@ -1261,7 +1263,7 @@ expmeta(char *enddir, char *name)
continue;
enddir[namlen] = '/';
enddir[namlen + 1] = '\0';
- expmeta(enddir + namlen + 1, endname);
+ expmeta(enddir + namlen + 1, endname, arglist);
}
}
}
@@ -1271,81 +1273,13 @@ expmeta(char *enddir, char *name)
}
-/*
- * Add a file name to the list.
- */
-
-static void
-addfname(char *name)
-{
- char *p;
- struct strlist *sp;
-
- p = stsavestr(name);
- sp = (struct strlist *)stalloc(sizeof *sp);
- sp->text = p;
- *exparg.lastp = sp;
- exparg.lastp = &sp->next;
-}
-
-
-/*
- * Sort the results of file name expansion. It calculates the number of
- * strings to sort and then calls msort (short for merge sort) to do the
- * work.
- */
-
-static struct strlist *
-expsort(struct strlist *str)
+static int
+expsortcmp(const void *p1, const void *p2)
{
- int len;
- struct strlist *sp;
-
- len = 0;
- for (sp = str ; sp ; sp = sp->next)
- len++;
- return msort(str, len);
-}
+ const char *s1 = *(const char * const *)p1;
+ const char *s2 = *(const char * const *)p2;
-
-static struct strlist *
-msort(struct strlist *list, int len)
-{
- struct strlist *p, *q = NULL;
- struct strlist **lpp;
- int half;
- int n;
-
- if (len <= 1)
- return list;
- half = len >> 1;
- p = list;
- for (n = half ; --n >= 0 ; ) {
- q = p;
- p = p->next;
- }
- q->next = NULL; /* terminate first half of list */
- q = msort(list, half); /* sort first half of list */
- p = msort(p, len - half); /* sort second half */
- lpp = &list;
- for (;;) {
- if (strcmp(p->text, q->text) < 0) {
- *lpp = p;
- lpp = &p->next;
- if ((p = *lpp) == NULL) {
- *lpp = q;
- break;
- }
- } else {
- *lpp = q;
- lpp = &q->next;
- if ((q = *lpp) == NULL) {
- *lpp = p;
- break;
- }
- }
- }
- return list;
+ return (strcmp(s1, s2));
}
@@ -1666,11 +1600,11 @@ freebsd_wordexpcmd(int argc __unused, char **argv __unused)
{
struct arglist arglist;
union node *args, *n;
- struct strlist *sp;
- size_t count, len;
+ size_t len;
int ch;
int protected = 0;
int fd = -1;
+ int i;
while ((ch = nextopt("f:p")) != '\0') {
switch (ch) {
@@ -1699,14 +1633,13 @@ freebsd_wordexpcmd(int argc __unused, char **argv __unused)
}
}
outcslow(' ', out1);
- arglist.lastp = &arglist.list;
+ emptyarglist(&arglist);
for (n = args; n != NULL; n = n->narg.next)
expandarg(n, &arglist, EXP_FULL | EXP_TILDE);
- *arglist.lastp = NULL;
- for (sp = arglist.list, count = len = 0; sp; sp = sp->next)
- count++, len += strlen(sp->text);
- out1fmt("%016zx %016zx", count, len);
- for (sp = arglist.list; sp; sp = sp->next)
- outbin(sp->text, strlen(sp->text) + 1, out1);
+ for (i = 0, len = 0; i < arglist.count; i++)
+ len += strlen(arglist.args[i]);
+ out1fmt("%016x %016zx", arglist.count, len);
+ for (i = 0; i < arglist.count; i++)
+ outbin(arglist.args[i], strlen(arglist.args[i]) + 1, out1);
return (0);
}
OpenPOWER on IntegriCloud