wordexp.c 2.1 KB

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