summaryrefslogtreecommitdiff
path: root/process.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-06-13 00:56:31 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-06-13 00:56:31 +0000
commit2d460925f2e5beb24fb19dc4b0a07ce1598dac60 (patch)
tree68cba742f6a4045aa1000749a58427617abf157f /process.c
parente6a6561121ef4475a0fd136524983bb22afbb3dc (diff)
process.c: use shell for reserved or special built-in
* process.c (rb_exec_fillarg): use shell if the first word is reserved or special built-in name. http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36049 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'process.c')
-rw-r--r--process.c80
1 files changed, 70 insertions, 10 deletions
diff --git a/process.c b/process.c
index a0ea94ec85..48a26ded18 100644
--- a/process.c
+++ b/process.c
@@ -79,6 +79,8 @@
#include <grp.h>
#endif
+#define numberof(array) (int)(sizeof(array)/sizeof((array)[0]))
+
#if defined(HAVE_TIMES) || defined(_WIN32)
static VALUE rb_cProcessTms;
#endif
@@ -1824,6 +1826,20 @@ rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, V
return prog;
}
+struct string_part {
+ const char *ptr;
+ size_t len;
+};
+
+static int
+compare_posix_sh(const void *key, const void *el)
+{
+ const struct string_part *word = key;
+ int ret = strncmp(word->ptr, el, word->len);
+ if (!ret && ((const char *)el)[word->len]) ret = -1;
+ return ret;
+}
+
static void
rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, struct rb_exec_arg *e)
{
@@ -1850,10 +1866,40 @@ rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, str
#ifndef _WIN32
if (e->use_shell) {
+ static const char posix_sh_cmds[][8] = {
+ "!", /* reserved */
+ ".", /* special built-in */
+ "break", /* special built-in */
+ "case", /* reserved */
+ "colon", /* special built-in */
+ "continue", /* special built-in */
+ "do", /* reserved */
+ "done", /* reserved */
+ "elif", /* reserved */
+ "else", /* reserved */
+ "esac", /* reserved */
+ "eval", /* special built-in */
+ "exec", /* special built-in */
+ "exit", /* special built-in */
+ "export", /* special built-in */
+ "fi", /* reserved */
+ "for", /* reserved */
+ "if", /* reserved */
+ "in", /* reserved */
+ "readonly", /* special built-in */
+ "return", /* special built-in */
+ "set", /* special built-in */
+ "shift", /* special built-in */
+ "then", /* reserved */
+ "times", /* special built-in */
+ "trap", /* special built-in */
+ "unset", /* special built-in */
+ "until", /* reserved */
+ "while", /* reserved */
+ };
const char *p;
- int first = 1;
+ struct string_part first = {0, 0};
int has_meta = 0;
- int has_nonspace = 0;
/*
* meta characters:
*
@@ -1879,18 +1925,32 @@ rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, str
* % (used in Parameter Expansion)
*/
for (p = RSTRING_PTR(prog); *p; p++) {
- if (!has_nonspace && *p != ' ' && *p != '\t')
- has_nonspace = 1;
- if (has_nonspace && (*p == ' ' || *p == '\t'))
- first = 0;
+ if (*p == ' ' || *p == '\t') {
+ if (first.ptr && !first.len) first.len = p - first.ptr;
+ }
+ else {
+ if (!first.ptr) first.ptr = p;
+ }
if (!has_meta && strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p))
has_meta = 1;
- if (first && *p == '=')
- has_meta = 1;
- if (has_nonspace && has_meta)
+ if (!first.len) {
+ if (*p == '=') {
+ has_meta = 1;
+ }
+ else if (*p == '/') {
+ first.len = SIZE_T_MAX; /* longer than any posix_sh_cmds */
+ }
+ }
+ if (has_meta)
break;
}
- if (has_nonspace && !has_meta) {
+ if (!has_meta && first.ptr) {
+ if (!first.len) first.len = p - first.ptr;
+ if (first.len > 0 && first.len <= sizeof(posix_sh_cmds[0]) &&
+ bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds), sizeof(posix_sh_cmds[0]), compare_posix_sh))
+ has_meta = 1;
+ }
+ if (!has_meta) {
/* avoid shell since no shell meta charactor found. */
e->use_shell = 0;
}