Revision: 3939 http://trac.macosforge.org/projects/ruby/changeset/3939 Author: martinlagardette@apple.com Date: 2010-04-16 19:09:53 -0700 (Fri, 16 Apr 2010) Log Message: ----------- Adds support for `Array` arguments in `IO.popen` Also adds support for the "|" argument in `IO.read` and `IO.open` Modified Paths: -------------- MacRuby/trunk/io.c Modified: MacRuby/trunk/io.c =================================================================== --- MacRuby/trunk/io.c 2010-04-17 00:55:39 UTC (rev 3938) +++ MacRuby/trunk/io.c 2010-04-17 02:09:53 UTC (rev 3939) @@ -2111,11 +2111,31 @@ "could not add a close() to stdout"); pid_t pid; - // TODO: Split the process_name up into char* components? - char *spawnedArgs[] = {(char*)_PATH_BSHELL, "-c", - (char*)RSTRING_PTR(prog), NULL}; - errno = posix_spawn(&pid, spawnedArgs[0], &actions, NULL, spawnedArgs, - *(_NSGetEnviron())); + + VALUE argArray = rb_check_array_type(prog); + if (!NIL_P(argArray)) { + const long len = RARRAY_LEN(argArray); + char **spawnedArgs = + malloc((len + 1) * sizeof(char *)); + for (long i = 0; i < len; i++) { + VALUE str = RARRAY_AT(argArray, i); + spawnedArgs[i] = StringValuePtr(str); + } + spawnedArgs[len] = 0; + // using posix_spawnP (look up binary in PATH) + errno = posix_spawnp(&pid, spawnedArgs[0], &actions, NULL, spawnedArgs, + *(_NSGetEnviron())); + const int err = errno; + free(spawnedArgs); + errno = err; + } + else { + // TODO: Split the process_name up into char* components? + char *spawnedArgs[] = {(char*)_PATH_BSHELL, "-c", + StringValuePtr(prog), NULL}; + errno = posix_spawn(&pid, spawnedArgs[0], &actions, NULL, spawnedArgs, + *(_NSGetEnviron())); + } if (errno != 0) { const int err = errno; close(fd[0]); @@ -2153,7 +2173,6 @@ if (NIL_P(mode)) { mode = (VALUE)CFSTR("r"); } - StringValue(process_name); VALUE io = io_from_spawning_new_process(process_name, mode); if (rb_block_given_p()) { VALUE ret = rb_vm_yield(1, &io); @@ -2190,6 +2209,19 @@ return io; } +static VALUE +check_pipe_command(VALUE fname) +{ + const char *cname = StringValuePtr(fname); + const size_t len = strlen(cname); + + if (cname[0] == '|') { + VALUE cmd = rb_str_new(cname + 1, len - 1); + return cmd; + } + return Qnil; +} + /* * call-seq: * open(path [, mode_enc [, perm]] ) => io or nil @@ -2300,12 +2332,23 @@ static VALUE rb_file_open(VALUE io, int argc, VALUE *argv) { + if (argc > 0) { + // First argument must always be a path, we are checking it here to + // conform to RubySpecs which states that the conversion must only + // happen once. + FilePathValue(argv[0]); + } + if (argc >= 1) { + VALUE cmd = check_pipe_command(argv[0]); + if (cmd != Qnil) { + return rb_io_s_popen(rb_cIO, 0, 1, &cmd); + } + } VALUE path, modes, permissions; rb_scan_args(argc, argv, "12", &path, &modes, &permissions); if (NIL_P(modes)) { modes = (VALUE)CFSTR("r"); } - FilePathValue(path); const char *filepath = RSTRING_PTR(path); const int flags = convert_mode_string_to_oflags(modes); const mode_t perm = NIL_P(permissions) ? 0666 : NUM2UINT(permissions); @@ -2349,6 +2392,12 @@ VALUE rb_f_open(VALUE klass, SEL sel, int argc, VALUE *argv) { + if (argc >= 1) { + VALUE cmd = check_pipe_command(argv[0]); + if (cmd != Qnil) { + return rb_io_s_popen(rb_cIO, 0, 1, &cmd); + } + } VALUE io = rb_class_new_instance(argc, argv, rb_cFile); if (rb_block_given_p()) { return rb_ensure(f_open_body, io, f_open_ensure, io);