b0d6846fc69376ed2901eaa583eee25576a9b737
[musl] / src / misc / wordexp.c
1 #include <wordexp.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <limits.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8
9 static char *getword(FILE *f)
10 {
11         char *s = 0;
12         return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s;
13 }
14
15 int wordexp(const char *s, wordexp_t *we, int flags)
16 {
17         size_t i, l, len;
18         int sq=0, dq=0;
19         size_t np=0;
20         char *cmd, *w, **tmp;
21         char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null";
22         int err = 0, status;
23         FILE *f;
24         size_t wc = 0;
25         char **wv = 0;
26
27         if (flags & WRDE_REUSE) wordfree(we);
28
29         if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) {
30         case '\\':
31                 if (!sq) i++;
32                 break;
33         case '\'':
34                 if (!dq) sq^=1;
35                 break;
36         case '"':
37                 if (!sq) dq^=1;
38                 break;
39         case '(':
40                 if (np) {
41                         np++;
42                         break;
43                 }
44         case ')':
45                 if (np) {
46                         np--;
47                         break;
48                 }
49         case '\n':
50         case '|':
51         case '&':
52         case ';':
53         case '<':
54         case '>':
55         case '{':
56         case '}':
57                 if (!(sq|dq|np)) return WRDE_BADCHAR;
58                 break;
59         case '$':
60                 if (s[i+1]=='(' && s[i+2]=='(') {
61                         i += 2;
62                         np += 2;
63                         break;
64                 } else if (s[i+1] != '(') break;
65         case '`':
66                 if (sq) break;
67                 return WRDE_CMDSUB;
68         }
69
70         if (flags & WRDE_APPEND) {
71                 wc = we->we_wordc;
72                 wv = we->we_wordv;
73         }
74
75         i = wc;
76         if (flags & WRDE_DOOFFS) {
77                 if (we->we_offs > SIZE_MAX/sizeof(void *)/4)
78                         return WRDE_NOSPACE;
79                 i += we->we_offs;
80         }
81
82         len = 50 + strlen(s);
83         cmd = malloc(len);
84         if (!cmd) return WRDE_NOSPACE;
85         snprintf(cmd, len, "printf %%s\\\\0 %s %s", s, redir);
86 printf("{%s}\n", cmd);
87         f = popen(cmd, "r");
88         free(cmd);
89         if (!f) return WRDE_NOSPACE;
90
91         l = wv ? i+1 : 0;
92
93         while ((w = getword(f))) {
94                 if (i+1 >= l) {
95                         l += l/2+10;
96                         tmp = realloc(wv, l*sizeof(char *));
97                         if (!tmp) break;
98                         wv = tmp;
99                 }
100                 wv[i++] = w;
101                 wv[i] = 0;
102         }
103         if (!feof(f)) err = WRDE_NOSPACE;
104
105         status = pclose(f);
106         if (WEXITSTATUS(status)) {
107                 if (!(flags & WRDE_APPEND)) {
108                         free(wv);
109                         return WRDE_SYNTAX;
110                 } else if (wv==we->we_wordv) {
111                         return WRDE_SYNTAX;
112                 }
113         }
114
115         we->we_wordv = wv;
116         we->we_wordc = i - we->we_offs;
117         return err;
118 }
119
120 void wordfree(wordexp_t *we)
121 {
122         size_t i;
123         if (!we->we_wordv) return;
124         for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]);
125         free(we->we_wordv);
126         we->we_wordv = 0;
127         we->we_wordc = 0;
128 }