win32-open3 0.2.6-x86-mswin32-60

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