mirror of https://git.musl-libc.org/git/musl
1 changed files with 128 additions and 0 deletions
@ -0,0 +1,128 @@ |
|||
#include <wordexp.h> |
|||
#include <unistd.h> |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include <limits.h> |
|||
#include <stdint.h> |
|||
#include <stdlib.h> |
|||
|
|||
static char *getword(FILE *f) |
|||
{ |
|||
char *s = 0; |
|||
return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s; |
|||
} |
|||
|
|||
int wordexp(const char *s, wordexp_t *we, int flags) |
|||
{ |
|||
size_t i, l, len; |
|||
int sq=0, dq=0; |
|||
size_t np=0; |
|||
char *cmd, *w, **tmp; |
|||
char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null"; |
|||
int err = 0, status; |
|||
FILE *f; |
|||
size_t wc = 0; |
|||
char **wv = 0; |
|||
|
|||
if (flags & WRDE_REUSE) wordfree(we); |
|||
|
|||
if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) { |
|||
case '\\': |
|||
if (!sq) i++; |
|||
break; |
|||
case '\'': |
|||
if (!dq) sq^=1; |
|||
break; |
|||
case '"': |
|||
if (!sq) dq^=1; |
|||
break; |
|||
case '(': |
|||
if (np) { |
|||
np++; |
|||
break; |
|||
} |
|||
case ')': |
|||
if (np) { |
|||
np--; |
|||
break; |
|||
} |
|||
case '\n': |
|||
case '|': |
|||
case '&': |
|||
case ';': |
|||
case '<': |
|||
case '>': |
|||
case '{': |
|||
case '}': |
|||
if (!(sq|dq|np)) return WRDE_BADCHAR; |
|||
break; |
|||
case '$': |
|||
if (s[i+1]=='(' && s[i+2]=='(') { |
|||
i += 2; |
|||
np += 2; |
|||
break; |
|||
} else if (s[i+1] != '(') break; |
|||
case '`': |
|||
if (sq) break; |
|||
return WRDE_CMDSUB; |
|||
} |
|||
|
|||
if (flags & WRDE_APPEND) { |
|||
wc = we->we_wordc; |
|||
wv = we->we_wordv; |
|||
} |
|||
|
|||
i = wc; |
|||
if (flags & WRDE_DOOFFS) { |
|||
if (we->we_offs > SIZE_MAX/sizeof(void *)/4) |
|||
return WRDE_NOSPACE; |
|||
i += we->we_offs; |
|||
} |
|||
|
|||
len = 50 + strlen(s); |
|||
cmd = malloc(len); |
|||
if (!cmd) return WRDE_NOSPACE; |
|||
snprintf(cmd, len, "printf %%s\\\\0 %s %s", s, redir); |
|||
printf("{%s}\n", cmd); |
|||
f = popen(cmd, "r"); |
|||
free(cmd); |
|||
if (!f) return WRDE_NOSPACE; |
|||
|
|||
l = wv ? i+1 : 0; |
|||
|
|||
while ((w = getword(f))) { |
|||
if (i+1 >= l) { |
|||
l += l/2+10; |
|||
tmp = realloc(wv, l*sizeof(char *)); |
|||
if (!tmp) break; |
|||
wv = tmp; |
|||
} |
|||
wv[i++] = w; |
|||
wv[i] = 0; |
|||
} |
|||
if (!feof(f)) err = WRDE_NOSPACE; |
|||
|
|||
status = pclose(f); |
|||
if (WEXITSTATUS(status)) { |
|||
if (!(flags & WRDE_APPEND)) { |
|||
free(wv); |
|||
return WRDE_SYNTAX; |
|||
} else if (wv==we->we_wordv) { |
|||
return WRDE_SYNTAX; |
|||
} |
|||
} |
|||
|
|||
we->we_wordv = wv; |
|||
we->we_wordc = i - we->we_offs; |
|||
return err; |
|||
} |
|||
|
|||
void wordfree(wordexp_t *we) |
|||
{ |
|||
size_t i; |
|||
if (!we->we_wordv) return; |
|||
for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]); |
|||
free(we->we_wordv); |
|||
we->we_wordv = 0; |
|||
we->we_wordc = 0; |
|||
} |
|||
Loading…
Reference in new issue