summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-12-20 09:28:29 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-12-20 09:28:29 +0000
commit67099c5be4fa1e2ac4c7242751a8cb4d8b707a84 (patch)
treee11ea80c5f938e580fdf12c891c72f2aef7a9a0f
parent0bfc184d742f28920e1de59d0cc09da6cb5a9841 (diff)
downloadruby-67099c5be4fa1e2ac4c7242751a8cb4d8b707a84.tar.gz
ruby-67099c5be4fa1e2ac4c7242751a8cb4d8b707a84.tar.xz
ruby-67099c5be4fa1e2ac4c7242751a8cb4d8b707a84.zip
* dln.c (dln_find_1): supplements an extension for executable
files on DOSish platforms. * io.c (pipe_open): use rb_w32_aspawn() for array form. * win32/win32.c (rb_w32_pipe_exec): no longer used. * win32/win32.c (rb_w32_spawn, rb_w32_aspawn): deals with batch files and commands with extensions. [ruby-core:20695] * win32/win32.c (has_redirection): supports environment variables references. git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@20892 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog15
-rw-r--r--dln.c63
-rw-r--r--io.c16
-rw-r--r--win32/win32.c304
4 files changed, 196 insertions, 202 deletions
diff --git a/ChangeLog b/ChangeLog
index a5e8628fe..e09dfe8a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+Sat Dec 20 18:28:26 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dln.c (dln_find_1): supplements an extension for executable
+ files on DOSish platforms.
+
+ * io.c (pipe_open): use rb_w32_aspawn() for array form.
+
+ * win32/win32.c (rb_w32_pipe_exec): no longer used.
+
+ * win32/win32.c (rb_w32_spawn, rb_w32_aspawn): deals with batch
+ files and commands with extensions. [ruby-core:20695]
+
+ * win32/win32.c (has_redirection): supports environment variables
+ references.
+
Sat Dec 20 10:59:16 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp>
* lib/irb/locale.rb (IRB::Locale#initialize)
diff --git a/dln.c b/dln.c
index bb64c52a0..d3408fb0f 100644
--- a/dln.c
+++ b/dln.c
@@ -1518,28 +1518,70 @@ dln_find_1(const char *fname, const char *path, char *fbuf, int size,
register const char *ep;
register char *bp;
struct stat st;
+ int i, fspace;
+#ifdef DOSISH
+ int is_abs = 0, has_path = 0, has_ext = 0;
+ const char *p = fname;
+#endif
#define RETURN_IF(expr) if (expr) return (char *)fname;
RETURN_IF(!fname);
- RETURN_IF(fname[0] == '/');
- RETURN_IF(strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0);
- RETURN_IF(exe_flag && strchr(fname, '/'));
#ifdef DOSISH
- RETURN_IF(fname[0] == '\\');
+# ifndef CharNext
+# define CharNext(p) ((p)+1)
+# endif
# ifdef DOSISH_DRIVE_LETTER
- RETURN_IF(strlen(fname) > 2 && fname[1] == ':');
+ if (((p[0] | 0x20) - 'a') < 26 && p[1] == ':') {
+ p += 2;
+ is_abs = 1;
+ }
# endif
- RETURN_IF(strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0);
- RETURN_IF(exe_flag && strchr(fname, '\\'));
+ switch (*p) {
+ case '/': case '\\':
+ is_abs = 1;
+ p++;
+ }
+ has_path = is_abs;
+ while (*p) {
+ switch (*p) {
+ case '/': case '\\':
+ has_path = 1;
+ has_ext = 0;
+ p++;
+ break;
+ case '.':
+ has_ext = 1;
+ p++;
+ break;
+ default:
+ p = CharNext(p);
+ }
+ }
+ ep = bp = 0;
+ if (!exe_flag) {
+ RETURN_IF(is_abs);
+ }
+ else if (has_path) {
+ RETURN_IF(has_ext);
+ i = p - fname;
+ if (i + 1 > size) goto toolong;
+ fspace = size - i - 1;
+ bp = fbuf;
+ ep = p;
+ memcpy(fbuf, fname, i + 1);
+ goto needs_extension;
+ }
#endif
+ RETURN_IF(fname[0] == '/');
+ RETURN_IF(strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0);
+ RETURN_IF(exe_flag && strchr(fname, '/'));
+
#undef RETURN_IF
for (dp = path;; dp = ++ep) {
register int l;
- int i;
- int fspace;
/* extract a component */
ep = strchr(dp, PATH_SEP[0]);
@@ -1602,7 +1644,7 @@ dln_find_1(const char *fname, const char *path, char *fbuf, int size,
memcpy(bp, fname, i + 1);
#if defined(DOSISH)
- if (exe_flag) {
+ if (exe_flag && !has_ext) {
static const char extension[][5] = {
#if defined(__EMX__) || defined(_WIN32)
".exe", ".com", ".cmd", ".bat",
@@ -1611,6 +1653,7 @@ dln_find_1(const char *fname, const char *path, char *fbuf, int size,
};
int j;
+ needs_extension:
for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
if (fspace < strlen(extension[j])) {
fprintf(stderr, "openpath: pathname too long (ignored)\n");
diff --git a/io.c b/io.c
index 12c6bbba5..f5efd3719 100644
--- a/io.c
+++ b/io.c
@@ -13,6 +13,7 @@
#include "ruby/ruby.h"
#include "ruby/io.h"
+#include "dln.h"
#include <ctype.h>
#include <errno.h>
@@ -4446,9 +4447,8 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
int status;
struct popen_arg arg;
#elif defined(_WIN32)
- int openmode = rb_io_modestr_oflags(modestr);
- const char *exename = NULL;
- volatile VALUE cmdbuf;
+ volatile VALUE argbuf;
+ char **args;
struct rb_exec_arg sarg;
int pair[2], write_pair[2];
#endif
@@ -4557,8 +4557,6 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
}
#elif defined(_WIN32)
if (argc) {
- volatile VALUE argbuf;
- char **args;
int i;
if (argc >= FIXNUM_MAX / sizeof(char *)) {
@@ -4570,10 +4568,6 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
args[i] = StringValueCStr(argv[i]);
}
args[i] = NULL;
- exename = cmd;
- cmdbuf = rb_str_tmp_new(rb_w32_argv_size(args));
- cmd = rb_w32_join_argv(RSTRING_PTR(cmdbuf), args);
- rb_str_resize(argbuf, 0);
}
switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
case FMODE_READABLE|FMODE_WRITABLE:
@@ -4610,7 +4604,9 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
rb_exec_arg_fixup(eargp);
rb_run_exec_options(eargp, &sarg);
}
- while ((pid = rb_w32_spawn(P_NOWAIT, cmd, exename)) == -1) {
+ while ((pid = (args ?
+ rb_w32_aspawn(P_NOWAIT, 0, args) :
+ rb_w32_spawn(P_NOWAIT, cmd, 0))) == -1) {
/* exec failed */
switch (errno) {
case EAGAIN:
diff --git a/win32/win32.c b/win32/win32.c
index 872fcd013..6cffc21ad 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -349,6 +349,17 @@ flock(int fd, int oper)
(DWORD)-1);
}
+static inline char *
+translate_char(char *p, int from, int to)
+{
+ while (*p) {
+ if ((unsigned char)*p == from)
+ *p = to;
+ p = CharNext(p);
+ }
+ return p;
+}
+
static void
init_env(void)
{
@@ -377,11 +388,7 @@ init_env(void)
alloc->lpVtbl->Release(alloc);
}
if (f) {
- char *p = env;
- while (*p) {
- if (*p == '\\') *p = '/';
- p = CharNext(p);
- }
+ char *p = translate_char(env, '\\', '/');
if (p - env == 2 && env[1] == ':') {
*p++ = '/';
*p = 0;
@@ -752,143 +759,33 @@ rb_w32_join_argv(char *cmd, char *const *argv)
return cmd;
}
-rb_pid_t
-rb_w32_pipe_exec(const char *cmd, const char *prog, int mode, int *pipe,
- int *write_pipe)
-{
- struct ChildRecord* child;
- HANDLE hIn, hOut;
- HANDLE hDupIn, hDupOut;
- HANDLE hCurProc;
- SECURITY_ATTRIBUTES sa;
- BOOL reading, writing;
- int ret;
-
- /* Figure out what we're doing... */
- if (mode & O_RDWR) {
- reading = writing = TRUE;
- }
- else if (mode & O_WRONLY) {
- reading = FALSE;
- writing = TRUE;
- }
- else {
- reading = TRUE;
- writing = FALSE;
- }
- mode &= ~(O_RDWR|O_RDONLY|O_WRONLY|O_TEXT);
- mode |= O_BINARY;
-
- sa.nLength = sizeof (SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
- ret = -1;
-
- RUBY_CRITICAL(do {
- /* create pipe */
- hCurProc = GetCurrentProcess();
- hIn = hOut = hDupIn = hDupOut = NULL;
- if (reading) {
- HANDLE hTmpIn;
- if (!CreatePipe(&hTmpIn, &hOut, &sa, 2048L)) {
- errno = map_errno(GetLastError());
- break;
- }
- if (!DuplicateHandle(hCurProc, hTmpIn, hCurProc, &hDupIn, 0,
- FALSE, DUPLICATE_SAME_ACCESS)) {
- errno = map_errno(GetLastError());
- CloseHandle(hTmpIn);
- CloseHandle(hOut);
- break;
- }
- CloseHandle(hTmpIn);
- hTmpIn = NULL;
- }
- if (writing) {
- HANDLE hTmpOut;
- if (!CreatePipe(&hIn, &hTmpOut, &sa, 2048L)) {
- errno = map_errno(GetLastError());
- break;
- }
- if (!DuplicateHandle(hCurProc, hTmpOut, hCurProc, &hDupOut, 0,
- FALSE, DUPLICATE_SAME_ACCESS)) {
- errno = map_errno(GetLastError());
- CloseHandle(hIn);
- CloseHandle(hTmpOut);
- break;
- }
- CloseHandle(hTmpOut);
- hTmpOut = NULL;
- }
-
- /* create child process */
- child = CreateChild(cmd, prog, &sa, hIn, hOut, NULL);
- if (!child) {
- if (hIn)
- CloseHandle(hIn);
- if (hOut)
- CloseHandle(hOut);
- if (hDupIn)
- CloseHandle(hDupIn);
- if (hDupOut)
- CloseHandle(hDupOut);
- break;
- }
-
- /* associate handle to file descritor */
- if (reading) {
- *pipe = rb_w32_open_osfhandle((intptr_t)hDupIn, O_RDONLY | mode);
- if (writing)
- *write_pipe = rb_w32_open_osfhandle((intptr_t)hDupOut,
- O_WRONLY | mode);
- }
- else {
- *pipe = rb_w32_open_osfhandle((intptr_t)hDupOut, O_WRONLY | mode);
- }
- if (hIn)
- CloseHandle(hIn);
- if (hOut)
- CloseHandle(hOut);
- if (reading && writing && *write_pipe == -1) {
- if (*pipe != -1)
- rb_w32_close(*pipe);
- else
- CloseHandle(hDupIn);
- CloseHandle(hDupOut);
- CloseChildHandle(child);
- break;
- }
- else if (*pipe == -1) {
- if (reading)
- CloseHandle(hDupIn);
- else
- CloseHandle(hDupOut);
- CloseChildHandle(child);
- break;
- }
-
- ret = child->pid;
- } while (0));
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#else
+# define MAXPATHLEN 512
+#endif
- return ret;
-}
+#define STRNDUPA(ptr, src, len) \
+ (((char *)memcpy(((ptr) = ALLOCA_N(char, (len) + 1)), (src), (len)))[len] = 0)
-rb_pid_t
-rb_w32_spawn(int mode, const char *cmd, const char *prog)
+static int
+check_spawn_mode(int mode)
{
- struct ChildRecord *child;
- DWORD exitcode;
-
switch (mode) {
case P_NOWAIT:
case P_OVERLAY:
- break;
+ return 0;
default:
errno = EINVAL;
return -1;
}
+}
+
+static rb_pid_t
+child_result(struct ChildRecord *child, int mode)
+{
+ DWORD exitcode;
- child = CreateChild(cmd, prog, NULL, NULL, NULL, NULL);
if (!child) {
return -1;
}
@@ -906,22 +803,6 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog)
}
}
-rb_pid_t
-rb_w32_aspawn(int mode, const char *prog, char *const *argv)
-{
- int len = rb_w32_argv_size(argv);
- char *cmd = ALLOCA_N(char, len);
-
- if (!prog) prog = argv[0];
- return rb_w32_spawn(mode, rb_w32_join_argv(cmd, argv), prog);
-}
-
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#else
-# define MAXPATHLEN 512
-#endif
-
static struct ChildRecord *
CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa,
HANDLE hInput, HANDLE hOutput, HANDLE hError)
@@ -931,10 +812,7 @@ CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa,
STARTUPINFO aStartupInfo;
PROCESS_INFORMATION aProcessInformation;
SECURITY_ATTRIBUTES sa;
- const char *shell;
struct ChildRecord *child;
- char *p = NULL;
- char fbuf[MAXPATHLEN];
if (!cmd && !prog) {
errno = EFAULT;
@@ -981,6 +859,40 @@ CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa,
dwCreationFlags = (NORMAL_PRIORITY_CLASS);
+ RUBY_CRITICAL({
+ fRet = CreateProcess(prog, (char *)cmd, psa, psa,
+ psa->bInheritHandle, dwCreationFlags, NULL, NULL,
+ &aStartupInfo, &aProcessInformation);
+ errno = map_errno(GetLastError());
+ });
+
+ if (!fRet) {
+ child->pid = 0; /* release the slot */
+ return NULL;
+ }
+
+ CloseHandle(aProcessInformation.hThread);
+
+ child->hProcess = aProcessInformation.hProcess;
+ child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
+
+ if (!IsWinNT()) {
+ /* On Win9x, make pid positive similarly to cygwin and perl */
+ child->pid = -child->pid;
+ }
+
+ return child;
+}
+
+rb_pid_t
+rb_w32_spawn(int mode, const char *cmd, const char *prog)
+{
+ char fbuf[MAXPATHLEN];
+ char *p = NULL;
+ const char *shell = NULL;
+
+ if (check_spawn_mode(mode)) return -1;
+
if (prog) {
if (!(p = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
shell = prog;
@@ -1024,20 +936,17 @@ CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa,
p = dln_find_exe_r(cmd, NULL, fbuf, sizeof(fbuf));
break;
}
- if (strchr(".:*?\"/\\", *prog)) {
+ if (strchr(":*?\"/\\", *prog)) {
if (cmd[len]) {
- char *tmp = ALLOCA_N(char, len + 1);
- memcpy(tmp, cmd, len);
- tmp[len] = 0;
- cmd = tmp;
+ STRNDUPA(p, cmd, len);
}
+ p = dln_find_exe_r(p ? p : cmd, NULL, fbuf, sizeof(fbuf));
+ cmd += len;
break;
}
if (ISSPACE(*prog) || strchr("<>|", *prog)) {
len = prog - cmd;
- p = ALLOCA_N(char, len + 1);
- memcpy(p, cmd, len);
- p[len] = 0;
+ STRNDUPA(p, cmd, len);
p = dln_find_exe_r(p, NULL, fbuf, sizeof(fbuf));
break;
}
@@ -1047,36 +956,61 @@ CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa,
}
if (p) {
shell = p;
- while (*p) {
- if ((unsigned char)*p == '/')
- *p = '\\';
- p = CharNext(p);
- }
+ translate_char(p, '/', '\\');
}
- RUBY_CRITICAL({
- fRet = CreateProcess(shell, (char *)cmd, psa, psa,
- psa->bInheritHandle, dwCreationFlags, NULL, NULL,
- &aStartupInfo, &aProcessInformation);
- errno = map_errno(GetLastError());
- });
-
- if (!fRet) {
- child->pid = 0; /* release the slot */
- return NULL;
- }
+ return child_result(CreateChild(cmd, shell, NULL, NULL, NULL, NULL), mode);
+}
- CloseHandle(aProcessInformation.hThread);
+rb_pid_t
+rb_w32_aspawn(int mode, const char *prog, char *const *argv)
+{
+ int len, differ = 0, c_switch =0;
+ const char *shell;
+ char *cmd, fbuf[MAXPATHLEN];
- child->hProcess = aProcessInformation.hProcess;
- child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
+ if (check_spawn_mode(mode)) return -1;
- if (!IsWinNT()) {
- /* On Win9x, make pid positive similarly to cygwin and perl */
- child->pid = -child->pid;
+ if (!prog) prog = argv[0];
+ if ((shell = getenv("COMSPEC")) &&
+ (has_redirection(prog) ||
+ is_internal_cmd(prog, !is_command_com(shell)))) {
+ prog = shell;
+ c_switch = 1;
+ differ = 1;
+ }
+ else if ((cmd = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
+ if (cmd == prog) strlcpy(cmd = fbuf, prog, sizeof(fbuf));
+ translate_char(cmd, '/', '\\');
+ prog = cmd;
+ argv++;
+ differ = 1;
+ }
+ else if (strchr(prog, '/')) {
+ strlcpy(fbuf, prog, sizeof(fbuf));
+ translate_char(fbuf, '/', '\\');
+ prog = fbuf;
+ argv++;
+ differ = 1;
+ }
+ if (differ) {
+ char *progs[2];
+ progs[0] = (char *)prog;
+ progs[1] = NULL;
+ len = rb_w32_argv_size(progs);
+ if (c_switch) len += 3;
+ if (argv[0]) len += rb_w32_argv_size(argv);
+ cmd = ALLOCA_N(char, len);
+ rb_w32_join_argv(cmd, progs);
+ if (c_switch) strlcat(cmd, " /c", len);
+ if (argv[0]) rb_w32_join_argv(cmd + strlcat(cmd, " ", len), argv);
}
-
- return child;
+ else {
+ len = rb_w32_argv_size(argv);
+ cmd = ALLOCA_N(char, len);
+ rb_w32_join_argv(cmd, argv);
+ }
+ return child_result(CreateChild(cmd, prog, NULL, NULL, NULL, NULL), mode);
}
typedef struct _NtCmdLineElement {
@@ -1176,6 +1110,12 @@ has_redirection(const char *cmd)
ptr++;
break;
+ case '%':
+ if (*++ptr != '_' && !ISALPHA(*ptr)) break;
+ while (*++ptr == '_' || ISALNUM(*ptr));
+ if (*ptr++ == '%') return TRUE;
+ break;
+
case '\\':
ptr++;
default: