win32-open3 0.3.2-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +81 -0
- data/MANIFEST +11 -0
- data/README +64 -0
- data/Rakefile +98 -0
- data/doc/open3.txt +79 -0
- data/examples/win32_open3_example.rb +34 -0
- data/ext/win32/open3.c +567 -0
- data/lib/win32/open3.so +0 -0
- data/test/test_win32_open3.rb +113 -0
- data/win32-open3.gemspec +36 -0
- metadata +69 -0
data/CHANGES
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
== 0.3.2 - 23-Jan-2010
|
2
|
+
* Updated the gemspec. The required version is now any version less
|
3
|
+
than 1.9.x. This library is for the 1.8.x branch only.
|
4
|
+
* The Rakefile now handles the gem building and installation and some
|
5
|
+
existing tasks were refactored.
|
6
|
+
|
7
|
+
== 0.3.1 - 23-Jun-2009
|
8
|
+
* Updated the license to Artistic 2.0
|
9
|
+
* Set the license in the gemspec.
|
10
|
+
* Added note regarding 1.9.x in the open3.txt file.
|
11
|
+
|
12
|
+
== 0.3.0 - 22-Jun-2009
|
13
|
+
* Fixed an issue where the block form of the Open3.popen3 method did not
|
14
|
+
return the exit value.
|
15
|
+
* Fixed the version number.
|
16
|
+
* Added a test to validate the exit value in block form.
|
17
|
+
* Updated the gemspec description.
|
18
|
+
|
19
|
+
== 0.2.9 - 8-Mar-2009
|
20
|
+
* Fixed a bug within an internal function that could cause an exception.
|
21
|
+
Thanks go to Ross Bunker for the spot and patch.
|
22
|
+
* Fixed the release dates for 0.2.7 and 0.2.8 (2009, not 2008).
|
23
|
+
|
24
|
+
== 0.2.8 - 27-Feb-2009
|
25
|
+
* Fixed a potential bug where nil might be returned instead of an actual
|
26
|
+
Process::Status object. Thanks go to Benny Bach for the spot.
|
27
|
+
* The 'test' Rake task now runs the 'clean' task after the fact.
|
28
|
+
* Some updates to the README about precompiled binaries.
|
29
|
+
|
30
|
+
== 0.2.7 - 11-Jan-2009
|
31
|
+
* Fixed a bug that could cause exitstatus to return bogus information. Thanks
|
32
|
+
go to Roman Zawada for the spot.
|
33
|
+
* Added a 'build_binary_gem' Rake task.
|
34
|
+
* Updates to the gemspec, including the addition of Park Heesob as the primary
|
35
|
+
author in the gemspec.
|
36
|
+
* Renamed the test file and the example file.
|
37
|
+
|
38
|
+
== 0.2.6 - 1-June-2007
|
39
|
+
* Fixed RubyForge bug #20455 (closed IO stream). Thanks go an anonymous user
|
40
|
+
for the spot.
|
41
|
+
* Added a Rakefile with tasks for building, testing and installation.
|
42
|
+
* Minor updates to the test file.
|
43
|
+
* Some minor rdoc improvements.
|
44
|
+
|
45
|
+
== 0.2.5 - 8-Dec-2006
|
46
|
+
* Added a WIN32_OPEN3_VERSION constant.
|
47
|
+
* Fixes and updates to the gemspec.
|
48
|
+
* Some internal reorganization.
|
49
|
+
* Minor documentation updates and corrections.
|
50
|
+
|
51
|
+
== 0.2.4 - 4-Jun-2006
|
52
|
+
* Applied a patch for Windows 2000. Thanks again to John-Mason Shackelford
|
53
|
+
for the patch.
|
54
|
+
* Fixed the version number for the last release.
|
55
|
+
|
56
|
+
== 0.2.3 - 3-Jun-2006
|
57
|
+
* Now sets Process::Status when the block form is used. Thanks go to
|
58
|
+
Samuel Tesla and John-Mason Shackelford for their patches.
|
59
|
+
* Improved error messages.
|
60
|
+
* Documentation updated with regards to the block form of the method calls.
|
61
|
+
* Some internal reorganization that you don't care about.
|
62
|
+
|
63
|
+
== 0.2.2 - 10-Feb-2006
|
64
|
+
* Methods now support block form, and all handles are automatically closed
|
65
|
+
at the end of the block (via ensure).
|
66
|
+
|
67
|
+
== 0.2.1 - 27-Oct-2005
|
68
|
+
* Added a type check in the extconf.rb file and did some type mangling in
|
69
|
+
order to handle rb_pid_t in a backwards compatible way. In other words,
|
70
|
+
you need this version to work with 1.8.3 or later.
|
71
|
+
|
72
|
+
== 0.2.0 - 9-Jan-2005
|
73
|
+
* Added the Open4 module and popen4 method. Thanks go to Aslak Hellesoy for
|
74
|
+
the patch.
|
75
|
+
* Added an optional 3rd parameter - the "show" flag. See docs for details.
|
76
|
+
* Made some documentation more rdoc friendly.
|
77
|
+
* Moved the "examples" directory to the toplevel directory.
|
78
|
+
* Added some information to the README file about possible compiler problems.
|
79
|
+
|
80
|
+
== 0.1.0 - 8-Oct-2004
|
81
|
+
* Initial release
|
data/MANIFEST
ADDED
data/README
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
= Description
|
2
|
+
This library provides an Open3.popen3 implementation for MS Windows for
|
3
|
+
the Ruby 1.8.x branch.
|
4
|
+
|
5
|
+
= Prerequisites
|
6
|
+
Ruby 1.8.x branch only
|
7
|
+
C++ compiler (if building from source)
|
8
|
+
|
9
|
+
= Installation
|
10
|
+
gem install win32-open3 # Build and install from source
|
11
|
+
gem install win32-open3 --platform mingw # Install the binary gem
|
12
|
+
|
13
|
+
= Synopsis
|
14
|
+
require 'win32/open3'
|
15
|
+
|
16
|
+
Open3.popen3('ver'){ |io_in, io_out, io_err|
|
17
|
+
error = io_err.gets
|
18
|
+
|
19
|
+
if error
|
20
|
+
puts "Error: " + error.chomp
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
puts "Result: " + io_out.readlines.last.chomp
|
25
|
+
}
|
26
|
+
|
27
|
+
= Notes
|
28
|
+
This library is not supported on Windows 95, 98, or ME.
|
29
|
+
This is a stripped down version of Park Heesob's win32_popen library.
|
30
|
+
|
31
|
+
= Developer's Notes
|
32
|
+
This is a repackaging of Heesob's win32_popen module. The purpose of the
|
33
|
+
repackaging was to create a unified API between the existing Ruby open3
|
34
|
+
library and this library.
|
35
|
+
|
36
|
+
The popen2 and posix_popen methods are not included in this release. They
|
37
|
+
were originally part of the win32_popen module, but have been left out.
|
38
|
+
They may be added back in at a later date.
|
39
|
+
|
40
|
+
There are a couple of differences in the Windows version for open3 (which
|
41
|
+
also apply to Open4.popen4) - the mode flag and the show flag. For the
|
42
|
+
mode, you can specify either 't' (text, the default) or 'b' (binary) as a
|
43
|
+
second argument. For the show flag, you can specify either true or false,
|
44
|
+
which will show the console window, or not, depending on the value you
|
45
|
+
pass. The default is false.
|
46
|
+
|
47
|
+
= Known Issues
|
48
|
+
I have noticed that this library (and others) may segfault if you are using
|
49
|
+
the latest version of the Ruby one-click installer and VC++ 7.0 or later.
|
50
|
+
This appears to be an issue between VC++ 6 (which the installer was built
|
51
|
+
with) and VC++ 7.0. Your best solution is to either upgrade your C
|
52
|
+
compiler or to rebuild Ruby from scratch rather than using the installer.
|
53
|
+
|
54
|
+
= Precompiled binaries
|
55
|
+
If you do a typical "gem install win32-open3" you will get a precompiled
|
56
|
+
binary appropriate for your platform. If you want to build from source,
|
57
|
+
go the project page and download, download the .zip file, and run the
|
58
|
+
'install' Rake task from the command line.
|
59
|
+
|
60
|
+
= Future Plans
|
61
|
+
Replace the current implementation with a pure Ruby version, if possible.
|
62
|
+
|
63
|
+
= More Documentation
|
64
|
+
See the doc/open3.txt file for more details.
|
data/Rakefile
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rbconfig'
|
5
|
+
include Config
|
6
|
+
|
7
|
+
make = CONFIG['MAKEFILES'].nil? ? 'nmake' : 'make'
|
8
|
+
|
9
|
+
desc 'Install the win32-open3 library'
|
10
|
+
task :install => [:build] do
|
11
|
+
Dir.chdir('ext'){
|
12
|
+
sh "#{make} install"
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Clean any build files for win32-open3"
|
17
|
+
task :clean do
|
18
|
+
Dir.chdir('ext') do
|
19
|
+
if File.exists?('open3.so') || File.exists?('win32/open3.so')
|
20
|
+
sh "#{make} distclean"
|
21
|
+
rm 'win32/open3.so' if File.exists?('win32/open3.so')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
rm_rf 'lib'
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Build win32-open3 (but don't install it)"
|
28
|
+
task :build => [:clean] do
|
29
|
+
Dir.chdir('ext') do
|
30
|
+
ruby 'extconf.rb'
|
31
|
+
sh make
|
32
|
+
mv 'open3.so', 'win32' # For the test suite
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Run the sample program"
|
37
|
+
task :example => [:build] do |t|
|
38
|
+
Dir.chdir('examples'){
|
39
|
+
sh 'ruby -I../ext open3_test.rb'
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
namespace 'gem' do
|
44
|
+
desc 'Clean any build files and remove the .gem file'
|
45
|
+
task :clean do
|
46
|
+
Dir["*.gem"].each{ |f| File.delete(f) }
|
47
|
+
Dir.chdir('ext') do
|
48
|
+
if File.exists?('open3.so') || File.exists?('win32/open3.so')
|
49
|
+
sh "#{make} distclean"
|
50
|
+
rm 'win32/open3.so' if File.exists?('win32/open3.so')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'Build the gem'
|
56
|
+
task :build => [:clean] do
|
57
|
+
spec = eval(IO.read('win32-open3.gemspec'))
|
58
|
+
Gem::Builder.new(spec).build
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'Install the win32-open3 library as a gem'
|
62
|
+
task :install => [:build] do
|
63
|
+
file = Dir["*.gem"].first
|
64
|
+
sh "gem install #{file}"
|
65
|
+
end
|
66
|
+
|
67
|
+
desc 'Build a binary gem'
|
68
|
+
task :binary => [:clean] do
|
69
|
+
Dir.chdir('ext') do
|
70
|
+
ruby 'extconf.rb'
|
71
|
+
sh make
|
72
|
+
end
|
73
|
+
|
74
|
+
mkdir_p 'lib/win32'
|
75
|
+
mv 'ext/open3.so', 'lib/win32'
|
76
|
+
|
77
|
+
spec = eval(IO.read('win32-open3.gemspec'))
|
78
|
+
spec.extensions = nil
|
79
|
+
spec.platform = Gem::Platform::CURRENT
|
80
|
+
|
81
|
+
spec.files = Dir['**/*'].reject{ |file|
|
82
|
+
file.include?('ext') || file.include?('git')
|
83
|
+
}
|
84
|
+
|
85
|
+
Gem::Builder.new(spec).build
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Rake::TestTask.new('test') do |test|
|
90
|
+
task :test => [:build]
|
91
|
+
test.libs << 'ext'
|
92
|
+
test.warning = true
|
93
|
+
test.verbose = true
|
94
|
+
end
|
95
|
+
|
96
|
+
task :test do
|
97
|
+
Rake.application[:clean].execute
|
98
|
+
end
|
data/doc/open3.txt
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
= Description
|
2
|
+
An open3 library for MS Windows for the Ruby 1.8.x branch.
|
3
|
+
|
4
|
+
= Synopsis
|
5
|
+
require 'win32/open3'
|
6
|
+
|
7
|
+
Open3.popen3('ver'){ |io_in, io_out, io_err|
|
8
|
+
error = io_err.gets
|
9
|
+
if error
|
10
|
+
puts "Error: " + error.chomp
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
puts "Result: " + io_out.readlines.last.chomp
|
14
|
+
}
|
15
|
+
|
16
|
+
= Module functions
|
17
|
+
Open3.popen3(command, mode='t', show=false)
|
18
|
+
|
19
|
+
Open3.popen3(command, mode='t', show=false){ |io_in, io_out, io_err| ... }
|
20
|
+
|
21
|
+
Executes 'command', returning an array of three IO handles representing
|
22
|
+
STDIN, STDOUT and STDERR, respectively. In block form these IO handles
|
23
|
+
are yielded back to the block and automatically closed at the end of the
|
24
|
+
block.
|
25
|
+
|
26
|
+
You may optionally pass a mode flag of 't' (text, the default) or 'b'
|
27
|
+
(binary) to this method.
|
28
|
+
|
29
|
+
If the 'show' variable is set to true, then a console window is shown.
|
30
|
+
|
31
|
+
Open4.popen4(command, mode='t', show=false)
|
32
|
+
|
33
|
+
Open4.popen4(command, mode='t', show=false){ |io_in, io_out, io_err, pid| ... }
|
34
|
+
|
35
|
+
Executes 'command', returning an array consisting of three IO handles,
|
36
|
+
representing STDIN, STDOUT and STDERR, respectively, as well as the PID
|
37
|
+
of the newly generated process. In block form these IO handles and pid
|
38
|
+
are yielded back to the block and automatically closed at the end of the
|
39
|
+
block.
|
40
|
+
|
41
|
+
You may optionally pass a mode flag of 't' (text, the default) or 'b'
|
42
|
+
(binary) to this method.
|
43
|
+
|
44
|
+
If the 'show' variable is set to true, then a console window is shown.
|
45
|
+
|
46
|
+
= Notes
|
47
|
+
This is a remake of Park Heesob's win32_popen package. It has been reworked
|
48
|
+
in order to make the API (nearly) identical to the Open3 package currently
|
49
|
+
included in the Ruby standard library.
|
50
|
+
|
51
|
+
For now only the popen3 and popen4 methods have been included. In later
|
52
|
+
releases we will probably add the popen2 and posix_popen methods back in.
|
53
|
+
|
54
|
+
Ruby 1.9.x users will not generally need this library because of its support
|
55
|
+
for native threads. That means you can use the open3 library that ships as
|
56
|
+
part of the standard library.
|
57
|
+
|
58
|
+
= Acknowledgements
|
59
|
+
Thanks go to Samuel Tesla and John-Mason Shackelford for their patches that
|
60
|
+
enabled us to set Process::Status.
|
61
|
+
|
62
|
+
= Known Bugs
|
63
|
+
None that I know of. Please log any other bug reports on the RubyForge
|
64
|
+
project page at http://www.rubyforge.net/projects/win32utils.
|
65
|
+
|
66
|
+
= License
|
67
|
+
Artistic 2.0
|
68
|
+
|
69
|
+
= Copyright
|
70
|
+
(C) 2003-2010 Daniel J. Berger, All Rights Reserved .
|
71
|
+
|
72
|
+
= Warranty
|
73
|
+
This package is provided "as is" and without any express or
|
74
|
+
implied warranties, including, without limitation, the implied
|
75
|
+
warranties of merchantability and fitness for a particular purpose.
|
76
|
+
|
77
|
+
= Authors
|
78
|
+
Park Heesob
|
79
|
+
Daniel J. Berger
|
@@ -0,0 +1,34 @@
|
|
1
|
+
##############################################################################
|
2
|
+
# win32_open3_example.rb
|
3
|
+
#
|
4
|
+
# Test script for the win32-open3 library. You should run this via the
|
5
|
+
# 'rake example' Rakefile task.
|
6
|
+
#
|
7
|
+
# Modify as you see fit.
|
8
|
+
##############################################################################
|
9
|
+
require 'win32/open3'
|
10
|
+
|
11
|
+
puts "VERSION: " + Open3::WIN32_OPEN3_VERSION
|
12
|
+
|
13
|
+
cmd1 = 'ver' # valid
|
14
|
+
cmd2 = 'verb' # invalid
|
15
|
+
cmd3 = "ruby -e 'exit 1'" # valid, with explicit exit status
|
16
|
+
|
17
|
+
# Try each command as you like...
|
18
|
+
Open3.popen3(cmd3){ |io_in, io_out, io_err|
|
19
|
+
error = io_err.read
|
20
|
+
if error && error.length > 0
|
21
|
+
puts 'Error: ' + error
|
22
|
+
break
|
23
|
+
else
|
24
|
+
output = io_out.read
|
25
|
+
puts 'Output: ' + output if output
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
p $?.class
|
30
|
+
p $? >> 8
|
31
|
+
p $?.stopped?
|
32
|
+
p $?.exited?
|
33
|
+
p $?.exitstatus
|
34
|
+
p $?.pid
|
data/ext/win32/open3.c
ADDED
@@ -0,0 +1,567 @@
|
|
1
|
+
/***************************************************
|
2
|
+
* open3.c
|
3
|
+
*
|
4
|
+
* Source for the win32-open3 extension.
|
5
|
+
***************************************************/
|
6
|
+
#include "ruby.h"
|
7
|
+
|
8
|
+
#ifdef HAVE_RUBY_IO_H
|
9
|
+
#include "ruby/io.h"
|
10
|
+
#else
|
11
|
+
#include "rubysig.h"
|
12
|
+
#include "rubyio.h"
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#include "open3.h"
|
16
|
+
|
17
|
+
#include <malloc.h>
|
18
|
+
#include <io.h>
|
19
|
+
#include <string.h>
|
20
|
+
#include <fcntl.h>
|
21
|
+
#include <sys/stat.h>
|
22
|
+
|
23
|
+
// Necessary to work with Ruby 1.8.3 or later
|
24
|
+
#ifdef HAVE_TYPE_RB_PID_T
|
25
|
+
#define pid_t rb_pid_t
|
26
|
+
#endif
|
27
|
+
|
28
|
+
// Ruby 1.9.x
|
29
|
+
#ifndef RSTRING_PTR
|
30
|
+
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
31
|
+
#endif
|
32
|
+
#ifndef RSTRING_LEN
|
33
|
+
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#ifndef RARRAY_PTR
|
37
|
+
#define RARRAY_PTR(a) (RARRAY(a)->ptr)
|
38
|
+
#endif
|
39
|
+
#ifndef RARRAY_LEN
|
40
|
+
#define RARRAY_LEN(a) (RARRAY(a)->len)
|
41
|
+
#endif
|
42
|
+
|
43
|
+
static VALUE win32_last_status = Qnil;
|
44
|
+
static HANDLE pid_handle = NULL;
|
45
|
+
|
46
|
+
static VALUE ruby_popen(char *, int, VALUE);
|
47
|
+
|
48
|
+
static int rb_io_mode_flags2(int mode){
|
49
|
+
int flags;
|
50
|
+
|
51
|
+
switch (mode & (O_RDONLY|O_WRONLY|O_RDWR)) {
|
52
|
+
case O_RDONLY:
|
53
|
+
flags = FMODE_READABLE;
|
54
|
+
break;
|
55
|
+
case O_WRONLY:
|
56
|
+
flags = FMODE_WRITABLE;
|
57
|
+
break;
|
58
|
+
case O_RDWR:
|
59
|
+
flags = FMODE_WRITABLE|FMODE_READABLE;
|
60
|
+
break;
|
61
|
+
}
|
62
|
+
|
63
|
+
#ifdef O_BINARY
|
64
|
+
if(mode & O_BINARY)
|
65
|
+
flags |= FMODE_BINMODE;
|
66
|
+
#endif
|
67
|
+
|
68
|
+
return flags;
|
69
|
+
}
|
70
|
+
|
71
|
+
static char* rb_io_modenum_mode(int flags, char* mode){
|
72
|
+
char *p = mode;
|
73
|
+
|
74
|
+
switch(flags & (O_RDONLY|O_WRONLY|O_RDWR)){
|
75
|
+
case O_RDONLY:
|
76
|
+
*p++ = 'r';
|
77
|
+
break;
|
78
|
+
case O_WRONLY:
|
79
|
+
*p++ = 'w';
|
80
|
+
break;
|
81
|
+
case O_RDWR:
|
82
|
+
*p++ = 'r';
|
83
|
+
*p++ = '+';
|
84
|
+
break;
|
85
|
+
}
|
86
|
+
|
87
|
+
*p++ = '\0';
|
88
|
+
|
89
|
+
#ifdef O_BINARY
|
90
|
+
if(flags & O_BINARY){
|
91
|
+
if(mode[1] == '+'){
|
92
|
+
mode[1] = 'b';
|
93
|
+
mode[2] = '+';
|
94
|
+
mode[3] = '\0';
|
95
|
+
}
|
96
|
+
else{
|
97
|
+
mode[1] = 'b'; mode[2] = '\0';
|
98
|
+
}
|
99
|
+
}
|
100
|
+
#endif
|
101
|
+
return mode;
|
102
|
+
}
|
103
|
+
|
104
|
+
/* Used to close io handle */
|
105
|
+
static VALUE io_close(VALUE val) {
|
106
|
+
int i;
|
107
|
+
|
108
|
+
for(i = 0; i < 3; i++){
|
109
|
+
if(rb_funcall(RARRAY_PTR(val)[i], rb_intern("closed?"), 0) == Qfalse)
|
110
|
+
rb_funcall(RARRAY_PTR(val)[i], rb_intern("close"), 0);
|
111
|
+
}
|
112
|
+
|
113
|
+
return Qnil;
|
114
|
+
}
|
115
|
+
|
116
|
+
/*
|
117
|
+
* call-seq:
|
118
|
+
* Open3.popen3(cmd, mode='t', show=false)
|
119
|
+
* Open3.popen3(cmd, mode='t', show=false){ |io_in, io_out, io_err| ... }
|
120
|
+
*
|
121
|
+
* Executes 'command', returning an array of three IO handles representing
|
122
|
+
* STDIN, STDOUT and STDERR, respectively. In block form these IO handles
|
123
|
+
* are yielded back to the block and automatically closed at the end of the
|
124
|
+
* block.
|
125
|
+
*
|
126
|
+
* You may optionally pass a mode flag of 't' (text, the default) or 'b'
|
127
|
+
* (binary) to this method.
|
128
|
+
*
|
129
|
+
* If the 'show' variable is set to true, then a console window is shown.
|
130
|
+
*/
|
131
|
+
static VALUE win32_popen3(int argc, VALUE *argv, VALUE klass)
|
132
|
+
{
|
133
|
+
VALUE v_name, v_mode, v_port;
|
134
|
+
VALUE v_show_window = Qfalse;
|
135
|
+
char mbuf[4];
|
136
|
+
int tm = 0;
|
137
|
+
char *mode = "t";
|
138
|
+
|
139
|
+
rb_scan_args(argc, argv, "12", &v_name, &v_mode, &v_show_window);
|
140
|
+
|
141
|
+
// Mode can be either a string or a number
|
142
|
+
if(!NIL_P(v_mode)){
|
143
|
+
if(FIXNUM_P(v_mode))
|
144
|
+
mode = rb_io_modenum_mode(FIX2INT(v_mode), mbuf);
|
145
|
+
else
|
146
|
+
mode = StringValuePtr(v_mode);
|
147
|
+
}
|
148
|
+
|
149
|
+
if(*mode == 't')
|
150
|
+
tm = _O_TEXT;
|
151
|
+
else if(*mode != 'b')
|
152
|
+
rb_raise(rb_eArgError, "popen3() arg 2 must be 't' or 'b'");
|
153
|
+
else
|
154
|
+
tm = _O_BINARY;
|
155
|
+
|
156
|
+
v_port = ruby_popen(StringValuePtr(v_name), tm, v_show_window);
|
157
|
+
|
158
|
+
// Ensure handles are closed in block form
|
159
|
+
if(rb_block_given_p()){
|
160
|
+
return rb_ensure(rb_yield_splat, v_port, io_close, v_port);
|
161
|
+
}
|
162
|
+
|
163
|
+
return v_port;
|
164
|
+
}
|
165
|
+
|
166
|
+
static BOOL RubyCreateProcess(char *cmdstring, HANDLE hStdin, HANDLE hStdout,
|
167
|
+
HANDLE hStderr, HANDLE *hProcess, pid_t *pid, VALUE v_show_window)
|
168
|
+
{
|
169
|
+
PROCESS_INFORMATION piProcInfo;
|
170
|
+
STARTUPINFO siStartInfo;
|
171
|
+
char *s1,*s2, *s3 = " /c ";
|
172
|
+
int i, x;
|
173
|
+
|
174
|
+
if(i = GetEnvironmentVariable("COMSPEC", NULL, 0)){
|
175
|
+
char *comshell;
|
176
|
+
s1 = (char *)_alloca(i);
|
177
|
+
|
178
|
+
if(!(x = GetEnvironmentVariable("COMSPEC", s1, i)))
|
179
|
+
return x;
|
180
|
+
|
181
|
+
/* Explicitly check if we are using COMMAND.COM. If we are
|
182
|
+
* then use the w9xpopen hack.
|
183
|
+
*/
|
184
|
+
comshell = s1 + x;
|
185
|
+
|
186
|
+
while(comshell >= s1 && *comshell != '\\')
|
187
|
+
--comshell;
|
188
|
+
|
189
|
+
++comshell;
|
190
|
+
|
191
|
+
// Windows 95, 98 and ME are not supported
|
192
|
+
if(GetVersion() < 0x80000000 && _stricmp(comshell, "command.com") != 0){
|
193
|
+
x = i + strlen(s3) + strlen(cmdstring) + 1;
|
194
|
+
s2 = ALLOCA_N(char, x);
|
195
|
+
sprintf(s2, "%s%s%s", s1, s3, cmdstring);
|
196
|
+
}
|
197
|
+
else{
|
198
|
+
rb_raise(rb_eRuntimeError,"not supported on this platform");
|
199
|
+
}
|
200
|
+
}
|
201
|
+
else{
|
202
|
+
// Could be an else here to try cmd.exe / command.com in the path.
|
203
|
+
// Now we'll just error out..
|
204
|
+
rb_raise(rb_eRuntimeError,
|
205
|
+
"Cannot locate a COMSPEC environment variable to use as the shell"
|
206
|
+
);
|
207
|
+
return FALSE;
|
208
|
+
}
|
209
|
+
|
210
|
+
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
|
211
|
+
|
212
|
+
siStartInfo.cb = sizeof(STARTUPINFO);
|
213
|
+
siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
214
|
+
siStartInfo.hStdInput = hStdin;
|
215
|
+
siStartInfo.hStdOutput = hStdout;
|
216
|
+
siStartInfo.hStdError = hStderr;
|
217
|
+
siStartInfo.wShowWindow = SW_HIDE;
|
218
|
+
|
219
|
+
if(v_show_window == Qtrue)
|
220
|
+
siStartInfo.wShowWindow = SW_SHOW;
|
221
|
+
|
222
|
+
// Try the command first without COMSPEC
|
223
|
+
if(CreateProcess(
|
224
|
+
NULL,
|
225
|
+
cmdstring,
|
226
|
+
NULL,
|
227
|
+
NULL,
|
228
|
+
TRUE,
|
229
|
+
0,
|
230
|
+
NULL,
|
231
|
+
NULL,
|
232
|
+
&siStartInfo,
|
233
|
+
&piProcInfo)
|
234
|
+
){
|
235
|
+
// Close the handles now so anyone waiting is woken.
|
236
|
+
CloseHandle(piProcInfo.hThread);
|
237
|
+
|
238
|
+
// Return process handle
|
239
|
+
*hProcess = piProcInfo.hProcess;
|
240
|
+
*pid = (pid_t)piProcInfo.dwProcessId;
|
241
|
+
return TRUE;
|
242
|
+
}
|
243
|
+
|
244
|
+
// If that failed, try again with COMSPEC
|
245
|
+
if(CreateProcess(
|
246
|
+
NULL,
|
247
|
+
s2,
|
248
|
+
NULL,
|
249
|
+
NULL,
|
250
|
+
TRUE,
|
251
|
+
CREATE_NEW_CONSOLE,
|
252
|
+
NULL,
|
253
|
+
NULL,
|
254
|
+
&siStartInfo,
|
255
|
+
&piProcInfo)
|
256
|
+
){
|
257
|
+
// Close the handles now so anyone waiting is woken.
|
258
|
+
CloseHandle(piProcInfo.hThread);
|
259
|
+
|
260
|
+
// Return process handle
|
261
|
+
*hProcess = piProcInfo.hProcess;
|
262
|
+
*pid = (pid_t)piProcInfo.dwProcessId;
|
263
|
+
return TRUE;
|
264
|
+
}
|
265
|
+
|
266
|
+
rb_raise(rb_eRuntimeError, "CreateProcess() failed: %s",
|
267
|
+
ErrorDescription(GetLastError())
|
268
|
+
);
|
269
|
+
|
270
|
+
return FALSE;
|
271
|
+
}
|
272
|
+
|
273
|
+
/* Set the Process::Status. This code is based on patches by Samuel Tesla and
|
274
|
+
* John-Mason Shackelford.
|
275
|
+
*/
|
276
|
+
static void win32_set_last_status(const int status, const int pid)
|
277
|
+
{
|
278
|
+
// rb_last_status is defined in process.c in the main ruby.exe
|
279
|
+
__declspec (dllimport) extern VALUE rb_last_status;
|
280
|
+
VALUE klass = rb_path2class("Process::Status");
|
281
|
+
VALUE process_status = rb_obj_alloc(klass);
|
282
|
+
rb_iv_set(process_status, "status", INT2FIX(status << 8));
|
283
|
+
rb_iv_set(process_status, "pid", INT2FIX(pid));
|
284
|
+
rb_last_status = process_status;
|
285
|
+
win32_last_status = process_status;
|
286
|
+
}
|
287
|
+
|
288
|
+
static void win32_pipe_finalize(OpenFile *file, int noraise)
|
289
|
+
{
|
290
|
+
DWORD status;
|
291
|
+
|
292
|
+
if(file->f){
|
293
|
+
fclose(file->f);
|
294
|
+
file->f = NULL;
|
295
|
+
}
|
296
|
+
|
297
|
+
if(file->f2){
|
298
|
+
fclose(file->f2);
|
299
|
+
file->f2 = NULL;
|
300
|
+
}
|
301
|
+
|
302
|
+
if(pid_handle != NULL){
|
303
|
+
GetExitCodeProcess(pid_handle, &status);
|
304
|
+
|
305
|
+
if(status != STILL_ACTIVE){
|
306
|
+
CloseHandle(pid_handle);
|
307
|
+
pid_handle = NULL;
|
308
|
+
win32_set_last_status(status, file->pid);
|
309
|
+
}
|
310
|
+
}
|
311
|
+
}
|
312
|
+
|
313
|
+
// The following code is based off of KB: Q190351
|
314
|
+
static VALUE ruby_popen(char *cmdstring, int mode, VALUE v_show_window)
|
315
|
+
{
|
316
|
+
HANDLE hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr,
|
317
|
+
hChildStderrRd, hChildStderrWr, hChildStdinWrDup, hChildStdoutRdDup,
|
318
|
+
hChildStderrRdDup, hProcess;
|
319
|
+
|
320
|
+
pid_t pid;
|
321
|
+
|
322
|
+
SECURITY_ATTRIBUTES saAttr;
|
323
|
+
BOOL fSuccess;
|
324
|
+
int fd1, fd2, fd3;
|
325
|
+
FILE *f1, *f2, *f3;
|
326
|
+
long file_count;
|
327
|
+
VALUE port;
|
328
|
+
VALUE p1,p2,p3;
|
329
|
+
int modef;
|
330
|
+
OpenFile *fptr;
|
331
|
+
char *m1, *m2;
|
332
|
+
|
333
|
+
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
334
|
+
saAttr.bInheritHandle = TRUE;
|
335
|
+
saAttr.lpSecurityDescriptor = NULL;
|
336
|
+
|
337
|
+
if(!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
|
338
|
+
rb_raise(rb_eRuntimeError, "CreatePipe() failed: %s",
|
339
|
+
ErrorDescription(GetLastError())
|
340
|
+
);
|
341
|
+
}
|
342
|
+
|
343
|
+
/* Create new output read handle and the input write handle. Set
|
344
|
+
* the inheritance properties to FALSE. Otherwise, the child inherits
|
345
|
+
* the these handles; resulting in non-closeable handles to the pipes
|
346
|
+
* being created.
|
347
|
+
*/
|
348
|
+
fSuccess = DuplicateHandle(
|
349
|
+
GetCurrentProcess(),
|
350
|
+
hChildStdinWr,
|
351
|
+
GetCurrentProcess(),
|
352
|
+
&hChildStdinWrDup,
|
353
|
+
0,
|
354
|
+
FALSE,
|
355
|
+
DUPLICATE_SAME_ACCESS
|
356
|
+
);
|
357
|
+
|
358
|
+
if(!fSuccess){
|
359
|
+
rb_raise(rb_eRuntimeError, "DuplicateHandle() failed: %s",
|
360
|
+
ErrorDescription(GetLastError())
|
361
|
+
);
|
362
|
+
}
|
363
|
+
|
364
|
+
// Close the inheritable version of ChildStdin that we're using
|
365
|
+
CloseHandle(hChildStdinWr);
|
366
|
+
|
367
|
+
if(!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
|
368
|
+
rb_raise(rb_eRuntimeError, "CreatePipe() failed: %s",
|
369
|
+
ErrorDescription(GetLastError())
|
370
|
+
);
|
371
|
+
}
|
372
|
+
|
373
|
+
fSuccess = DuplicateHandle(
|
374
|
+
GetCurrentProcess(),
|
375
|
+
hChildStdoutRd,
|
376
|
+
GetCurrentProcess(),
|
377
|
+
&hChildStdoutRdDup,
|
378
|
+
0,
|
379
|
+
FALSE,
|
380
|
+
DUPLICATE_SAME_ACCESS
|
381
|
+
);
|
382
|
+
|
383
|
+
if(!fSuccess){
|
384
|
+
rb_raise(rb_eRuntimeError, "DuplicateHandle() failed: %s",
|
385
|
+
ErrorDescription(GetLastError())
|
386
|
+
);
|
387
|
+
}
|
388
|
+
|
389
|
+
// Close the inheritable version of ChildStdout that we're using.
|
390
|
+
CloseHandle(hChildStdoutRd);
|
391
|
+
|
392
|
+
if(!CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0)) {
|
393
|
+
rb_raise(rb_eRuntimeError, "CreatePipe() failed: %s",
|
394
|
+
ErrorDescription(GetLastError())
|
395
|
+
);
|
396
|
+
}
|
397
|
+
|
398
|
+
fSuccess = DuplicateHandle(
|
399
|
+
GetCurrentProcess(),
|
400
|
+
hChildStderrRd,
|
401
|
+
GetCurrentProcess(),
|
402
|
+
&hChildStderrRdDup,
|
403
|
+
0,
|
404
|
+
FALSE,
|
405
|
+
DUPLICATE_SAME_ACCESS
|
406
|
+
);
|
407
|
+
|
408
|
+
if (!fSuccess) {
|
409
|
+
rb_raise(rb_eRuntimeError, "DuplicateHandle() failed: %s",
|
410
|
+
ErrorDescription(GetLastError())
|
411
|
+
);
|
412
|
+
}
|
413
|
+
|
414
|
+
// Close the inheritable version of ChildStdErr that we're using.
|
415
|
+
CloseHandle(hChildStderrRd);
|
416
|
+
|
417
|
+
if(mode & _O_TEXT){
|
418
|
+
m1 = "r";
|
419
|
+
m2 = "w";
|
420
|
+
}
|
421
|
+
else{
|
422
|
+
m1 = "rb";
|
423
|
+
m2 = "wb";
|
424
|
+
}
|
425
|
+
|
426
|
+
// Convert HANDLE's into file descriptors and, ultimately, Ruby IO objects.
|
427
|
+
fd1 = _open_osfhandle((long)hChildStdinWrDup, mode);
|
428
|
+
f1 = _fdopen(fd1, m2);
|
429
|
+
|
430
|
+
fd2 = _open_osfhandle((long)hChildStdoutRdDup, mode);
|
431
|
+
f2 = _fdopen(fd2, m1);
|
432
|
+
|
433
|
+
fd3 = _open_osfhandle((long)hChildStderrRdDup, mode);
|
434
|
+
f3 = _fdopen(fd3, m1);
|
435
|
+
|
436
|
+
file_count = 3;
|
437
|
+
|
438
|
+
if(!RubyCreateProcess(cmdstring,hChildStdinRd,hChildStdoutWr,
|
439
|
+
hChildStderrWr, &hProcess, &pid, v_show_window))
|
440
|
+
{
|
441
|
+
return Qnil;
|
442
|
+
}
|
443
|
+
|
444
|
+
// I think this is only possible on Win9x, but we'll leave it here
|
445
|
+
if(pid < 0){
|
446
|
+
pid = -pid;
|
447
|
+
}
|
448
|
+
|
449
|
+
modef = rb_io_mode_flags(m2);
|
450
|
+
p1 = io_alloc(rb_cIO);
|
451
|
+
MakeOpenFile(p1, fptr);
|
452
|
+
|
453
|
+
fptr->finalize = win32_pipe_finalize;
|
454
|
+
fptr->mode = modef;
|
455
|
+
fptr->pid = pid;
|
456
|
+
|
457
|
+
if(modef & FMODE_READABLE){
|
458
|
+
fptr->f = f1;
|
459
|
+
}
|
460
|
+
|
461
|
+
if(modef & FMODE_WRITABLE){
|
462
|
+
if(fptr->f){
|
463
|
+
fptr->f2 = f1;
|
464
|
+
}
|
465
|
+
else{
|
466
|
+
fptr->f = f1;
|
467
|
+
}
|
468
|
+
fptr->mode |= FMODE_SYNC;
|
469
|
+
}
|
470
|
+
|
471
|
+
modef = rb_io_mode_flags(m1);
|
472
|
+
p2 = io_alloc(rb_cIO);
|
473
|
+
MakeOpenFile(p2, fptr);
|
474
|
+
|
475
|
+
pid_handle = hProcess;
|
476
|
+
fptr->finalize = win32_pipe_finalize;
|
477
|
+
fptr->mode = modef;
|
478
|
+
fptr->pid = pid;
|
479
|
+
|
480
|
+
if(modef & FMODE_READABLE){
|
481
|
+
fptr->f = f2;
|
482
|
+
}
|
483
|
+
if(modef & FMODE_WRITABLE){
|
484
|
+
if(fptr->f){
|
485
|
+
fptr->f2 = f2;
|
486
|
+
}
|
487
|
+
else{
|
488
|
+
fptr->f = f2;
|
489
|
+
}
|
490
|
+
fptr->mode |= FMODE_SYNC;
|
491
|
+
}
|
492
|
+
|
493
|
+
modef = rb_io_mode_flags(m1);
|
494
|
+
p3 = io_alloc(rb_cIO);
|
495
|
+
MakeOpenFile(p3, fptr);
|
496
|
+
|
497
|
+
fptr->finalize = win32_pipe_finalize;
|
498
|
+
fptr->mode = modef;
|
499
|
+
fptr->pid = pid;
|
500
|
+
|
501
|
+
if(modef & FMODE_READABLE){
|
502
|
+
fptr->f = f3;
|
503
|
+
}
|
504
|
+
|
505
|
+
if(modef & FMODE_WRITABLE){
|
506
|
+
if(fptr->f){
|
507
|
+
fptr->f2 = f3;
|
508
|
+
}
|
509
|
+
else{
|
510
|
+
fptr->f = f3;
|
511
|
+
}
|
512
|
+
fptr->mode |= FMODE_SYNC;
|
513
|
+
}
|
514
|
+
|
515
|
+
port = rb_ary_new2(4);
|
516
|
+
rb_ary_push(port,(VALUE)p1);
|
517
|
+
rb_ary_push(port,(VALUE)p2);
|
518
|
+
rb_ary_push(port,(VALUE)p3);
|
519
|
+
rb_ary_push(port,UINT2NUM((DWORD)pid));
|
520
|
+
|
521
|
+
/* Child is launched. Close the parents copy of those pipe
|
522
|
+
* handles that only the child should have open. You need to
|
523
|
+
* make sure that no handles to the write end of the output pipe
|
524
|
+
* are maintained in this process or else the pipe will not close
|
525
|
+
* when the child process exits and the ReadFile() will hang.
|
526
|
+
*/
|
527
|
+
|
528
|
+
if(!CloseHandle(hChildStdinRd)){
|
529
|
+
rb_raise(rb_eRuntimeError, "CloseHandle() failed: %s",
|
530
|
+
ErrorDescription(GetLastError())
|
531
|
+
);
|
532
|
+
}
|
533
|
+
|
534
|
+
if(!CloseHandle(hChildStdoutWr)){
|
535
|
+
rb_raise(rb_eRuntimeError, "CloseHandle() failed: %s",
|
536
|
+
ErrorDescription(GetLastError())
|
537
|
+
);
|
538
|
+
}
|
539
|
+
|
540
|
+
if(!CloseHandle(hChildStderrWr)){
|
541
|
+
rb_raise(rb_eRuntimeError, "CloseHandle() failed: %s",
|
542
|
+
ErrorDescription(GetLastError())
|
543
|
+
);
|
544
|
+
}
|
545
|
+
|
546
|
+
return port;
|
547
|
+
}
|
548
|
+
|
549
|
+
/*
|
550
|
+
* Spawn an external program and retrieve the stdin, stdout and stderr IO
|
551
|
+
* handles, as well as the process ID. Use in block or non-block form.
|
552
|
+
*/
|
553
|
+
void Init_open3()
|
554
|
+
{
|
555
|
+
VALUE mOpen3 = rb_define_module("Open3");
|
556
|
+
|
557
|
+
VALUE mOpen4 = rb_define_module("Open4");
|
558
|
+
|
559
|
+
rb_define_module_function(mOpen3, "popen3", win32_popen3, -1);
|
560
|
+
rb_define_module_function(mOpen4, "popen4", win32_popen3, -1);
|
561
|
+
|
562
|
+
/* 0.3.1: The version of this library */
|
563
|
+
rb_define_const(mOpen3, "WIN32_OPEN3_VERSION", rb_str_new2(WIN32_OPEN3_VERSION));
|
564
|
+
|
565
|
+
/* 0.3.1: The version of this library */
|
566
|
+
rb_define_const(mOpen4, "WIN32_OPEN3_VERSION", rb_str_new2(WIN32_OPEN3_VERSION));
|
567
|
+
}
|
data/lib/win32/open3.so
ADDED
Binary file
|
@@ -0,0 +1,113 @@
|
|
1
|
+
###########################################################################
|
2
|
+
# test_win32_open3.rb
|
3
|
+
#
|
4
|
+
# Test suite for the win32-open3 library. Except for the
|
5
|
+
# 'test_open3_with_arguments' test and Open4 tests, this suite passes
|
6
|
+
# on Unix as well.
|
7
|
+
#
|
8
|
+
# You should run this test suite via the 'rake test' task.
|
9
|
+
###########################################################################
|
10
|
+
require 'win32/open3'
|
11
|
+
require 'test/unit'
|
12
|
+
|
13
|
+
class TC_Win32_Open3 < Test::Unit::TestCase
|
14
|
+
def setup
|
15
|
+
@good_cmd = 'ver'
|
16
|
+
@bad_cmd = 'verb'
|
17
|
+
@stdin = nil
|
18
|
+
@stdout = nil
|
19
|
+
@stderr = nil
|
20
|
+
@value = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_open3_version
|
24
|
+
assert_equal('0.3.1', Open3::WIN32_OPEN3_VERSION)
|
25
|
+
assert_equal('0.3.1', Open4::WIN32_OPEN3_VERSION)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_open3_basic
|
29
|
+
assert_respond_to(Open3, :popen3)
|
30
|
+
assert_nothing_raised{ Open3.popen3(@good_cmd) }
|
31
|
+
assert_nothing_raised{ Open3.popen3(@bad_cmd) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_open4_basic
|
35
|
+
assert_respond_to(Open4, :popen4)
|
36
|
+
assert_nothing_raised{ Open4.popen4(@good_cmd) }
|
37
|
+
assert_nothing_raised{ Open4.popen4(@bad_cmd) }
|
38
|
+
end
|
39
|
+
|
40
|
+
# This test would fail on other platforms
|
41
|
+
def test_open3_with_arguments
|
42
|
+
assert_nothing_raised{ Open3.popen3(@good_cmd, 't') }
|
43
|
+
assert_nothing_raised{ Open3.popen3(@bad_cmd, 't') }
|
44
|
+
assert_nothing_raised{ Open3.popen3(@good_cmd, 'b') }
|
45
|
+
assert_nothing_raised{ Open3.popen3(@bad_cmd, 'b') }
|
46
|
+
assert_nothing_raised{ Open3.popen3(@good_cmd, 't', false) }
|
47
|
+
assert_nothing_raised{ Open3.popen3(@good_cmd, 't', true) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_open3_handles
|
51
|
+
arr = Open3.popen3(@good_cmd)
|
52
|
+
assert_kind_of(Array, arr)
|
53
|
+
assert_kind_of(IO, arr[0])
|
54
|
+
assert_kind_of(IO, arr[1])
|
55
|
+
assert_kind_of(IO, arr[2])
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_open3_block
|
59
|
+
assert_nothing_raised{ Open3.popen3(@good_cmd){ |pin, pout, perr| } }
|
60
|
+
Open3.popen3(@good_cmd){ |pin, pout, perr|
|
61
|
+
assert_kind_of(IO, pin)
|
62
|
+
assert_kind_of(IO, pout)
|
63
|
+
assert_kind_of(IO, perr)
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_open4_block
|
68
|
+
assert_nothing_raised{ Open4.popen4(@good_cmd){ |pin, pout, perr, pid| } }
|
69
|
+
Open4.popen4(@good_cmd){ |pin, pout, perr, pid|
|
70
|
+
assert_kind_of(IO, pin)
|
71
|
+
assert_kind_of(IO, pout)
|
72
|
+
assert_kind_of(IO, perr)
|
73
|
+
assert_kind_of(Fixnum, pid)
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_open4_return_values
|
78
|
+
arr = Open4.popen4(@good_cmd)
|
79
|
+
assert_kind_of(Array,arr)
|
80
|
+
assert_kind_of(IO, arr[0])
|
81
|
+
assert_kind_of(IO, arr[1])
|
82
|
+
assert_kind_of(IO, arr[2])
|
83
|
+
assert_kind_of(Fixnum, arr[3])
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_handle_good_content
|
87
|
+
fin, fout, ferr = Open3.popen3(@good_cmd)
|
88
|
+
assert_kind_of(String, fout.gets)
|
89
|
+
assert_nil(ferr.gets)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_handle_bad_content
|
93
|
+
fin, fout, ferr = Open3.popen3(@bad_cmd)
|
94
|
+
assert_kind_of(String, ferr.gets)
|
95
|
+
assert_nil(fout.gets)
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_exit_status_in_block_form_popen4
|
99
|
+
assert_nothing_raised{ @value = Open3.popen3('dir'){ |x,y,z| 1 } }
|
100
|
+
assert_equal(1, @value)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_exit_status_in_block_form_popen4
|
104
|
+
assert_nothing_raised{ @value = Open4.popen4('dir'){ |x,y,z,a| 1 } }
|
105
|
+
assert_equal(1, @value)
|
106
|
+
end
|
107
|
+
|
108
|
+
def teardown
|
109
|
+
@good_cmd = nil
|
110
|
+
@bad_cmd = nil
|
111
|
+
@value = nil
|
112
|
+
end
|
113
|
+
end
|
data/win32-open3.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'win32-open3'
|
5
|
+
spec.version = '0.3.2'
|
6
|
+
spec.authors = ['Park Heesob', 'Daniel J. Berger']
|
7
|
+
spec.email = 'djberg96@gmail.com'
|
8
|
+
spec.homepage = 'http://www.rubyforge.org/projects/win32utils'
|
9
|
+
spec.platform = Gem::Platform::RUBY
|
10
|
+
spec.summary = 'Provides an Open3.popen3 implementation for MS Windows'
|
11
|
+
spec.test_file = 'test/test_win32_open3.rb'
|
12
|
+
spec.has_rdoc = true
|
13
|
+
spec.license = 'Artistic 2.0'
|
14
|
+
spec.extensions = ['ext/extconf.rb']
|
15
|
+
spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
|
16
|
+
|
17
|
+
spec.extra_rdoc_files = [
|
18
|
+
'CHANGES',
|
19
|
+
'README',
|
20
|
+
'MANIFEST',
|
21
|
+
'doc/open3.txt',
|
22
|
+
'ext/win32/open3.c'
|
23
|
+
]
|
24
|
+
|
25
|
+
spec.rubyforge_project = 'win32utils'
|
26
|
+
spec.required_ruby_version = '< 1.9.0'
|
27
|
+
|
28
|
+
spec.description = <<-EOF
|
29
|
+
The win32-open3 library provides a working implementation of the open3
|
30
|
+
library for MS Windows. In addition, it provides the Open4 class, which
|
31
|
+
also returns pid information.
|
32
|
+
|
33
|
+
Note that this library is unnecessary with Ruby 1.9.x because of its
|
34
|
+
support for native threads.
|
35
|
+
EOF
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: win32-open3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.2
|
5
|
+
platform: x86-mingw32
|
6
|
+
authors:
|
7
|
+
- Park Heesob
|
8
|
+
- Daniel J. Berger
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2010-01-23 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: " The win32-open3 library provides a working implementation of the open3\n library for MS Windows. In addition, it provides the Open4 class, which\n also returns pid information.\n \n Note that this library is unnecessary with Ruby 1.9.x because of its\n support for native threads.\n"
|
18
|
+
email: djberg96@gmail.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- CHANGES
|
25
|
+
- README
|
26
|
+
- MANIFEST
|
27
|
+
- doc/open3.txt
|
28
|
+
- ext/win32/open3.c
|
29
|
+
files:
|
30
|
+
- CHANGES
|
31
|
+
- doc/open3.txt
|
32
|
+
- examples/win32_open3_example.rb
|
33
|
+
- lib/win32/open3.so
|
34
|
+
- MANIFEST
|
35
|
+
- Rakefile
|
36
|
+
- README
|
37
|
+
- test/test_win32_open3.rb
|
38
|
+
- win32-open3.gemspec
|
39
|
+
- ext/win32/open3.c
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://www.rubyforge.org/projects/win32utils
|
42
|
+
licenses:
|
43
|
+
- Artistic 2.0
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - <
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.9.0
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project: win32utils
|
64
|
+
rubygems_version: 1.3.5
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: Provides an Open3.popen3 implementation for MS Windows
|
68
|
+
test_files:
|
69
|
+
- test/test_win32_open3.rb
|