remove some stray trailing space characters
[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 #include <sys/wait.h>
9 #include <signal.h>
10 #include <pthread.h>
11
12 static char *getword(FILE *f)
13 {
14         char *s = 0;
15         return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s;
16 }
17
18 static int do_wordexp(const char *s, wordexp_t *we, int flags)
19 {
20         size_t i, l;
21         int sq=0, dq=0;
22         size_t np=0;
23         char *w, **tmp;
24         char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null";
25         int err = 0, status;
26         FILE *f;
27         size_t wc = 0;
28         char **wv = 0;
29         int p[2];
30         pid_t pid;
31
32         if (flags & WRDE_REUSE) wordfree(we);
33
34         if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) {
35         case '\\':
36                 if (!sq) i++;
37                 break;
38         case '\'':
39                 if (!dq) sq^=1;
40                 break;
41         case '"':
42                 if (!sq) dq^=1;
43                 break;
44         case '(':
45                 if (np) {
46                         np++;
47                         break;
48                 }
49         case ')':
50                 if (np) {
51                         np--;
52                         break;
53                 }
54         case '\n':
55         case '|':
56         case '&':
57         case ';':
58         case '<':
59         case '>':
60         case '{':
61         case '}':
62                 if (!(sq|dq|np)) return WRDE_BADCHAR;
63                 break;
64         case '$':
65                 if (s[i+1]=='(' && s[i+2]=='(') {
66                         i += 2;
67                         np += 2;
68                         break;
69                 } else if (s[i+1] != '(') break;
70         case '`':
71                 if (sq) break;
72                 return WRDE_CMDSUB;
73         }
74
75         if (flags & WRDE_APPEND) {
76                 wc = we->we_wordc;
77                 wv = we->we_wordv;
78         }
79
80         i = wc;
81         if (flags & WRDE_DOOFFS) {
82                 if (we->we_offs > SIZE_MAX/sizeof(void *)/4)
83                         return WRDE_NOSPACE;
84                 i += we->we_offs;
85         }
86
87         if (pipe(p) < 0) return WRDE_NOSPACE;
88         pid = fork();
89         if (pid < 0) {
90                 close(p[0]);
91                 close(p[1]);
92                 return WRDE_NOSPACE;
93         }
94         if (!pid) {
95                 dup2(p[1], 1);
96                 close(p[0]);
97                 close(p[1]);
98                 execl("/bin/sh", "sh", "-c",
99                         "eval \"printf %s\\\\\\\\0 $1 $2\"",
100                         "sh", s, redir, (char *)0);
101                 _exit(1);
102         }
103         close(p[1]);
104         
105         f = fdopen(p[0], "r");
106         if (!f) {
107                 close(p[0]);
108                 kill(pid, SIGKILL);
109                 waitpid(pid, &status, 0);
110                 return WRDE_NOSPACE;
111         }
112
113         l = wv ? i+1 : 0;
114
115         while ((w = getword(f))) {
116                 if (i+1 >= l) {
117                         l += l/2+10;
118                         tmp = realloc(wv, l*sizeof(char *));
119                         if (!tmp) break;
120                         wv = tmp;
121                 }
122                 wv[i++] = w;
123                 wv[i] = 0;
124         }
125         if (!feof(f)) err = WRDE_NOSPACE;
126
127         fclose(f);
128         waitpid(pid, &status, 0);
129         if (WEXITSTATUS(status)) {
130                 if (!(flags & WRDE_APPEND)) {
131                         free(wv);
132                         return WRDE_SYNTAX;
133                 } else if (wv==we->we_wordv) {
134                         return WRDE_SYNTAX;
135                 }
136         }
137
138         we->we_wordv = wv;
139         we->we_wordc = i;
140         if (flags & WRDE_DOOFFS) we->we_wordc -= we->we_offs;
141         return err;
142 }
143
144 int wordexp(const char *s, wordexp_t *we, int flags)
145 {
146         int r, cs;
147         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
148         r = do_wordexp(s, we, flags);
149         pthread_setcancelstate(cs, 0);
150         return r;
151 }
152
153 void wordfree(wordexp_t *we)
154 {
155         size_t i;
156         if (!we->we_wordv) return;
157         for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]);
158         free(we->we_wordv);
159         we->we_wordv = 0;
160         we->we_wordc = 0;
161 }