io-extra 1.2.8 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/CHANGES +11 -0
- data/MANIFEST +2 -1
- data/README +11 -7
- data/ext/extconf.rb +0 -4
- data/ext/io/extra.c +144 -225
- data/lib/io-extra.rb +1 -0
- data/test/test_io_extra.rb +2 -1
- metadata +44 -22
- metadata.gz.sig +0 -0
- data/.gemtest +0 -0
- data/Rakefile +0 -98
- data/doc/io_extra.txt +0 -85
- data/examples/example_io_extra.rb +0 -42
- data/examples/example_pread.rb +0 -24
- data/io-extra.gemspec +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e110a14a9b41e4ae67f06a04338ebba468ae3731b1ed8d940606cfc50f56fa11
|
4
|
+
data.tar.gz: 90bc28cf009765f3cdefdeb4fa6028b4269a2b58067ceb9272f58fdfd75e5352
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dbb68585d84b9e0fde2b4e508749500eb86993157aeff7ce830e7b86676ac96027ef6ba18bac8ec1258f16f5b1331a97d5187de90237858828361928c888bc2
|
7
|
+
data.tar.gz: 66beb1736b6ca2d846aa0eeca812dcf317b90463b260a18f439197090df1de51d4117c9ae233ddcc9c687e84967af30446a270ec8e8ffd229636f9413ae70d6f
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
���$��d�/�56?�����I�π�T2�F������v3��wscmk
|
data/CHANGES
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
== 1.3.0 - 19-Oct-2018
|
2
|
+
* Now assumes Ruby 2.1 or later. This has no effect on the external API, but
|
3
|
+
it does allow for lots of internal cleanup.
|
4
|
+
* License changed to Apache-2.0.
|
5
|
+
* The EXTRA_VERSION constant is now frozen.
|
6
|
+
* Added the io-extra.rb file for convenience.
|
7
|
+
* Updates to the gemspec, including the addition of metadata.
|
8
|
+
* The Rakefile now assumes Rubygems 2.0 or later.
|
9
|
+
* Added a cert.
|
10
|
+
* Removed the .gemtest file.
|
11
|
+
|
1
12
|
== 1.2.8 - 29-Dec-2014
|
2
13
|
* Updated for compatibility with Ruby 2.2.x.
|
3
14
|
|
data/MANIFEST
CHANGED
data/README
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
gem install io-extra
|
12
12
|
|
13
13
|
= Synopsis
|
14
|
-
require 'io/extra'
|
14
|
+
require 'io/extra' # or 'io-extra'
|
15
15
|
|
16
16
|
# Close all file descriptors from 3 up.
|
17
17
|
IO.closefrom(3)
|
@@ -45,9 +45,9 @@
|
|
45
45
|
of IO.fdwalk and a pure Ruby version that looks something like this:
|
46
46
|
|
47
47
|
def IO.fdwalk(n)
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
ObjectSpace.each_object(File){ |f|
|
49
|
+
yield f if f.fileno >= n
|
50
|
+
}
|
51
51
|
end
|
52
52
|
|
53
53
|
The primary difference is that this only closes Ruby file objects, not
|
@@ -67,21 +67,25 @@
|
|
67
67
|
The IO.writev tests fail on Solaris. Short test scripts seem to work,
|
68
68
|
however. We're not sure what the issue is yet. Help wanted.
|
69
69
|
|
70
|
+
Update: As of 2018 Solaris is basically dead, so I'm not going to worry
|
71
|
+
about supporting Solaris unless there's an outcry.
|
72
|
+
|
70
73
|
Please file any bug reports on the project page at
|
71
74
|
https://github.com/djberg96/io-extra
|
72
75
|
|
73
76
|
= Future Plans
|
74
|
-
* Switch from C extension to FFI.
|
77
|
+
* Switch from C extension to FFI (maybe).
|
78
|
+
* Add the IO.pselect method.
|
75
79
|
|
76
80
|
= Acknowledgements
|
77
81
|
Eric Wong for some great work on Linux compatibility and other fixes, as
|
78
82
|
well as the code for the IO.writev method.
|
79
83
|
|
80
84
|
= License
|
81
|
-
|
85
|
+
Apache-2.0
|
82
86
|
|
83
87
|
= Copyright
|
84
|
-
(C) 2003-
|
88
|
+
(C) 2003-2018 Daniel J. Berger
|
85
89
|
All Rights Reserved
|
86
90
|
|
87
91
|
= Warranty
|
data/ext/extconf.rb
CHANGED
@@ -13,11 +13,7 @@ have_func('directio')
|
|
13
13
|
have_func('pread')
|
14
14
|
have_func('pwrite')
|
15
15
|
have_func('writev')
|
16
|
-
have_func('rb_str_set_len', 'ruby.h')
|
17
|
-
have_func('rb_thread_blocking_region')
|
18
16
|
have_func('ttyname')
|
19
|
-
have_func('rb_reserved_fd_p')
|
20
|
-
have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
|
21
17
|
|
22
18
|
case RbConfig::CONFIG['host_os']
|
23
19
|
when /darwin/i
|
data/ext/io/extra.c
CHANGED
@@ -1,10 +1,7 @@
|
|
1
1
|
/* Extra methods for the IO class */
|
2
2
|
#include "ruby.h"
|
3
|
-
#ifdef HAVE_RUBY_IO_H
|
4
3
|
#include "ruby/io.h"
|
5
|
-
#
|
6
|
-
#include "rubyio.h"
|
7
|
-
#endif
|
4
|
+
#include "ruby/thread.h"
|
8
5
|
|
9
6
|
#include <unistd.h>
|
10
7
|
#include <stdlib.h>
|
@@ -26,69 +23,11 @@
|
|
26
23
|
#if defined(_SC_IOV_MAX)
|
27
24
|
#define IOV_MAX (sysconf(_SC_IOV_MAX))
|
28
25
|
#else
|
29
|
-
|
26
|
+
// Assume infinity, or let the syscall return with error
|
30
27
|
#define IOV_MAX INT_MAX
|
31
28
|
#endif
|
32
29
|
#endif
|
33
30
|
|
34
|
-
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
|
35
|
-
#include <ruby/thread.h>
|
36
|
-
#endif
|
37
|
-
|
38
|
-
#if ! defined(HAVE_RB_THREAD_BLOCKING_REGION) && \
|
39
|
-
! defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
40
|
-
/*
|
41
|
-
* Partial emulation of the 1.9 rb_thread_blocking_region under 1.8,
|
42
|
-
* this is enough to ensure signals are processed safely when doing I/O
|
43
|
-
* to a slow device, but doesn't actually ensure threads can be
|
44
|
-
* scheduled fairly in 1.8.
|
45
|
-
*/
|
46
|
-
#include <rubysig.h>
|
47
|
-
#define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
|
48
|
-
typedef void rb_unblock_function_t(void *);
|
49
|
-
typedef VALUE rb_blocking_function_t(void *);
|
50
|
-
static VALUE
|
51
|
-
rb_thread_blocking_region(
|
52
|
-
rb_blocking_function_t *fn, void *data1,
|
53
|
-
rb_unblock_function_t *ubf, void *data2)
|
54
|
-
{
|
55
|
-
VALUE rv;
|
56
|
-
|
57
|
-
TRAP_BEG;
|
58
|
-
rv = fn(data1);
|
59
|
-
TRAP_END;
|
60
|
-
|
61
|
-
return rv;
|
62
|
-
}
|
63
|
-
#endif
|
64
|
-
|
65
|
-
#ifndef RSTRING_PTR
|
66
|
-
#define RSTRING_PTR(v) (RSTRING(v)->ptr)
|
67
|
-
#define RSTRING_LEN(v) (RSTRING(v)->len)
|
68
|
-
#endif
|
69
|
-
|
70
|
-
#ifndef HAVE_RB_STR_SET_LEN
|
71
|
-
/* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
|
72
|
-
static void rb_18_str_set_len(VALUE str, long len)
|
73
|
-
{
|
74
|
-
RSTRING(str)->len = len;
|
75
|
-
RSTRING(str)->ptr[len] = '\0';
|
76
|
-
}
|
77
|
-
#define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
|
78
|
-
#endif
|
79
|
-
|
80
|
-
/*
|
81
|
-
* Matz Ruby 1.9.3 has rb_reserved_fd_p() because it uses an internal
|
82
|
-
* timer thread + pipe to communicate signal wakeups (1.9.0 - 1.9.2
|
83
|
-
* wokeup every 10ms to check for signals). Accidentally closing this
|
84
|
-
* pipe breaks the VM completely, so we use this function to avoid it.
|
85
|
-
* This can be safely made a no-op for Ruby implementations that do
|
86
|
-
* not have this function (since it implies the VM does not reserve FDs)
|
87
|
-
*/
|
88
|
-
#ifndef RB_RESERVED_FD_P
|
89
|
-
#define RB_RESERVED_FD_P(fd) (0)
|
90
|
-
#endif
|
91
|
-
|
92
31
|
#ifdef PROC_SELF_FD_DIR
|
93
32
|
#include <dirent.h>
|
94
33
|
#endif
|
@@ -147,20 +86,16 @@ static int open_max(void){
|
|
147
86
|
* The manual approach was copied from the closefrom() man page on Solaris 9.
|
148
87
|
*/
|
149
88
|
static VALUE io_closefrom(VALUE klass, VALUE v_low_fd){
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
#else
|
154
|
-
int i, lowfd;
|
155
|
-
int maxfd = open_max();
|
156
|
-
lowfd = NUM2INT(v_low_fd);
|
89
|
+
int i, lowfd;
|
90
|
+
int maxfd = open_max();
|
91
|
+
lowfd = NUM2INT(v_low_fd);
|
157
92
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
93
|
+
for(i = lowfd; i < maxfd; i++) {
|
94
|
+
if(!RB_RESERVED_FD_P(i))
|
95
|
+
close(i);
|
96
|
+
}
|
97
|
+
|
98
|
+
return klass;
|
164
99
|
}
|
165
100
|
|
166
101
|
#ifndef HAVE_FDWALK
|
@@ -226,6 +161,7 @@ static int close_func(void* lowfd, int fd){
|
|
226
161
|
if(fd >= *(int*)lowfd){
|
227
162
|
if (RB_RESERVED_FD_P(fd))
|
228
163
|
return 0;
|
164
|
+
|
229
165
|
v_args[0] = UINT2NUM(fd);
|
230
166
|
rb_yield(rb_class_new_instance(1, v_args, rb_cFile));
|
231
167
|
}
|
@@ -242,15 +178,15 @@ static int close_func(void* lowfd, int fd){
|
|
242
178
|
* Not supported on all platforms.
|
243
179
|
*/
|
244
180
|
static VALUE io_fdwalk(int argc, VALUE* argv, VALUE klass){
|
245
|
-
|
246
|
-
|
181
|
+
VALUE v_low_fd, v_block;
|
182
|
+
int lowfd;
|
247
183
|
|
248
|
-
|
249
|
-
|
184
|
+
rb_scan_args(argc, argv, "1&", &v_low_fd, &v_block);
|
185
|
+
lowfd = NUM2INT(v_low_fd);
|
250
186
|
|
251
|
-
|
187
|
+
fdwalk(close_func, &lowfd);
|
252
188
|
|
253
|
-
|
189
|
+
return klass;
|
254
190
|
}
|
255
191
|
#endif
|
256
192
|
|
@@ -264,20 +200,20 @@ static VALUE io_fdwalk(int argc, VALUE* argv, VALUE klass){
|
|
264
200
|
*/
|
265
201
|
static VALUE io_get_directio(VALUE self){
|
266
202
|
#if defined(HAVE_DIRECTIO) || defined(F_NOCACHE)
|
267
|
-
|
203
|
+
VALUE v_advice = rb_iv_get(self, "@directio");
|
268
204
|
|
269
|
-
|
270
|
-
|
205
|
+
if(NIL_P(v_advice))
|
206
|
+
v_advice = Qfalse;
|
271
207
|
|
272
|
-
|
208
|
+
return v_advice;
|
273
209
|
#elif defined(O_DIRECT)
|
274
|
-
|
275
|
-
|
210
|
+
int fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
|
211
|
+
int flags = fcntl(fd, F_GETFL);
|
276
212
|
|
277
|
-
|
278
|
-
|
213
|
+
if(flags < 0)
|
214
|
+
rb_sys_fail("fcntl");
|
279
215
|
|
280
|
-
|
216
|
+
return (flags & O_DIRECT) ? Qtrue : Qfalse;
|
281
217
|
#endif /* O_DIRECT */
|
282
218
|
}
|
283
219
|
|
@@ -350,17 +286,16 @@ static VALUE io_set_directio(VALUE self, VALUE v_advice){
|
|
350
286
|
|
351
287
|
#ifdef HAVE_PREAD
|
352
288
|
struct pread_args {
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
289
|
+
int fd;
|
290
|
+
void *buf;
|
291
|
+
size_t nbyte;
|
292
|
+
off_t offset;
|
357
293
|
};
|
358
294
|
|
359
295
|
static VALUE nogvl_pread(void *ptr)
|
360
296
|
{
|
361
|
-
|
362
|
-
|
363
|
-
return (VALUE)pread(args->fd, args->buf, args->nbyte, args->offset);
|
297
|
+
struct pread_args *args = ptr;
|
298
|
+
return (VALUE)pread(args->fd, args->buf, args->nbyte, args->offset);
|
364
299
|
}
|
365
300
|
|
366
301
|
/*
|
@@ -371,28 +306,25 @@ static VALUE nogvl_pread(void *ptr)
|
|
371
306
|
* the +fd+, +length+ and +offset+ arguments are all mandatory.
|
372
307
|
*/
|
373
308
|
static VALUE s_io_pread(VALUE klass, VALUE fd, VALUE nbyte, VALUE offset){
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
#endif
|
309
|
+
struct pread_args args;
|
310
|
+
VALUE str;
|
311
|
+
ssize_t nread;
|
312
|
+
|
313
|
+
args.fd = NUM2INT(fd);
|
314
|
+
args.nbyte = NUM2ULONG(nbyte);
|
315
|
+
args.offset = NUM2OFFT(offset);
|
316
|
+
str = rb_str_new(NULL, args.nbyte);
|
317
|
+
args.buf = RSTRING_PTR(str);
|
318
|
+
|
319
|
+
nread = (ssize_t)rb_thread_call_without_gvl((void*)nogvl_pread, &args, RUBY_UBF_IO, 0);
|
320
|
+
|
321
|
+
if(nread == -1)
|
322
|
+
rb_sys_fail("pread");
|
389
323
|
|
390
|
-
|
391
|
-
|
392
|
-
if ((size_t)nread != args.nbyte)
|
393
|
-
rb_str_set_len(str, nread);
|
324
|
+
if((size_t)nread != args.nbyte)
|
325
|
+
rb_str_set_len(str, nread);
|
394
326
|
|
395
|
-
|
327
|
+
return str;
|
396
328
|
}
|
397
329
|
|
398
330
|
/*
|
@@ -422,17 +354,16 @@ static VALUE s_io_pread_ptr(VALUE klass, VALUE v_fd, VALUE v_nbyte, VALUE v_offs
|
|
422
354
|
|
423
355
|
#ifdef HAVE_PWRITE
|
424
356
|
struct pwrite_args {
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
357
|
+
int fd;
|
358
|
+
const void *buf;
|
359
|
+
size_t nbyte;
|
360
|
+
off_t offset;
|
429
361
|
};
|
430
362
|
|
431
363
|
static VALUE nogvl_pwrite(void *ptr)
|
432
364
|
{
|
433
|
-
|
434
|
-
|
435
|
-
return (VALUE)pwrite(args->fd, args->buf, args->nbyte, args->offset);
|
365
|
+
struct pwrite_args *args = ptr;
|
366
|
+
return (VALUE)pwrite(args->fd, args->buf, args->nbyte, args->offset);
|
436
367
|
}
|
437
368
|
|
438
369
|
/*
|
@@ -447,24 +378,20 @@ static VALUE nogvl_pwrite(void *ptr)
|
|
447
378
|
* Returns the number of bytes written.
|
448
379
|
*/
|
449
380
|
static VALUE s_io_pwrite(VALUE klass, VALUE fd, VALUE buf, VALUE offset){
|
450
|
-
|
451
|
-
|
381
|
+
ssize_t result;
|
382
|
+
struct pwrite_args args;
|
452
383
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
384
|
+
args.fd = NUM2INT(fd);
|
385
|
+
args.buf = RSTRING_PTR(buf);
|
386
|
+
args.nbyte = RSTRING_LEN(buf);
|
387
|
+
args.offset = NUM2OFFT(offset);
|
457
388
|
|
458
|
-
|
459
|
-
result = (ssize_t)rb_thread_call_without_gvl((void*)nogvl_pwrite, &args, RUBY_UBF_IO, 0);
|
460
|
-
#else
|
461
|
-
result = (ssize_t)rb_thread_blocking_region(nogvl_pwrite, &args, RUBY_UBF_IO, 0);
|
462
|
-
#endif
|
389
|
+
result = (ssize_t)rb_thread_call_without_gvl((void*)nogvl_pwrite, &args, RUBY_UBF_IO, 0);
|
463
390
|
|
464
|
-
|
465
|
-
|
391
|
+
if(result == -1)
|
392
|
+
rb_sys_fail("pwrite");
|
466
393
|
|
467
|
-
|
394
|
+
return ULL2NUM(result);
|
468
395
|
}
|
469
396
|
#endif
|
470
397
|
|
@@ -494,16 +421,15 @@ static VALUE s_io_pwrite(VALUE klass, VALUE fd, VALUE buf, VALUE offset){
|
|
494
421
|
|
495
422
|
#if defined(HAVE_WRITEV)
|
496
423
|
struct writev_args {
|
497
|
-
|
498
|
-
|
499
|
-
|
424
|
+
int fd;
|
425
|
+
struct iovec *iov;
|
426
|
+
int iovcnt;
|
500
427
|
};
|
501
428
|
|
502
429
|
static VALUE nogvl_writev(void *ptr)
|
503
430
|
{
|
504
|
-
|
505
|
-
|
506
|
-
return (VALUE)writev(args->fd, args->iov, args->iovcnt);
|
431
|
+
struct writev_args *args = ptr;
|
432
|
+
return (VALUE)writev(args->fd, args->iov, args->iovcnt);
|
507
433
|
}
|
508
434
|
|
509
435
|
/*
|
@@ -518,75 +444,68 @@ static VALUE nogvl_writev(void *ptr)
|
|
518
444
|
* Returns the number of bytes written.
|
519
445
|
*/
|
520
446
|
static VALUE s_io_writev(VALUE klass, VALUE fd, VALUE ary) {
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
args.fd = NUM2INT(fd);
|
526
|
-
ARY2IOVEC(args.iov, args.iovcnt, left, ary);
|
527
|
-
|
528
|
-
for(;;) {
|
529
|
-
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
|
530
|
-
ssize_t w = (ssize_t)rb_thread_call_without_gvl(
|
531
|
-
(void*)nogvl_writev, &args, RUBY_UBF_IO, 0
|
532
|
-
);
|
533
|
-
#else
|
534
|
-
ssize_t w = (ssize_t)rb_thread_blocking_region(
|
535
|
-
nogvl_writev, &args, RUBY_UBF_IO, 0
|
536
|
-
);
|
537
|
-
#endif
|
447
|
+
ssize_t result = 0;
|
448
|
+
ssize_t left;
|
449
|
+
struct writev_args args;
|
538
450
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
451
|
+
args.fd = NUM2INT(fd);
|
452
|
+
ARY2IOVEC(args.iov, args.iovcnt, left, ary);
|
453
|
+
|
454
|
+
for(;;) {
|
455
|
+
ssize_t w = (ssize_t)rb_thread_call_without_gvl(
|
456
|
+
(void*)nogvl_writev, &args, RUBY_UBF_IO, 0
|
457
|
+
);
|
458
|
+
|
459
|
+
if(w == -1){
|
460
|
+
if(rb_io_wait_writable(args.fd)){
|
461
|
+
continue;
|
462
|
+
}
|
463
|
+
else{
|
464
|
+
if(result > 0){
|
465
|
+
/* unlikely to hit this case, return the already written bytes,
|
466
|
+
* we'll let the next write (or close) fail instead */
|
467
|
+
break;
|
468
|
+
}
|
469
|
+
rb_sys_fail("writev");
|
552
470
|
}
|
471
|
+
}
|
553
472
|
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
/* skip over iovecs we've already written completely */
|
564
|
-
for (i = 0; i < args.iovcnt; i++, new_iov++) {
|
565
|
-
if (w == 0)
|
566
|
-
break;
|
567
|
-
|
568
|
-
/*
|
569
|
-
* partially written iov,
|
570
|
-
* modify and retry with current iovec in front
|
571
|
-
*/
|
572
|
-
if (new_iov->iov_len > (size_t)w) {
|
573
|
-
VALUE base = (VALUE)new_iov->iov_base;
|
574
|
-
|
575
|
-
new_iov->iov_len -= w;
|
576
|
-
new_iov->iov_base = (void *)(base + w);
|
577
|
-
break;
|
578
|
-
}
|
579
|
-
|
580
|
-
w -= new_iov->iov_len;
|
581
|
-
}
|
473
|
+
result += w;
|
474
|
+
|
475
|
+
if(w == left){
|
476
|
+
break;
|
477
|
+
}
|
478
|
+
else{
|
479
|
+
// Partial write, this can get tricky
|
480
|
+
int i;
|
481
|
+
struct iovec *new_iov = args.iov;
|
582
482
|
|
583
|
-
|
584
|
-
|
585
|
-
|
483
|
+
left -= w;
|
484
|
+
|
485
|
+
// Skip over iovecs we've already written completely
|
486
|
+
for(i = 0; i < args.iovcnt; i++, new_iov++){
|
487
|
+
if (w == 0)
|
488
|
+
break;
|
489
|
+
|
490
|
+
// Partially written iov, modify and retry with current iovec in front
|
491
|
+
if(new_iov->iov_len > (size_t)w){
|
492
|
+
VALUE base = (VALUE)new_iov->iov_base;
|
493
|
+
|
494
|
+
new_iov->iov_len -= w;
|
495
|
+
new_iov->iov_base = (void *)(base + w);
|
496
|
+
break;
|
497
|
+
}
|
498
|
+
|
499
|
+
w -= new_iov->iov_len;
|
586
500
|
}
|
587
|
-
}
|
588
501
|
|
589
|
-
|
502
|
+
// Retry without the already-written iovecs
|
503
|
+
args.iovcnt -= i;
|
504
|
+
args.iov = new_iov;
|
505
|
+
}
|
506
|
+
}
|
507
|
+
|
508
|
+
return LONG2NUM(result);
|
590
509
|
}
|
591
510
|
#endif
|
592
511
|
|
@@ -617,47 +536,47 @@ static VALUE io_get_ttyname(VALUE self){
|
|
617
536
|
* and IO#directio? instance methods (if supported on your platform).
|
618
537
|
*/
|
619
538
|
void Init_extra(){
|
620
|
-
|
539
|
+
rb_define_singleton_method(rb_cIO, "closefrom", io_closefrom, 1);
|
621
540
|
|
622
541
|
#ifdef HAVE_FDWALK
|
623
|
-
|
542
|
+
rb_define_singleton_method(rb_cIO, "fdwalk", io_fdwalk, -1);
|
624
543
|
#endif
|
625
544
|
|
626
545
|
#if defined(HAVE_DIRECTIO) || defined(O_DIRECT) || defined(F_NOCACHE)
|
627
|
-
|
628
|
-
|
546
|
+
rb_define_method(rb_cIO, "directio?", io_get_directio, 0);
|
547
|
+
rb_define_method(rb_cIO, "directio=", io_set_directio, 1);
|
629
548
|
|
630
|
-
|
631
|
-
|
549
|
+
/* 0: Applications get the default system behavior when accessing file data. */
|
550
|
+
rb_define_const(rb_cIO, "DIRECTIO_OFF", UINT2NUM(DIRECTIO_OFF));
|
632
551
|
|
633
|
-
|
634
|
-
|
552
|
+
/* 1: File data is not cached in the system's memory pages. */
|
553
|
+
rb_define_const(rb_cIO, "DIRECTIO_ON", UINT2NUM(DIRECTIO_ON));
|
635
554
|
#endif
|
636
555
|
|
637
556
|
#ifdef O_DIRECT
|
638
|
-
|
639
|
-
|
557
|
+
/* 040000: direct disk access (in Linux) */
|
558
|
+
rb_define_const(rb_cIO, "DIRECT", UINT2NUM(O_DIRECT));
|
640
559
|
#endif
|
641
560
|
|
642
|
-
|
561
|
+
rb_define_const(rb_cIO, "IOV_MAX", LONG2NUM(IOV_MAX));
|
643
562
|
|
644
563
|
#ifdef HAVE_PREAD
|
645
|
-
|
646
|
-
|
564
|
+
rb_define_singleton_method(rb_cIO, "pread", s_io_pread, 3);
|
565
|
+
rb_define_singleton_method(rb_cIO, "pread_ptr", s_io_pread_ptr, 3);
|
647
566
|
#endif
|
648
567
|
|
649
568
|
#ifdef HAVE_PWRITE
|
650
|
-
|
569
|
+
rb_define_singleton_method(rb_cIO, "pwrite", s_io_pwrite, 3);
|
651
570
|
#endif
|
652
571
|
|
653
572
|
#ifdef HAVE_WRITEV
|
654
|
-
|
573
|
+
rb_define_singleton_method(rb_cIO, "writev", s_io_writev, 2);
|
655
574
|
#endif
|
656
575
|
|
657
576
|
#ifdef HAVE_TTYNAME
|
658
577
|
rb_define_method(rb_cIO, "ttyname", io_get_ttyname, 0);
|
659
578
|
#endif
|
660
579
|
|
661
|
-
|
662
|
-
|
580
|
+
/* 1.3.0: The version of this library. */
|
581
|
+
rb_define_const(rb_cIO, "EXTRA_VERSION", rb_str_freeze(rb_str_new2("1.3.0")));
|
663
582
|
}
|
data/lib/io-extra.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'io/extra'
|
data/test/test_io_extra.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-extra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIEcDCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MREwDwYDVQQDDAhkamJl
|
14
|
+
cmc5NjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t
|
15
|
+
MB4XDTE4MDMxODE1MjIwN1oXDTI4MDMxNTE1MjIwN1owPzERMA8GA1UEAwwIZGpi
|
16
|
+
ZXJnOTYxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
|
17
|
+
bTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALgfaroVM6CI06cxr0/h
|
18
|
+
A+j+pc8fgpRgBVmHFaFunq28GPC3IvW7Nvc3Y8SnAW7pP1EQIbhlwRIaQzJ93/yj
|
19
|
+
u95KpkP7tA9erypnV7dpzBkzNlX14ACaFD/6pHoXoe2ltBxk3CCyyzx70mTqJpph
|
20
|
+
75IB03ni9a8yqn8pmse+s83bFJOAqddSj009sGPcQO+QOWiNxqYv1n5EHcvj2ebO
|
21
|
+
6hN7YTmhx7aSia4qL/quc4DlIaGMWoAhvML7u1fmo53CYxkKskfN8MOecq2vfEmL
|
22
|
+
iLu+SsVVEAufMDDFMXMJlvDsviolUSGMSNRTujkyCcJoXKYYxZSNtIiyd9etI0X3
|
23
|
+
ctu0uhrFyrMZXCedutvXNjUolD5r9KGBFSWH1R9u2I3n3SAyFF2yzv/7idQHLJJq
|
24
|
+
74BMnx0FIq6fCpu5slAipvxZ3ZkZpEXZFr3cIBtO1gFvQWW7E/Y3ijliWJS1GQFq
|
25
|
+
058qERadHGu1yu1dojmFRo6W2KZvY9al2yIlbkpDrD5MYQIDAQABo3cwdTAJBgNV
|
26
|
+
HRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUFZsMapgzJimzsbaBG2Tm8j5e
|
27
|
+
AzgwHQYDVR0RBBYwFIESZGpiZXJnOTZAZ21haWwuY29tMB0GA1UdEgQWMBSBEmRq
|
28
|
+
YmVyZzk2QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAW2tnYixXQtKxgGXq
|
29
|
+
/3iSWG2bLwvxS4go3srO+aRXZHrFUMlJ5W0mCxl03aazxxKTsVVpZD8QZxvK91OQ
|
30
|
+
h9zr9JBYqCLcCVbr8SkmYCi/laxIZxsNE5YI8cC8vvlLI7AMgSfPSnn/Epq1GjGY
|
31
|
+
6L1iRcEDtanGCIvjqlCXO9+BmsnCfEVehqZkQHeYczA03tpOWb6pon2wzvMKSsKH
|
32
|
+
ks0ApVdstSLz1kzzAqem/uHdG9FyXdbTAwH1G4ZPv69sQAFAOCgAqYmdnzedsQtE
|
33
|
+
1LQfaQrx0twO+CZJPcRLEESjq8ScQxWRRkfuh2VeR7cEU7L7KqT10mtUwrvw7APf
|
34
|
+
DYoeCY9KyjIBjQXfbj2ke5u1hZj94Fsq9FfbEQg8ygCgwThnmkTrrKEiMSs3alYR
|
35
|
+
ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
|
36
|
+
WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
|
37
|
+
-----END CERTIFICATE-----
|
38
|
+
date: 2018-10-19 00:00:00.000000000 Z
|
12
39
|
dependencies:
|
13
40
|
- !ruby/object:Gem::Dependency
|
14
41
|
name: test-unit
|
@@ -38,22 +65,17 @@ extra_rdoc_files:
|
|
38
65
|
- MANIFEST
|
39
66
|
- ext/io/extra.c
|
40
67
|
files:
|
41
|
-
-
|
42
|
-
-
|
43
|
-
- MANIFEST
|
44
|
-
- README
|
45
|
-
- Rakefile
|
46
|
-
- doc/io_extra.txt
|
47
|
-
- examples/example_io_extra.rb
|
48
|
-
- examples/example_pread.rb
|
49
|
-
- ext/extconf.rb
|
50
|
-
- ext/io/extra.c
|
51
|
-
- io-extra.gemspec
|
52
|
-
- test/test_io_extra.rb
|
53
|
-
homepage: http://www.rubyforge.org/projects/shards
|
68
|
+
- lib/io-extra.rb
|
69
|
+
homepage: https://github.com/djberg96/io-extra
|
54
70
|
licenses:
|
55
|
-
-
|
56
|
-
metadata:
|
71
|
+
- Apache-2.0
|
72
|
+
metadata:
|
73
|
+
homepage_uri: https://github.com/djberg96/io-extra
|
74
|
+
bug_tracker_uri: https://github.com/djberg96/io-extra/issues
|
75
|
+
changelog_uri: https://github.com/djberg96/io-extra/blob/master/CHANGES
|
76
|
+
documentation_uri: https://github.com/djberg96/io-extra/wiki
|
77
|
+
source_code_uri: https://github.com/djberg96/io-extra
|
78
|
+
wiki_uri: https://github.com/djberg96/io-extra/wiki
|
57
79
|
post_install_message:
|
58
80
|
rdoc_options: []
|
59
81
|
require_paths:
|
@@ -62,17 +84,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
62
84
|
requirements:
|
63
85
|
- - ">="
|
64
86
|
- !ruby/object:Gem::Version
|
65
|
-
version: 1.
|
87
|
+
version: 2.1.0
|
66
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
89
|
requirements:
|
68
90
|
- - ">="
|
69
91
|
- !ruby/object:Gem::Version
|
70
92
|
version: '0'
|
71
93
|
requirements: []
|
72
|
-
rubyforge_project:
|
73
|
-
rubygems_version: 2.
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.7.6
|
74
96
|
signing_key:
|
75
97
|
specification_version: 4
|
76
|
-
summary: Adds extra methods to the IO class
|
98
|
+
summary: Adds extra methods to the IO class
|
77
99
|
test_files:
|
78
100
|
- test/test_io_extra.rb
|
metadata.gz.sig
ADDED
Binary file
|
data/.gemtest
DELETED
File without changes
|
data/Rakefile
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'rake'
|
2
|
-
require 'rake/clean'
|
3
|
-
require 'rake/testtask'
|
4
|
-
require 'rbconfig'
|
5
|
-
include RbConfig
|
6
|
-
|
7
|
-
CLEAN.include(
|
8
|
-
'**/*.gem', # Gem files
|
9
|
-
'**/*.rbc', # Rubinius
|
10
|
-
'**/*.o', # C object file
|
11
|
-
'**/*.log', # Ruby extension build log
|
12
|
-
'**/Makefile', # C Makefile
|
13
|
-
'**/conftest.dSYM', # OS X build directory
|
14
|
-
"**/*.#{CONFIG['DLEXT']}" # C shared object
|
15
|
-
)
|
16
|
-
|
17
|
-
if File::ALT_SEPARATOR
|
18
|
-
STDERR.puts 'Not supported on this platform. Exiting.'
|
19
|
-
exit(-1)
|
20
|
-
end
|
21
|
-
|
22
|
-
desc "Build the io-extra library (but don't install it)"
|
23
|
-
task :build => [:clean] do
|
24
|
-
Dir.chdir('ext') do
|
25
|
-
ruby 'extconf.rb'
|
26
|
-
sh 'make'
|
27
|
-
build_file = File.join(Dir.pwd, 'extra.' + CONFIG['DLEXT'])
|
28
|
-
Dir.mkdir('io') unless File.exists?('io')
|
29
|
-
FileUtils.cp(build_file, 'io')
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
namespace :gem do
|
34
|
-
desc 'Create the io-extra gem'
|
35
|
-
task :create => [:clean] do
|
36
|
-
spec = eval(IO.read('io-extra.gemspec'))
|
37
|
-
if Gem::VERSION.to_f >= 2.0
|
38
|
-
require 'rubygems/package'
|
39
|
-
Gem::Package.build(spec)
|
40
|
-
else
|
41
|
-
Gem::Builder.new(spec).build
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
desc "Install the io-extra library as a gem"
|
46
|
-
task :install => [:create] do
|
47
|
-
file = Dir["io-extra*.gem"].last
|
48
|
-
sh "gem install -l #{file}"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
namespace :archive do
|
53
|
-
spec = eval(IO.read('io-extra.gemspec'))
|
54
|
-
file = "io-extra-#{spec.version}"
|
55
|
-
|
56
|
-
desc 'Create an io-extra tarball.'
|
57
|
-
task :tar do
|
58
|
-
file = file + ".tar"
|
59
|
-
cmd = "git archive --format=tar --prefix=#{file}/ -o #{file} HEAD"
|
60
|
-
sh cmd
|
61
|
-
end
|
62
|
-
|
63
|
-
desc 'Create a gzipped tarball for io-extra'
|
64
|
-
task :gz => [:tar] do
|
65
|
-
sh "gzip #{file}"
|
66
|
-
end
|
67
|
-
|
68
|
-
desc 'Create a bzip2 tarball for io-extra'
|
69
|
-
task :bz2 => [:tar] do
|
70
|
-
sh "bzip2 #{file}"
|
71
|
-
end
|
72
|
-
|
73
|
-
desc 'Create a zipped tarball for io-extra'
|
74
|
-
task :zip do
|
75
|
-
sh "git archive --format=zip --prefix=#{file}/ -o #{file}.zip HEAD"
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
desc "Run the example io-extra program"
|
80
|
-
task :example => [:build] do
|
81
|
-
ruby '-Iext examples/example_io_extra.rb'
|
82
|
-
end
|
83
|
-
|
84
|
-
namespace :example do
|
85
|
-
desc "Run the IO.pread example program."
|
86
|
-
task :pread do
|
87
|
-
ruby '-Iext examples/example_io_extra.rb'
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
Rake::TestTask.new do |t|
|
92
|
-
task :test => :build
|
93
|
-
t.libs << 'ext'
|
94
|
-
t.verbose = true
|
95
|
-
t.warning = true
|
96
|
-
end
|
97
|
-
|
98
|
-
task :default => :test
|
data/doc/io_extra.txt
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
= Description
|
2
|
-
The io-extra library provides a few extra IO methods that you may find
|
3
|
-
handy.
|
4
|
-
|
5
|
-
= Supported Platforms
|
6
|
-
Works on most Unix platforms.
|
7
|
-
|
8
|
-
Not supported on MS Windows or OS X.
|
9
|
-
|
10
|
-
= Synopsis
|
11
|
-
require "io/extra"
|
12
|
-
|
13
|
-
# Print the fileno of each file handle and then close it
|
14
|
-
IO.fdwalk(0){ |fh|
|
15
|
-
p fh.fileno
|
16
|
-
fh.close
|
17
|
-
}
|
18
|
-
|
19
|
-
# Close all file handles with a fileno greater than or equal to 2.
|
20
|
-
IO.closefrom(2)
|
21
|
-
|
22
|
-
= Class Methods
|
23
|
-
IO.closefrom(low_fd)
|
24
|
-
Closes all open file descriptors greater than or equal to 'low_fd'.
|
25
|
-
|
26
|
-
This uses your systems native closefrom() function, if supported. If not,
|
27
|
-
this method uses a slightly less efficient manual approach that uses
|
28
|
-
getrlimit() behind the scenes.
|
29
|
-
|
30
|
-
IO.fdwalk(low_fd){ |fh| ... }
|
31
|
-
Iterates over each open file descriptor and yields back a File object.
|
32
|
-
Note that it is up to you to close file handles, if desired, when this
|
33
|
-
method is used.
|
34
|
-
|
35
|
-
Not supported on all platforms.
|
36
|
-
|
37
|
-
IO.pread(fd, length, offset)
|
38
|
-
Reads +length+ bytes of data from the given +fd+, starting at +offset.
|
39
|
-
The primary advantage of this method over Ruby's IO#read method is that
|
40
|
-
it performs the read without changing the file pointer.
|
41
|
-
|
42
|
-
Not supported on all platforms.
|
43
|
-
|
44
|
-
IO.pwrite(fd, buf, offset)
|
45
|
-
Writes +buf+ to the given +fd+, starting at +offset. The primary advantage
|
46
|
-
of this method over a standard seek & write approach is that it performs
|
47
|
-
the write without changing the file pointer.
|
48
|
-
|
49
|
-
Not supported on all platforms.
|
50
|
-
|
51
|
-
= Instance methods
|
52
|
-
IO#directio?
|
53
|
-
Returns true or false, based on whether directio has been set for the
|
54
|
-
current handle. The default is false.
|
55
|
-
|
56
|
-
Note supported on all platforms.
|
57
|
-
|
58
|
-
IO#directio=(io_const)
|
59
|
-
Sets the advice for the current file descriptor using directio(). Valid
|
60
|
-
values are IO::DIRECTIO_ON and IO::DIRECTIO_OFF.
|
61
|
-
|
62
|
-
All file descriptors start at DIRECTIO_OFF, unless your filesystem has
|
63
|
-
been mounted using 'forcedirectio' (and supports that option).
|
64
|
-
|
65
|
-
Not supported on all platforms
|
66
|
-
|
67
|
-
= Constants
|
68
|
-
IO::DIRECTIO_ON
|
69
|
-
This value can be passed to IO#directio= in order to turn directio on for
|
70
|
-
the given file handle.
|
71
|
-
|
72
|
-
This value is only defined if your platform supports the directio()
|
73
|
-
function.
|
74
|
-
IO::DIRECTIO_OFF
|
75
|
-
This value can be passed to IO#directio= in order to turn directio off for
|
76
|
-
the given file handle.
|
77
|
-
|
78
|
-
This value is only defined if your platform supports the directio()
|
79
|
-
function.
|
80
|
-
|
81
|
-
IO::EXTRA_VERSION
|
82
|
-
Returns the current version number of this library as a String.
|
83
|
-
|
84
|
-
= Other documentation
|
85
|
-
See the README for more documentation.
|
@@ -1,42 +0,0 @@
|
|
1
|
-
##############################################################################
|
2
|
-
# test.rb
|
3
|
-
#
|
4
|
-
# This is a small test program for the io-extra library. Modify as you see
|
5
|
-
# fit. You can run this via the 'rake example' task.
|
6
|
-
##############################################################################
|
7
|
-
require "io/extra"
|
8
|
-
p IO::EXTRA_VERSION
|
9
|
-
|
10
|
-
fh = File.open("foo.txt","w+")
|
11
|
-
|
12
|
-
=begin
|
13
|
-
p fh.directio?
|
14
|
-
|
15
|
-
fh.directio = IO::DIRECTIO_ON
|
16
|
-
p fh.directio?
|
17
|
-
|
18
|
-
fh.close
|
19
|
-
=end
|
20
|
-
|
21
|
-
IO.fdwalk(0){ |handle|
|
22
|
-
p handle
|
23
|
-
p handle.fileno
|
24
|
-
puts
|
25
|
-
}
|
26
|
-
|
27
|
-
=begin
|
28
|
-
STDIN.close
|
29
|
-
|
30
|
-
# Should print "Hello" 2 times
|
31
|
-
IO.fdwalk(0){ |fd|
|
32
|
-
puts "Hello #{fd}"
|
33
|
-
}
|
34
|
-
|
35
|
-
|
36
|
-
IO.closefrom(0)
|
37
|
-
|
38
|
-
puts "Done" # Shouldn't see this
|
39
|
-
=end
|
40
|
-
|
41
|
-
fh.close
|
42
|
-
File.delete("foo.txt") if File.exists?("foo.txt")
|
data/examples/example_pread.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
########################################################################
|
2
|
-
# example_pread.rb
|
3
|
-
#
|
4
|
-
# Example program demonstrating the use of IO.pread.
|
5
|
-
########################################################################
|
6
|
-
require 'io/extra'
|
7
|
-
require 'tmpdir'
|
8
|
-
|
9
|
-
# Create a temporary file with a little data in it.
|
10
|
-
file = File.join(Dir.tmpdir, 'pread_test.txt')
|
11
|
-
File.open(file, 'w'){ |fh| 100.times{ |n| fh.puts "Hello: #{n}" } }
|
12
|
-
|
13
|
-
# Read from the file using pread.
|
14
|
-
begin
|
15
|
-
fh = File.open(file)
|
16
|
-
|
17
|
-
puts "Handle position before read: #{fh.pos}"
|
18
|
-
puts IO.pread(fh.fileno, 18, 0)
|
19
|
-
|
20
|
-
puts "Handle position after read: #{fh.pos}"
|
21
|
-
puts IO.pread(fh.fileno, 18, 0)
|
22
|
-
ensure
|
23
|
-
fh.close
|
24
|
-
end
|
data/io-extra.gemspec
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'rbconfig'
|
3
|
-
|
4
|
-
Gem::Specification.new do |spec|
|
5
|
-
if File::ALT_SEPARATOR
|
6
|
-
STDERR.puts 'Not supported on this platform. Exiting.'
|
7
|
-
exit(-1)
|
8
|
-
end
|
9
|
-
|
10
|
-
spec.name = 'io-extra'
|
11
|
-
spec.version = '1.2.8'
|
12
|
-
spec.author = 'Daniel J. Berger'
|
13
|
-
spec.license = 'Artistic 2.0'
|
14
|
-
spec.email = 'djberg96@gmail.com'
|
15
|
-
spec.homepage = 'http://www.rubyforge.org/projects/shards'
|
16
|
-
spec.summary = 'Adds extra methods to the IO class.'
|
17
|
-
spec.test_file = 'test/test_io_extra.rb'
|
18
|
-
spec.extensions = ['ext/extconf.rb']
|
19
|
-
spec.files = Dir['**/*'] << '.gemtest'
|
20
|
-
|
21
|
-
spec.extra_rdoc_files = [
|
22
|
-
'CHANGES',
|
23
|
-
'README',
|
24
|
-
'MANIFEST',
|
25
|
-
'ext/io/extra.c'
|
26
|
-
]
|
27
|
-
|
28
|
-
spec.rubyforge_project = 'shards'
|
29
|
-
spec.required_ruby_version = '>= 1.8.6'
|
30
|
-
|
31
|
-
spec.add_development_dependency('test-unit', '>= 2.5.0')
|
32
|
-
|
33
|
-
spec.description = <<-EOF
|
34
|
-
Adds the IO.closefrom, IO.fdwalk, IO.pread, IO.pread_ptr, IO.pwrite, and
|
35
|
-
IO.writev singleton methods as well as the IO#directio, IO#directio? and
|
36
|
-
IO#ttyname instance methods (for those platforms that support them).
|
37
|
-
EOF
|
38
|
-
end
|