supplement 1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MWJlMThjNWM2NDk3ZmFiMWQ3Y2ZkYWIwZjg2YzhlYjgxYWZjOTE5Mw==
5
+ data.tar.gz: !binary |-
6
+ MGZhYmI5YjQxMWQ0MjNiN2Y0YzVhZjcxY2VmZTkwZWU0YzQ2ZDg4Nw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ Y2M2MTcyZGEyMGMxZjFiZTdjNDM5NzM3OWFjNjRiMzQ4Y2I3MmUxZmNjZTQ4
10
+ MTkyNTNlOTk5NTlkNzhlZmExODE3NmEzZTMxYjBkMzU3ZDY3NTNlMjcxMTQ4
11
+ N2ViZWM2YWFjNjMzNTkwNjhhOWRhZDlhNWE1Njg3NmMyMDYxMzA=
12
+ data.tar.gz: !binary |-
13
+ NDhjNzViMTYzNTljZGNkNzQwYTAyMTI2YWIzYzNlODA3ZWRjZmI0MThlOTUx
14
+ OWUyMmRkYjQwYjcyNWZlNWZkYWFlZTFkMzY4MjFlOTcwYmQxNTQzNjY1ZmU3
15
+ NDgwNTljMGU4NzNlYzgxMjk4N2Y4MWZjZTEwMGY1NTM2M2VhZDk=
data/LICENSE ADDED
@@ -0,0 +1,34 @@
1
+ _ _
2
+ ___ _ _ _ __ _ __ | | ___ _ __ ___ ___ _ __ | |_
3
+ / __| | | | '_ \| '_ \| |/ _ \ '_ ` _ \ / _ \ '_ \| __|
4
+ \__ \ |_| | |_) | |_) | | __/ | | | | | __/ | | | |_
5
+ |___/\__,_| .__/| .__/|_|\___|_| |_| |_|\___|_| |_|\__|
6
+ |_| |_|
7
+
8
+ Copyright (c) 2009-2013, Bertram Scharpf <software@bertram-scharpf.de>.
9
+ All rights reserved.
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are
13
+ met:
14
+
15
+ * Redistributions of source code must retain the above copyright
16
+ notice, this list of conditions and the following disclaimer.
17
+
18
+ * Redistributions in binary form must reproduce the above copyright
19
+ notice, this list of conditions and the following disclaimer in
20
+ the documentation and/or other materials provided with the
21
+ distribution.
22
+
23
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
27
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+
data/README ADDED
@@ -0,0 +1,50 @@
1
+ = supplement 1.6 -- Useful Ruby enhancements
2
+
3
+ Some simple Ruby extensions.
4
+
5
+ == Description
6
+
7
+ These are methods on standard classes that didn't manage to become part of
8
+ the Ruby interpreter. (Although, some are part of Ruby 1.9/1.8.7 but not
9
+ 1.8.6).
10
+
11
+ They are all very small, most of them have less than 15 lines of code.
12
+ So they would not be a weight in the Ruby interpreter but it is very
13
+ difficult to convince a majority that they belong there.
14
+
15
+ The methods won't be useful for everybody but some programmers may like
16
+ to make them part of their programming style.
17
+
18
+ If you like to get taunted, then go to the Ruby mailing list and propose
19
+ one of them to be included into the Ruby standard.
20
+
21
+ == Intention
22
+
23
+ In my own code I use quite often a method <code>String#notempty?</code>
24
+ that does almost the same as <code>Numeric#nonzero?</code>. Every
25
+ attempt proposing it for the Ruby standard implementation has failed;
26
+ the discussion evolves the same every time.
27
+
28
+ Now here it is where I can just point to.
29
+
30
+ == Contents (uncomplete)
31
+
32
+ * String#notempty?
33
+ * String#clear
34
+ * String#head
35
+ * String#tail
36
+ * String#rest
37
+ * String#start_with?
38
+ * String#end_with?
39
+ * Array#notempty?
40
+ * Hash#notempty?
41
+ * Struct.[]
42
+ * Interval timer
43
+ * File system stats
44
+ * File#flockb using a block
45
+
46
+ == Warning
47
+
48
+ The RDoc in this project doesn't work properly. If in doubt, refer to the
49
+ source code.
50
+
data/examples/teatimer ADDED
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # teatimer -- Countdown timer
5
+ #
6
+
7
+ # This is an example application for the itimer library.
8
+ # Example:
9
+ #
10
+ # $ teatimer 3m play bell.wav
11
+ # # Count down 3 minutes and the exec the player.
12
+ #
13
+
14
+ require "supplement/itimer"
15
+
16
+
17
+ class TeaTimer
18
+
19
+ M = 60
20
+ H = 60 * M
21
+
22
+ class <<self
23
+
24
+ def from_str time
25
+ seconds = case time
26
+ when /m\z/ then Integer( $`) * M
27
+ when /h\z/ then Integer( $`) * H
28
+ else divide_colons time
29
+ end
30
+ new seconds
31
+ end
32
+
33
+ def run time
34
+ t = from_str time
35
+ t.run
36
+ end
37
+
38
+ private
39
+
40
+ def divide_colons time
41
+ a = time.split ":", -1
42
+ a.map! { |x| Integer( x) }
43
+ a.reverse!
44
+ r = a.shift
45
+ if a.first then r += M * a.shift end
46
+ if a.first then r += H * a.shift end
47
+ a.empty? or raise "Illegal time spec: #{time}."
48
+ r
49
+ end
50
+
51
+ end
52
+
53
+ def initialize seconds
54
+ @seconds = seconds
55
+ end
56
+
57
+ class Done < Exception ; end
58
+
59
+ def run
60
+ trap "SIGALRM" do
61
+ @seconds -= 1
62
+ print_rest
63
+ raise Done if @seconds.zero?
64
+ end
65
+ Process.setitimer 1
66
+ print_rest
67
+ sleep
68
+ rescue Done
69
+ puts
70
+ ensure
71
+ trap "SIGALRM", "DEFAULT"
72
+ Process.setitimer nil
73
+ end
74
+
75
+ private
76
+
77
+ def print_rest
78
+ $stdout.print " \r%02d:%02d:%02d" %
79
+ [ @seconds / H, @seconds % H / M, @seconds % M]
80
+ $stdout.flush
81
+ end
82
+
83
+ end
84
+
85
+ TeaTimer.run $*.first =~ /\A\d+/ ? $*.shift : "3m"
86
+ exec *$* if $*.any?
87
+
data/lib/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ #
2
+ # Rakefile -- build some libraries
3
+ #
4
+
5
+ require "autorake"
6
+
7
+ c = compiler "-O2", "-fPIC"
8
+ l = linker "-shared"
9
+
10
+ rule ".o" => ".c" do |t|
11
+ c.cc t.name, t.source
12
+ end
13
+
14
+ DLs = {
15
+ "supplement.so" => %w(supplement.o sync.o),
16
+ "supplement/filesys.so" => %w(supplement/filesys.o),
17
+ "supplement/itimer.so" => %w(supplement/itimer.o),
18
+ "supplement/terminal.so" => %w(supplement/terminal.o),
19
+ }
20
+
21
+ DLs.each { |k,v|
22
+ task k => v do |t|
23
+ l.cc t.name, t.prerequisites
24
+ end
25
+ }
26
+
27
+ task :default => DLs.keys
28
+
29
+ task :clean do
30
+ FileList[ "**/*.o", "**/*.so"].each { |f| rm_f f }
31
+ end
32
+
data/lib/mkrf_conf ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # mkrf_conf -- configure Supplement
5
+ #
6
+
7
+ require "autorake/mkconfig"
8
+
9
+ Autorake.configure {
10
+
11
+ extending_ruby
12
+
13
+ if RUBY_VERSION < "1.9.2" then
14
+ enable :array_select_bang
15
+ if RUBY_VERSION < "1.9" then
16
+ enable :string_ord
17
+ enable :string_clear
18
+ if RUBY_VERSION < "1.8.7" then
19
+ enable :array_index_with_block
20
+ enable :kernel_tap
21
+ enable :string_start_with
22
+ enable :thread_exclusive
23
+ end
24
+ have_header "rubysig.h"
25
+ end
26
+ end
27
+
28
+ if RUBY_VERSION < "1.9" then
29
+ have_header "ruby.h"
30
+ have_header "st.h"
31
+ have_header "rubyio.h"
32
+ have_header "re.h"
33
+ else
34
+ have_header "ruby/ruby.h"
35
+ have_header "ruby/st.h"
36
+ have_header "ruby/io.h"
37
+ have_header "ruby/re.h"
38
+ end
39
+
40
+ }
41
+
data/lib/supplement.c ADDED
@@ -0,0 +1,1657 @@
1
+ /*
2
+ * supplement.c -- Simple Ruby Extensions
3
+ */
4
+
5
+ #include "supplement.h"
6
+
7
+ #include "sync.h"
8
+
9
+ #if HAVE_HEADER_ST_H
10
+ #include <st.h>
11
+ #elif HAVE_HEADER_RUBY_ST_H
12
+ #include <ruby/st.h>
13
+ #endif
14
+ #if HAVE_HEADER_RUBYIO_H
15
+ #include <rubyio.h>
16
+ #elif HAVE_HEADER_RUBY_IO_H
17
+ #include <ruby/io.h>
18
+ #endif
19
+ #if HAVE_HEADER_RE_H
20
+ #include <re.h>
21
+ #elif HAVE_HEADER_RUBY_RE_H
22
+ #include <ruby/re.h>
23
+ #endif
24
+
25
+ #ifdef FEATURE_THREAD_EXCLUSIVE
26
+ #ifdef HAVE_HEADER_RUBYSIG_H
27
+ #include <rubysig.h>
28
+ #endif
29
+ #endif
30
+
31
+
32
+ #include <sys/stat.h>
33
+ #include <sys/file.h>
34
+ #include <math.h>
35
+
36
+
37
+
38
+ #ifdef HAVE_HEADER_RUBY_H
39
+ /* Oh what a bug! */
40
+ #define R_MATCH( obj) RMATCH( obj)
41
+ #else
42
+ #endif
43
+
44
+
45
+ struct supplement_flock {
46
+ struct supplement_flock *prev;
47
+ VALUE file;
48
+ int op;
49
+ int last_op;
50
+ };
51
+
52
+ static struct supplement_flock *flocks_root = NULL;
53
+
54
+
55
+ static VALUE supplement_index_blk( VALUE);
56
+ static VALUE supplement_rindex_blk( VALUE);
57
+ #ifdef FEATURE_ARRAY_INDEX_WITH_BLOCK
58
+ static VALUE supplement_index_val( VALUE, VALUE);
59
+ static VALUE supplement_rindex_val( VALUE, VALUE);
60
+ #endif
61
+ #ifdef FEATURE_ARRAY_SELECT_BANG
62
+ static VALUE supplement_reject( VALUE);
63
+ static VALUE supplement_invert_yield( VALUE);
64
+ #endif
65
+ static VALUE supplement_each_line( VALUE);
66
+ static void supplement_init_flock( struct supplement_flock *, VALUE, VALUE);
67
+ static VALUE supplement_do_unflock( VALUE);
68
+ static VALUE supplement_do_unumask( VALUE);
69
+ static VALUE supplement_chdir( VALUE);
70
+ #ifdef FEATURE_THREAD_EXCLUSIVE
71
+ static VALUE bsruby_set_thread_critical( VALUE);
72
+ #endif
73
+
74
+
75
+
76
+ static ID id_delete_at;
77
+ static ID id_cmp;
78
+ static ID id_eqq;
79
+ #ifdef FEATURE_ARRAY_SELECT_BANG
80
+ static ID id_reject_bang;
81
+ #endif
82
+ static ID id_chdir;
83
+ static ID id_path;
84
+ static ID id_mkdir;
85
+ static ID id_index;
86
+
87
+
88
+
89
+ /*
90
+ * Document-class: Object
91
+ */
92
+
93
+ /*
94
+ * call-seq:
95
+ * new_string -> str
96
+ *
97
+ * Returns another string that may be modified without touching the original
98
+ * object. This means +dup+ for a string and +to_s+ for any other object.
99
+ *
100
+ * If a block is given, that may modify a created string (built from a
101
+ * non-string object). For a dup'ed string object the block will not be
102
+ * called.
103
+ */
104
+
105
+ VALUE
106
+ rb_obj_new_string( VALUE obj)
107
+ {
108
+ VALUE r;
109
+
110
+ r = rb_obj_as_string( obj);
111
+ if (rb_block_given_p())
112
+ rb_yield( r);
113
+ return r;
114
+ }
115
+
116
+
117
+ /*
118
+ * call-seq:
119
+ * nil_if val -> nil or self
120
+ *
121
+ * Returns +nil+ when the string matches +val+. +val+ is compared using
122
+ * the <code>===</code> operator, just like in the case statement.
123
+ *
124
+ * "hello".nil_if "NONE" #=> "hello"
125
+ * "NONE".nil_if "NONE" #=> nil
126
+ * "NONE".nil_if /^none$/i #=> nil
127
+ *
128
+ * 20.nil_if 10 #=> 20
129
+ * 10.nil_if 10 #=> nil
130
+ * 1.0.nil_if Float #=> nil
131
+ *
132
+ */
133
+
134
+ VALUE
135
+ rb_obj_nil_if( VALUE obj, VALUE val)
136
+ {
137
+ if (!id_eqq)
138
+ id_eqq = rb_intern( "===");
139
+ return RTEST( rb_funcall( val, id_eqq, 1, obj)) ? Qnil : obj;
140
+ }
141
+
142
+
143
+ /*
144
+ * Document-module: Kernel
145
+ */
146
+
147
+ #ifdef FEATURE_KERNEL_TAP
148
+
149
+ /*
150
+ * call-seq:
151
+ * tap { |x| ... } -> obj
152
+ *
153
+ * Yields <code>x</code> to the block, and then returns <code>x</code>.
154
+ * The primary purpose of this method is to "tap into" a method chain,
155
+ * in order to perform operations on intermediate results within the chain.
156
+ *
157
+ * (1..10) .tap { |x| puts "original: #{x.inspect}" }
158
+ * .to_a .tap { |x| puts "array: #{x.inspect}" }
159
+ * .select { |x| x%2==0 } .tap { |x| puts "evens: #{x.inspect}" }
160
+ * .map { |x| x*x } .tap { |x| puts "squares: #{x.inspect}" }
161
+ *
162
+ */
163
+
164
+ VALUE
165
+ rb_krn_tap( VALUE obj)
166
+ {
167
+ rb_yield( obj);
168
+ return obj;
169
+ }
170
+
171
+ #endif
172
+
173
+ /*
174
+ * call-seq:
175
+ * tap! { |x| ... } -> obj
176
+ *
177
+ * Yields +x+ to the block, and then returns +x+ if and only
178
+ * if +x+ is not +nil+.
179
+ *
180
+ */
181
+
182
+ VALUE
183
+ rb_krn_tap_bang( VALUE obj)
184
+ {
185
+ if (!NIL_P( obj))
186
+ rb_yield( obj);
187
+ return obj;
188
+ }
189
+
190
+
191
+ /*
192
+ * Document-class: NilClass
193
+ */
194
+
195
+ /*
196
+ * call-seq:
197
+ * notempty? -> nil
198
+ *
199
+ * This spares testing for +nil+ when checking strings.
200
+ */
201
+
202
+ VALUE
203
+ rb_nil_notempty_p( VALUE str)
204
+ {
205
+ return Qnil;
206
+ }
207
+
208
+ /*
209
+ * Document-method: nonzero?
210
+ *
211
+ * call-seq:
212
+ * nonzero? -> nil
213
+ *
214
+ * This spares testing for +nil+ when checking numbers.
215
+ */
216
+
217
+ /*
218
+ * Document-method: each_line
219
+ *
220
+ * call-seq:
221
+ * each_line { |l| ... } -> nil
222
+ *
223
+ * This spares testing for +nil+ when checking strings.
224
+ */
225
+
226
+ VALUE
227
+ rb_nil_each_line( VALUE str)
228
+ {
229
+ RETURN_ENUMERATOR( str, 0, 0);
230
+ return Qnil;
231
+ }
232
+
233
+
234
+
235
+ /*
236
+ * Document-class: String
237
+ */
238
+
239
+
240
+ /*
241
+ * call-seq:
242
+ * new_string -> str
243
+ *
244
+ * Returns another string that may be modified without touching the original
245
+ * object. This means +dup+ for a string and +to_s+ for any other object.
246
+ *
247
+ */
248
+
249
+ VALUE
250
+ rb_str_new_string( VALUE obj)
251
+ {
252
+ return rb_str_dup( obj);
253
+ }
254
+
255
+
256
+ /*
257
+ * call-seq:
258
+ * notempty? -> nil or self
259
+ *
260
+ * Returns <code>self</code> if and only if <code>str</code> is not
261
+ * empty, <code>nil</code> otherwise.
262
+ *
263
+ * "hello".notempty? #=> "hello"
264
+ * "".notempty? #=> nil
265
+ */
266
+
267
+ VALUE
268
+ rb_str_notempty_p( VALUE str)
269
+ {
270
+ #if 0
271
+ /* Ruby Coding style */
272
+ if (RSTRING_LEN( str) == 0)
273
+ return Qnil;
274
+ return str;
275
+ #else
276
+ return RSTRING_LEN( str) ? str : Qnil;
277
+ #endif
278
+ }
279
+
280
+
281
+ /*
282
+ * call-seq:
283
+ * eat( n = nil) -> str
284
+ *
285
+ * Returns first <code>n</code> characters of <code>self</code> or
286
+ * whole string if <code>n</code> is <code>nil</code>. The returned
287
+ * substring will be deleted from <code>self</code>. If <code>n</code>
288
+ * is negative, characters will be eaten from the right.
289
+ *
290
+ * a = "upcase"
291
+ * a.eat 2 #=> "up"
292
+ * a #=> "case"
293
+ */
294
+
295
+ VALUE
296
+ rb_str_eat( int argc, VALUE *argv, VALUE str)
297
+ {
298
+ VALUE val;
299
+ int n;
300
+ int l;
301
+ int r;
302
+
303
+ #ifdef HAVE_HEADER_RUBY_H
304
+ n = l = RSTRING_LEN( str);
305
+ #else
306
+ n = l = rb_str_strlen( str);
307
+ #endif
308
+ if (rb_scan_args( argc, argv, "01", &val) == 1) {
309
+ if (!NIL_P( val)) {
310
+ int v = NUM2INT( val);
311
+ if (v >= 0) {
312
+ if (n >= v) n = v;
313
+ } else {
314
+ n = -n;
315
+ if (n <= v) n = v;
316
+ }
317
+ }
318
+ }
319
+ rb_str_modify( str);
320
+ #ifdef HAVE_HEADER_RUBY_H
321
+ if (n > 0) {
322
+ r = l - n;
323
+ val = rb_str_new5( str, RSTRING_PTR( str), n);
324
+ memmove( RSTRING_PTR( str), RSTRING_PTR( str) + n, r);
325
+ } else {
326
+ r = l + n;
327
+ val = rb_str_new5( str, RSTRING_PTR( str) + r, -n);
328
+ }
329
+ RSTRING_LEN( str) = r;
330
+ OBJ_INFECT( val, str);
331
+ #else
332
+ if (n > 0) {
333
+ r = 0;
334
+ } else if (n < 0) {
335
+ r = l + n;
336
+ n = -n;
337
+ } else
338
+ return Qnil;
339
+ val = rb_str_substr( str, r, n);
340
+ if (!NIL_P(val))
341
+ rb_str_update( str, r, n, rb_str_new( NULL, 0));
342
+ #endif
343
+ return val;
344
+ }
345
+
346
+
347
+ /*
348
+ * call-seq:
349
+ * cut!( length) -> str
350
+ *
351
+ * Cut string to <code>length</code>. If nothing was removed,
352
+ * <code>nil</code> is returned.
353
+ *
354
+ * a = "hello"
355
+ * a.cut! 4 #=> "hell"
356
+ * a #=> "hell"
357
+ * a.cut! 4 #=> nil
358
+ */
359
+
360
+ VALUE
361
+ rb_str_cut_bang( VALUE str, VALUE len)
362
+ {
363
+ int l;
364
+ #ifdef HAVE_HEADER_RUBY_H
365
+ #else
366
+ int n;
367
+ #endif
368
+
369
+ rb_str_modify( str);
370
+ l = NUM2INT( len);
371
+ if (l < 0)
372
+ l = 0;
373
+ #ifdef HAVE_HEADER_RUBY_H
374
+ if (l < RSTRING_LEN( str)) {
375
+ RSTRING_LEN( str) = l;
376
+ return str;
377
+ }
378
+ #else
379
+ n = rb_str_strlen( str);
380
+ if (l < n) {
381
+ rb_str_update( str, l, n - l, rb_str_new( NULL, 0));
382
+ return str;
383
+ }
384
+ #endif
385
+ return Qnil;
386
+ }
387
+
388
+
389
+ #ifdef FEATURE_STRING_CLEAR
390
+
391
+ /*
392
+ * call-seq:
393
+ * clear -> self
394
+ *
395
+ * Set to empty string. Equivalent to <code>str.replace ""</code>.
396
+ *
397
+ * a = "hello" #=> "hello"
398
+ * a.clear #=> ""
399
+ * a.empty? #=> true
400
+ */
401
+
402
+ VALUE
403
+ rb_str_clear( VALUE str)
404
+ {
405
+ rb_str_modify( str);
406
+ rb_str_resize( str, 0);
407
+ return str;
408
+ }
409
+
410
+ #endif
411
+
412
+
413
+ /*
414
+ * call-seq:
415
+ * head( n = 1) -> str
416
+ *
417
+ * Returns first <code>n</code> bytes in <code>str</code>.
418
+ *
419
+ * "hello".head( 2) #=> "he"
420
+ */
421
+
422
+ VALUE
423
+ rb_str_head( int argc, VALUE *argv, VALUE str)
424
+ {
425
+ VALUE n;
426
+ VALUE str2;
427
+ long len;
428
+
429
+ len = rb_scan_args( argc, argv, "01", &n) == 1 ? NUM2LONG( n) : 1;
430
+ return rb_str_substr( str, 0, len);
431
+ }
432
+
433
+
434
+ /*
435
+ * call-seq:
436
+ * rest( n = 1) -> str
437
+ *
438
+ * Return rest after <code>n</code> bytes in <code>str</code>.
439
+ *
440
+ * "hello".rest( 2) #=> "llo"
441
+ */
442
+
443
+ VALUE
444
+ rb_str_rest( int argc, VALUE *argv, VALUE str)
445
+ {
446
+ VALUE n;
447
+ long l, beg, len;
448
+
449
+ beg = rb_scan_args( argc, argv, "01", &n) == 1 ? NUM2LONG( n) : 1;
450
+ if (beg < 0)
451
+ beg = 0;
452
+ #ifdef HAVE_HEADER_RUBY_H
453
+ l = RSTRING_LEN( str);
454
+ #else
455
+ l = rb_str_strlen( str);
456
+ #endif
457
+ return rb_str_substr( str, beg, l - beg);
458
+ }
459
+
460
+
461
+ /*
462
+ * call-seq:
463
+ * tail( n = 1) -> str
464
+ *
465
+ * Returns last <code>n</code> bytes in <code>str</code>.
466
+ *
467
+ * "hello".tail( 2) #=> "lo"
468
+ */
469
+
470
+ VALUE
471
+ rb_str_tail( int argc, VALUE *argv, VALUE str)
472
+ {
473
+ VALUE n;
474
+ long l, beg, len;
475
+
476
+ len = rb_scan_args( argc, argv, "01", &n) == 1 ? NUM2LONG( n) : 1;
477
+ #ifdef HAVE_HEADER_RUBY_H
478
+ l = RSTRING_LEN( str);
479
+ #else
480
+ l = rb_str_strlen( str);
481
+ #endif
482
+ beg = l - len;
483
+ if (beg < 0)
484
+ beg = 0, len = l;
485
+ return rb_str_substr( str, beg, len);
486
+ }
487
+
488
+
489
+ #ifdef FEATURE_STRING_START_WITH
490
+
491
+ /*
492
+ * call-seq:
493
+ * start_with?( oth) -> true or false
494
+ *
495
+ * Checks whether the head is <code>oth</code>.
496
+ *
497
+ * "sys-apps".start_with?( "sys-") #=> true
498
+ */
499
+
500
+ VALUE
501
+ rb_str_start_with_p( VALUE str, VALUE oth)
502
+ {
503
+ return NIL_P( rb_str_starts_with_p( str, oth)) ? Qfalse : Qtrue;
504
+ }
505
+
506
+
507
+ /*
508
+ * call-seq:
509
+ * end_with?( oth) -> true or false
510
+ *
511
+ * Checks whether the tail is <code>oth</code>.
512
+ *
513
+ * "sys-apps".end_with?( "-apps") #=> true
514
+ */
515
+
516
+ VALUE
517
+ rb_str_end_with_p( VALUE str, VALUE oth)
518
+ {
519
+ return NIL_P( rb_str_ends_with_p( str, oth)) ? Qfalse : Qtrue;
520
+ }
521
+
522
+ #endif
523
+
524
+ /*
525
+ * call-seq:
526
+ * starts_with?( oth) -> nil or int
527
+ *
528
+ * Checks whether the head is <code>oth</code>. Returns length of
529
+ * <code>oth</code> when matching.
530
+ *
531
+ * "sys-apps".starts_with?( "sys-") #=> 4
532
+ *
533
+ * Caution! The Ruby 1.9.3 method #start_with? (notice the missing s)
534
+ * just returns +true+ or +false+.
535
+ */
536
+
537
+ VALUE
538
+ rb_str_starts_with_p( VALUE str, VALUE oth)
539
+ {
540
+ long i;
541
+ char *s, *o;
542
+ VALUE ost;
543
+
544
+ #ifdef HAVE_HEADER_RUBY_H
545
+ #else
546
+ if (!rb_str_comparable( str, oth))
547
+ return Qnil;
548
+ #endif
549
+ ost = rb_string_value( &oth);
550
+ i = RSTRING_LEN( ost);
551
+ if (i > RSTRING_LEN( str))
552
+ return Qnil;
553
+ s = RSTRING_PTR( str);
554
+ o = RSTRING_PTR( ost);
555
+ for (; i; i--, s++, o++) {
556
+ if (*s != *o)
557
+ return Qnil;
558
+ }
559
+ #ifdef HAVE_HEADER_RUBY_H
560
+ return INT2FIX( RSTRING_LEN( ost));
561
+ #else
562
+ return INT2FIX( rb_str_strlen( ost));
563
+ #endif
564
+ }
565
+
566
+
567
+ /*
568
+ * call-seq:
569
+ * ends_with?( oth) -> nil or int
570
+ *
571
+ * Checks whether the tail is <code>oth</code>. Returns the position
572
+ * where <code>oth</code> starts when matching.
573
+ *
574
+ * "sys-apps".ends_with?( "-apps") #=> 3
575
+ *
576
+ * Caution! The Ruby 1.9.3 method #start_with? (notice the missing s)
577
+ * just returns +true+ or +false+.
578
+ */
579
+
580
+ VALUE
581
+ rb_str_ends_with_p( VALUE str, VALUE oth)
582
+ {
583
+ long i;
584
+ char *s, *o;
585
+ VALUE ost;
586
+
587
+ #ifdef HAVE_HEADER_RUBY_H
588
+ #else
589
+ if (!rb_str_comparable( str, oth))
590
+ return Qnil;
591
+ #endif
592
+ ost = rb_string_value( &oth);
593
+ i = RSTRING_LEN( ost);
594
+ if (i > RSTRING_LEN( str))
595
+ return Qnil;
596
+ s = RSTRING_END( str);
597
+ o = RSTRING_END( ost);
598
+ for (; i; i--)
599
+ if (*--s != *--o)
600
+ return Qnil;
601
+ #ifdef HAVE_HEADER_RUBY_H
602
+ return INT2FIX( RSTRING_LEN( str) - RSTRING_LEN( ost));
603
+ #else
604
+ return INT2FIX( rb_str_strlen( str) - rb_str_strlen( ost));
605
+ #endif
606
+ }
607
+
608
+ #ifdef FEATURE_STRING_ORD
609
+
610
+ /*
611
+ * call-seq:
612
+ * ord() -> nil or int
613
+ *
614
+ * Returns the ASCII value of the first character, if any.
615
+ *
616
+ * Caution! For UTF-8 characters, this will return the first byte's value.
617
+ * This will do no harm in Ruby 1.8 but the standard Ruby 1.9 +String#ord+
618
+ * returns the first codepoint. Please do not overwrite that method.
619
+ */
620
+
621
+ VALUE rb_str_ord( VALUE str)
622
+ {
623
+ return RSTRING_LEN( str) > 0 ? INT2FIX( RSTRING_PTR( str)[ 0]) : Qnil;
624
+ }
625
+
626
+ #endif
627
+
628
+ /*
629
+ * call-seq:
630
+ * axe( n = 80) -> str
631
+ *
632
+ * Cut off everthing beyond then <code>n</code>th character. Replace the
633
+ * last bytes by ellipses.
634
+ *
635
+ * a = "Redistribution and use in source and binary forms, with or without"
636
+ * a.axe( 16) #=> "Redistributio..."
637
+ */
638
+
639
+ VALUE
640
+ rb_str_axe( int argc, VALUE *argv, VALUE str)
641
+ {
642
+ VALUE n;
643
+ VALUE ret;
644
+ long newlen, oldlen;
645
+
646
+ if (rb_scan_args( argc, argv, "01", &n) == 1 && !NIL_P( n))
647
+ newlen = NUM2LONG( n);
648
+ else
649
+ newlen = 80;
650
+ if (newlen < 0)
651
+ return Qnil;
652
+
653
+ #ifdef HAVE_HEADER_RUBY_H
654
+ oldlen = RSTRING_LEN( str);
655
+ #else
656
+ oldlen = rb_str_strlen( str);
657
+ #endif
658
+ if (newlen < oldlen) {
659
+ VALUE ell;
660
+ long e;
661
+
662
+ ell = rb_str_new2( "...");
663
+ #ifdef HAVE_HEADER_RUBY_H
664
+ e = RSTRING_LEN( ell);
665
+ #else
666
+ e = rb_str_strlen( ell);
667
+ #endif
668
+ if (newlen > e) {
669
+ ret = rb_str_substr( str, 0, newlen - e);
670
+ rb_str_append( ret, ell);
671
+ } else
672
+ ret = rb_str_substr( str, 0, newlen);
673
+ OBJ_INFECT( ret, str);
674
+ } else
675
+ ret = str;
676
+ return ret;
677
+ }
678
+
679
+
680
+ /*
681
+ * Document-class: Numeric
682
+ */
683
+
684
+ /*
685
+ * call-seq:
686
+ * pos? -> true or false
687
+ *
688
+ * Check whether +num+ is positive.
689
+ *
690
+ */
691
+
692
+ VALUE
693
+ rb_num_pos_p( VALUE num)
694
+ {
695
+ VALUE r = Qfalse;
696
+
697
+ switch (TYPE( num)) {
698
+ case T_FIXNUM:
699
+ if (NUM2LONG( num) > 0)
700
+ r = Qtrue;
701
+ break;
702
+
703
+ case T_BIGNUM:
704
+ if (RBIGNUM_SIGN( num)) /* 0 is not a Bignum. */
705
+ r = Qtrue;
706
+ break;
707
+
708
+ case T_FLOAT:
709
+ if (RFLOAT_VALUE( num) > 0.0)
710
+ r = Qtrue;
711
+ break;
712
+
713
+ default:
714
+ return rb_num_neg_p( rb_funcall( INT2FIX( 0), id_cmp, 1, num));
715
+ break;
716
+ }
717
+ return r;
718
+ }
719
+
720
+ /*
721
+ * call-seq:
722
+ * neg? -> true or false
723
+ *
724
+ * Check whether +num+ is negative.
725
+ *
726
+ */
727
+
728
+ VALUE
729
+ rb_num_neg_p( VALUE num)
730
+ {
731
+ VALUE r = Qfalse;
732
+
733
+ switch (TYPE( num)) {
734
+ case T_FIXNUM:
735
+ if (NUM2LONG( num) < 0)
736
+ r = Qtrue;
737
+ break;
738
+
739
+ case T_BIGNUM:
740
+ if (!RBIGNUM_SIGN( num)) /* 0 is not a Bignum. */
741
+ r = Qtrue;
742
+ break;
743
+
744
+ case T_FLOAT:
745
+ if (RFLOAT_VALUE( num) < 0.0)
746
+ r = Qtrue;
747
+ break;
748
+
749
+ default:
750
+ return rb_num_neg_p( rb_funcall( num, id_cmp, 1, INT2FIX( 0)));
751
+ break;
752
+ }
753
+ return r;
754
+ }
755
+
756
+ /*
757
+ * call-seq:
758
+ * grammatical sing, plu -> str
759
+ *
760
+ * Singular or plural
761
+ *
762
+ * 1.grammatical "line", "lines" #=> "line"
763
+ * 6.grammatical "child", "children" #=> "children"
764
+ */
765
+
766
+ VALUE
767
+ rb_num_grammatical( VALUE num, VALUE sing, VALUE plu)
768
+ {
769
+ long l;
770
+ double d;
771
+
772
+ switch (TYPE( num)) {
773
+ case T_FIXNUM:
774
+ l = NUM2LONG( num);
775
+ if (l == 1l || l == -1l)
776
+ return sing;
777
+ break;
778
+
779
+ case T_BIGNUM:
780
+ /* 1 is not a Bignum */
781
+ break;
782
+
783
+ case T_FLOAT:
784
+ d = RFLOAT_VALUE( num);
785
+ if (d == 1.0 || d == -1.0)
786
+ return sing;
787
+ break;
788
+
789
+ default:
790
+ l = NUM2LONG( rb_funcall( num, id_cmp, 1, INT2FIX( 1)));
791
+ if (l == 0)
792
+ return sing;
793
+ l = NUM2LONG( rb_funcall( num, id_cmp, 1, INT2FIX(-1)));
794
+ if (l == 0)
795
+ return sing;
796
+ break;
797
+ }
798
+ return plu;
799
+ }
800
+
801
+
802
+ /*
803
+ * call-seq:
804
+ * num.sqrt -> num
805
+ *
806
+ * Square root.
807
+ *
808
+ * 144.sqrt #=> 12.0
809
+ */
810
+
811
+ VALUE
812
+ rb_num_sqrt( VALUE num)
813
+ {
814
+ return rb_float_new( sqrt( RFLOAT_VALUE( rb_Float( num))));
815
+ }
816
+
817
+ /*
818
+ * call-seq:
819
+ * num.cbrt -> num
820
+ *
821
+ * Cube root.
822
+ *
823
+ * 27.cbrt #=> 3.0
824
+ */
825
+
826
+ VALUE
827
+ rb_num_cbrt( VALUE num)
828
+ {
829
+ double n;
830
+ int neg;
831
+ int i;
832
+
833
+ n = RFLOAT_VALUE( rb_Float( num));
834
+ if ((neg = n < 0))
835
+ n = -n;
836
+ n = sqrt( sqrt( n));
837
+ i = 2;
838
+ for (;;) {
839
+ double w = n;
840
+ int j;
841
+
842
+ for (j=i;j;--j) w = sqrt( w);
843
+ i *= 2;
844
+ w *= n;
845
+ if (n == w) break;
846
+ n = w;
847
+ }
848
+ return rb_float_new( neg ? -n : n);
849
+ }
850
+
851
+
852
+ /*
853
+ * Document-class: Array
854
+ */
855
+
856
+ /*
857
+ * call-seq:
858
+ * notempty? -> nil or self
859
+ *
860
+ * Returns <code>self</code> if and only if <code>ary</code> is not
861
+ * empty, <code>nil</code> otherwise.
862
+ *
863
+ * %w(a b).notempty? #=> [ "a", "b"]
864
+ * [].notempty? #=> nil
865
+ */
866
+
867
+ VALUE
868
+ rb_ary_notempty_p( VALUE ary)
869
+ {
870
+ return RARRAY_LEN( ary) == 0 ? Qnil : ary;
871
+ }
872
+
873
+
874
+ /*
875
+ * call-seq:
876
+ * indexes() -> ary
877
+ * keys() -> ary
878
+ *
879
+ * Returns the indexes from <code>0</code> to
880
+ * <code>array.length()</code> as an array.
881
+ *
882
+ * [ "a", "h", "q"].indexes #=> [ 0, 1, 2]
883
+ */
884
+
885
+ VALUE
886
+ rb_ary_indexes( VALUE ary)
887
+ {
888
+ VALUE ret;
889
+ int i, j;
890
+
891
+ j = RARRAY_LEN( ary);
892
+ ret = rb_ary_new2( j);
893
+ for (i = 0; j; ++i, --j) {
894
+ rb_ary_push( ret, INT2FIX( i));
895
+ }
896
+ return ret;
897
+ }
898
+
899
+
900
+ /*
901
+ * call-seq:
902
+ * pick { |elem| ... } -> obj or nil
903
+ *
904
+ * Deletes the element where the <em>block</em> first returns
905
+ * <code>true</code>. Or <code>nil</code> if nothing is found.
906
+ *
907
+ * a = %w(ant bat cat dog)
908
+ * a.pick { |e| e =~ /^c/ } #=> "cat"
909
+ * a #=> ["ant", "bat", "dog"]
910
+ * a.pick { |e| e =~ /^x/ } #=> nil
911
+ */
912
+
913
+ VALUE
914
+ rb_ary_pick( VALUE ary)
915
+ {
916
+ VALUE pos;
917
+
918
+ pos = supplement_index_blk( ary);
919
+ if (!NIL_P( pos))
920
+ return rb_funcall( ary, id_delete_at, 1, pos);
921
+ return Qnil;
922
+ }
923
+
924
+ VALUE
925
+ supplement_index_blk( VALUE ary)
926
+ {
927
+ long i, j;
928
+
929
+ for (i = 0, j = RARRAY_LEN( ary); j > 0; i++, j--) {
930
+ if (RTEST( rb_yield( RARRAY_PTR( ary)[ i])))
931
+ return LONG2NUM( i);
932
+ }
933
+ return Qnil;
934
+ }
935
+
936
+ /*
937
+ * call-seq:
938
+ * rpick { |elem| ... } -> obj or nil
939
+ *
940
+ * Deletes the element where the <em>block</em> first returns
941
+ * <code>true</code>. Or <code>nil</code> if nothing is found. Search
942
+ * from right to left.
943
+ *
944
+ * a = %w(ant cow bat cat dog)
945
+ * a.rpick { |e| e =~ /^c/ } #=> "cat"
946
+ * a #=> ["ant", "cow", "bat", "dog"]
947
+ * a.rpick { |e| e =~ /^x/ } #=> nil
948
+ */
949
+
950
+ VALUE
951
+ rb_ary_rpick( VALUE ary)
952
+ {
953
+ VALUE pos;
954
+
955
+ pos = supplement_rindex_blk( ary);
956
+ if (!NIL_P( pos))
957
+ return rb_funcall( ary, id_delete_at, 1, pos);
958
+ return Qnil;
959
+ }
960
+
961
+ VALUE
962
+ supplement_rindex_blk( VALUE ary)
963
+ {
964
+ long i;
965
+
966
+ for (i = RARRAY_LEN( ary); i;) {
967
+ --i;
968
+ if (rb_yield( RARRAY_PTR( ary)[ i]))
969
+ return LONG2NUM( i);
970
+ }
971
+ return Qnil;
972
+ }
973
+
974
+
975
+ #ifdef FEATURE_ARRAY_INDEX_WITH_BLOCK
976
+
977
+ /*
978
+ * call-seq:
979
+ * index( obj) -> int or nil
980
+ * index() { |elem| ... } -> int or nil
981
+ *
982
+ * Returns the index of the first object in <code>self</code> such that
983
+ * is <code>==</code> to <code>obj</code> or the <em>block</em> returns
984
+ * <code>true</code>. If no match is found, <code>nil</code> is
985
+ * returned.
986
+ *
987
+ * a = %w(a b c d e)
988
+ * a.index("b") #=> 1
989
+ * a.index("z") #=> nil
990
+ * a.index { |e| e >= "b" } #=> 1
991
+ * a.index { |e| e >= "q" } #=> nil
992
+ */
993
+
994
+ VALUE
995
+ rb_ary_index( int argc, VALUE *argv, VALUE ary)
996
+ {
997
+ VALUE val;
998
+
999
+ if (rb_scan_args( argc, argv, "01", &val) == 1) {
1000
+ if (rb_block_given_p())
1001
+ rb_warning( "given block not used");
1002
+ return supplement_index_val( ary, val);
1003
+ } else
1004
+ return supplement_index_blk( ary);
1005
+ return Qnil;
1006
+ }
1007
+
1008
+ VALUE
1009
+ supplement_index_val( VALUE ary, VALUE val)
1010
+ {
1011
+ long i;
1012
+
1013
+ for (i = 0; i < RARRAY_LEN( ary); i++)
1014
+ if (rb_equal( RARRAY_PTR( ary)[ i], val))
1015
+ return LONG2NUM( i);
1016
+ return Qnil;
1017
+ }
1018
+
1019
+
1020
+ /*
1021
+ * call-seq:
1022
+ * rindex( obj) -> int or nil
1023
+ * rindex() { |elem| ... } -> int or nil
1024
+ *
1025
+ * Returns the index of the first object in <code>self</code> such that
1026
+ * is <code>==</code> to <code>obj</code> or the <em>block</em> returns
1027
+ * <code>true</code>. If no match is found, <code>nil</code> is
1028
+ * returned. Search from right to left.
1029
+ *
1030
+ * a = %w(a b c d e)
1031
+ * a.rindex("b") #=> 1
1032
+ * a.rindex("z") #=> nil
1033
+ * a.rindex { |e| e >= "b" } #=> 4
1034
+ * a.rindex { |e| e >= "q" } #=> nil
1035
+ */
1036
+
1037
+ VALUE
1038
+ rb_ary_rindex( int argc, VALUE *argv, VALUE ary)
1039
+ {
1040
+ VALUE val;
1041
+
1042
+ if (rb_scan_args( argc, argv, "01", &val) == 1) {
1043
+ if (rb_block_given_p())
1044
+ rb_warning( "given block not used");
1045
+ return supplement_rindex_val( ary, val);
1046
+ } else
1047
+ return supplement_rindex_blk( ary);
1048
+ return Qnil;
1049
+ }
1050
+
1051
+ VALUE
1052
+ supplement_rindex_val( VALUE ary, VALUE val)
1053
+ {
1054
+ long i;
1055
+
1056
+ for (i = RARRAY_LEN( ary); i;)
1057
+ if (rb_equal( RARRAY_PTR( ary)[ --i], val))
1058
+ return LONG2NUM( i);
1059
+ return Qnil;
1060
+ }
1061
+
1062
+ #endif
1063
+
1064
+ #ifdef FEATURE_ARRAY_SELECT_BANG
1065
+
1066
+ /*
1067
+ * Document-method: select!
1068
+ *
1069
+ * call-seq:
1070
+ * select! { |x| ... } -> ary
1071
+ *
1072
+ * Remove all items for that the block returns +nil+ or +false+.
1073
+ *
1074
+ */
1075
+
1076
+ VALUE
1077
+ rb_ary_select_bang( VALUE self)
1078
+ {
1079
+ return rb_iterate( &supplement_reject, self,
1080
+ &supplement_invert_yield, Qnil);
1081
+ }
1082
+
1083
+ VALUE
1084
+ supplement_reject( VALUE obj)
1085
+ {
1086
+ if (!id_reject_bang)
1087
+ id_reject_bang = rb_intern( "reject!");
1088
+ return rb_funcall( obj, id_reject_bang, 0);
1089
+ }
1090
+
1091
+ VALUE
1092
+ supplement_invert_yield( VALUE elem)
1093
+ {
1094
+ return NIL_P( rb_yield( elem)) ? Qtrue : Qfalse;
1095
+ }
1096
+
1097
+ #endif
1098
+
1099
+
1100
+
1101
+ /*
1102
+ * Document-class: Hash
1103
+ */
1104
+
1105
+ /*
1106
+ * call-seq:
1107
+ * notempty? -> nil or self
1108
+ *
1109
+ * Returns <code>self</code> if and only if <code>hash</code> is not
1110
+ * empty, <code>nil</code> otherwise.
1111
+ *
1112
+ * { :a => "A"}.notempty? #=> { :a => "A"}
1113
+ * {}.notempty? #=> nil
1114
+ */
1115
+
1116
+ VALUE
1117
+ rb_hash_notempty_p( VALUE hash)
1118
+ {
1119
+ return RHASH_SIZE( hash) == 0 ? Qnil : hash;
1120
+ }
1121
+
1122
+
1123
+ /*
1124
+ * Document-class: File
1125
+ */
1126
+
1127
+ /*
1128
+ * call-seq:
1129
+ * size -> integer
1130
+ *
1131
+ * Returns <code>file</code>'s size. A shortcut for
1132
+ * <code>file.stat.size</code>. This constitutes consistency with
1133
+ * <code>StringIO</code>.
1134
+ *
1135
+ * file.size #=> 16384
1136
+ */
1137
+
1138
+ VALUE
1139
+ rb_file_size( VALUE obj)
1140
+ {
1141
+ #ifdef HAVE_HEADER_RUBY_H
1142
+ OpenFile *fptr;
1143
+ #else
1144
+ rb_io_t *fptr;
1145
+ #endif
1146
+ struct stat st;
1147
+
1148
+ GetOpenFile( obj, fptr);
1149
+ #ifdef HAVE_HEADER_RUBY_H
1150
+ if (fstat( fileno( fptr->f), &st) == -1) {
1151
+ rb_sys_fail( fptr->path);
1152
+ }
1153
+ #else
1154
+ if (fstat( fptr->fd, &st) == -1) {
1155
+ rb_sys_fail_str( fptr->pathv);
1156
+ }
1157
+ #endif
1158
+ return INT2FIX( st.st_size);
1159
+ }
1160
+
1161
+
1162
+ /*
1163
+ * call-seq:
1164
+ * flockb( excl = nil, nb = nil) { || ... } -> nil
1165
+ *
1166
+ * Lock file using the <code>flock()</code> system call.
1167
+ * When the <code>nb</code> flag is <code>true</code>, the method
1168
+ * won't block but rather raise an exception. Catch
1169
+ * <code>SystemCallError</code>. The calls may be nested in any order.
1170
+ *
1171
+ * File.open "/var/mail/joe", "a" do |f|
1172
+ * f.flockb true do
1173
+ * f.write another_message
1174
+ * end
1175
+ * end
1176
+ */
1177
+
1178
+ VALUE
1179
+ rb_file_flockb( int argc, VALUE *argv, VALUE file)
1180
+ {
1181
+ VALUE excl, nb;
1182
+ struct supplement_flock cur_flock;
1183
+ #ifdef HAVE_HEADER_RUBY_H
1184
+ OpenFile *fptr;
1185
+ #else
1186
+ rb_io_t *fptr;
1187
+ #endif
1188
+ int op;
1189
+
1190
+ rb_scan_args( argc, argv, "02", &excl, &nb);
1191
+ supplement_init_flock( &cur_flock, file, excl);
1192
+
1193
+ op = cur_flock.op | LOCK_NB;
1194
+ GetOpenFile( file, fptr);
1195
+ #ifdef HAVE_HEADER_RUBY_H
1196
+ while (flock( fileno( fptr->f), op) < 0) {
1197
+ #else
1198
+ while (flock( fptr->fd, op) < 0) {
1199
+ #endif
1200
+ switch (errno) {
1201
+ case EAGAIN:
1202
+ case EACCES:
1203
+ #if defined( EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1204
+ case EWOULDBLOCK:
1205
+ #endif
1206
+ if (!RTEST( nb)) {
1207
+ rb_thread_polling(); /* busy wait */
1208
+ rb_io_check_closed( fptr);
1209
+ continue;
1210
+ }
1211
+ /* fall through */
1212
+ default:
1213
+ #ifdef HAVE_HEADER_RUBY_H
1214
+ rb_sys_fail( fptr->path);
1215
+ #else
1216
+ rb_sys_fail_str( fptr->pathv);
1217
+ #endif
1218
+ }
1219
+ }
1220
+ cur_flock.prev = flocks_root;
1221
+ flocks_root = &cur_flock;
1222
+ return rb_ensure( rb_yield, Qnil, supplement_do_unflock, Qnil);
1223
+ }
1224
+
1225
+ void
1226
+ supplement_init_flock( struct supplement_flock *s, VALUE file, VALUE excl)
1227
+ {
1228
+ struct supplement_flock *i;
1229
+
1230
+ s->file = file;
1231
+
1232
+ s->last_op = LOCK_UN;
1233
+ for (i = flocks_root; i != NULL; i = i->prev) {
1234
+ if (i->file == file) {
1235
+ s->last_op = i->op;
1236
+ break;
1237
+ }
1238
+ }
1239
+
1240
+ switch (s->last_op) {
1241
+ case LOCK_UN:
1242
+ case LOCK_SH:
1243
+ s->op = RTEST( excl) ? LOCK_EX : LOCK_SH;
1244
+ break;
1245
+ case LOCK_EX:
1246
+ s->op = LOCK_EX;
1247
+ break;
1248
+ default:
1249
+ s->op = LOCK_UN; /* should never be reached. */
1250
+ break;
1251
+ }
1252
+ }
1253
+
1254
+ VALUE
1255
+ supplement_do_unflock( VALUE v)
1256
+ {
1257
+ #ifdef HAVE_HEADER_RUBY_H
1258
+ OpenFile *fptr;
1259
+ #else
1260
+ rb_io_t *fptr;
1261
+ #endif
1262
+ int fd;
1263
+
1264
+ GetOpenFile( flocks_root->file, fptr);
1265
+ #ifdef HAVE_HEADER_RUBY_H
1266
+ flock( fileno( fptr->f), flocks_root->last_op);
1267
+ #else
1268
+ flock( fptr->fd, flocks_root->last_op);
1269
+ #endif
1270
+ flocks_root = flocks_root->prev;
1271
+
1272
+ return Qnil;
1273
+ }
1274
+
1275
+
1276
+ /*
1277
+ * call-seq:
1278
+ * umask() -> int
1279
+ * umask( int) -> int
1280
+ * umask( int) { ... } -> obj
1281
+ *
1282
+ * Returns the current umask value for this process. If the optional
1283
+ * argument is given, set the umask to that value and return the
1284
+ * previous value. If a block is given, the umask value will be
1285
+ * reset and the blocks value is returned.
1286
+ *
1287
+ * Umask values are <em>subtracted</em> from the default permissions,
1288
+ * so a umask of <code>0222</code> would make a file read-only for
1289
+ * everyone.
1290
+ *
1291
+ * File.umask( 0006) #=> 18
1292
+ * File.umask #=> 6
1293
+ */
1294
+
1295
+ VALUE
1296
+ rb_file_s_umask( int argc, VALUE *argv)
1297
+ {
1298
+ int omask = 0;
1299
+
1300
+ rb_secure( 2);
1301
+ switch (argc) {
1302
+ case 0:
1303
+ omask = umask( 0777);
1304
+ umask( omask);
1305
+ break;
1306
+ case 1:
1307
+ omask = umask( NUM2INT( argv[ 0]));
1308
+ if (rb_block_given_p())
1309
+ return rb_ensure( rb_yield, Qnil,
1310
+ supplement_do_unumask, INT2FIX( omask));
1311
+ break;
1312
+ default:
1313
+ rb_raise( rb_eArgError,
1314
+ "wrong number of arguments (%d for 0..1)", argc);
1315
+ }
1316
+ return INT2FIX( omask);
1317
+ }
1318
+
1319
+ VALUE
1320
+ supplement_do_unumask( VALUE v)
1321
+ {
1322
+ umask( NUM2INT( v));
1323
+ return Qnil;
1324
+ }
1325
+
1326
+
1327
+ /*
1328
+ * Document-class: Dir
1329
+ */
1330
+
1331
+ /*
1332
+ * call-seq:
1333
+ * current() -> dir
1334
+ *
1335
+ * Current directory as a Dir object.
1336
+ *
1337
+ */
1338
+
1339
+ VALUE
1340
+ rb_dir_s_current( VALUE dir)
1341
+ {
1342
+ return rb_funcall( dir, rb_intern( "new"), 1, rb_str_new( ".", 1));
1343
+ }
1344
+
1345
+
1346
+ /*
1347
+ * call-seq:
1348
+ * mkdir!( path, modes = nil) -> str or nil
1349
+ *
1350
+ * Make a directory and all subdirectories if needed.
1351
+ *
1352
+ * If you specifiy modes, be sure that you have the permission to create
1353
+ * subdirectories.
1354
+ *
1355
+ * Returns the path demanded if the directory was created and +nil+ if
1356
+ * it existed before.
1357
+ *
1358
+ */
1359
+
1360
+ VALUE
1361
+ rb_dir_s_mkdir_bang( int argc, VALUE *argv)
1362
+ {
1363
+ VALUE path, modes;
1364
+
1365
+ rb_scan_args( argc, argv, "11", &path, &modes);
1366
+ if (!rb_file_directory_p( rb_cFile, path)) {
1367
+ VALUE parent[2];
1368
+
1369
+ parent[ 0] = rb_file_dirname( path);
1370
+ parent[ 1] = modes;
1371
+ rb_dir_s_mkdir_bang( 2, parent);
1372
+ if (!id_mkdir)
1373
+ id_mkdir = rb_intern( "mkdir");
1374
+ if (NIL_P(modes))
1375
+ rb_funcall( rb_cDir, id_mkdir, 1, path);
1376
+ else
1377
+ rb_funcall( rb_cDir, id_mkdir, 2, path, modes);
1378
+ return path;
1379
+ }
1380
+ return Qnil;
1381
+ }
1382
+
1383
+
1384
+ /*
1385
+ * call-seq:
1386
+ * entries!() -> dir
1387
+ *
1388
+ * Entries without <code>"."</code> and <code>".."</code>.
1389
+ *
1390
+ */
1391
+
1392
+ VALUE
1393
+ rb_dir_entries_bang( VALUE self)
1394
+ {
1395
+ VALUE e;
1396
+
1397
+ e = rb_funcall( self, rb_intern( "entries"), 0);
1398
+ rb_ary_delete( e, rb_str_new( ".", 1));
1399
+ rb_ary_delete( e, rb_str_new( "..", 2));
1400
+ return e;
1401
+ }
1402
+
1403
+
1404
+ /*
1405
+ * call-seq:
1406
+ * chdir() -> nil
1407
+ * chdir() { |path| ... } -> obj
1408
+ *
1409
+ * As you probably expect, change the working directory like in
1410
+ * <code>Dir.chdir</code>.
1411
+ *
1412
+ */
1413
+
1414
+ VALUE
1415
+ rb_dir_chdir( VALUE dir)
1416
+ {
1417
+ VALUE path;
1418
+
1419
+ if (!id_chdir) {
1420
+ id_chdir = rb_intern( "chdir");
1421
+ id_path = rb_intern( "path");
1422
+ }
1423
+ path = rb_funcall( dir, id_path, 0);
1424
+ if (rb_block_given_p())
1425
+ return rb_iterate( &supplement_chdir, path, &rb_yield, Qnil);
1426
+ else {
1427
+ supplement_chdir( path);
1428
+ return Qnil;
1429
+ }
1430
+ }
1431
+
1432
+ VALUE
1433
+ supplement_chdir( VALUE path)
1434
+ {
1435
+ return rb_funcall( rb_cDir, id_chdir, 1, path);
1436
+ }
1437
+
1438
+
1439
+ /*
1440
+ * Document-class: Match
1441
+ */
1442
+
1443
+ /*
1444
+ * call-seq:
1445
+ * begin( n = nil) -> integer
1446
+ *
1447
+ * Returns the offset of the start of the <code>n</code>th element of
1448
+ * the match array in the string. In case <code>n</code> is
1449
+ * <code>nil</code> the 0th match (whole) is assumed.
1450
+ *
1451
+ * m = /(.)(.)(\d+)(\d)/.match("THX1138.")
1452
+ * m.begin( 0) #=> 1
1453
+ * m.begin #=> 1
1454
+ * m.begin( 2) #=> 2
1455
+ */
1456
+
1457
+ VALUE
1458
+ rb_match_begin( int argc, VALUE *argv, VALUE match)
1459
+ {
1460
+ VALUE val;
1461
+ int i;
1462
+
1463
+ if (rb_scan_args( argc, argv, "01", &val) == 1) {
1464
+ i = NIL_P( val) ? 0 : NUM2INT( val);
1465
+ } else
1466
+ i = 0;
1467
+
1468
+ if (i < 0 || RMATCH_REGS( match)->num_regs <= i)
1469
+ rb_raise( rb_eIndexError, "index %d out of matches", i);
1470
+
1471
+ if (RMATCH_REGS( match)->beg[i] < 0)
1472
+ return Qnil;
1473
+
1474
+ return INT2FIX( RMATCH_REGS( match)->beg[i]);
1475
+ }
1476
+
1477
+
1478
+ /*
1479
+ * call-seq:
1480
+ * end( n = nil) -> integer
1481
+ *
1482
+ * Returns the offset of the character immediately following the end of
1483
+ * the <code>n</code>th element of the match array in the string. In
1484
+ * case <code>n</code> is <code>nil</code> the 0th match (whole) is
1485
+ * assumed.
1486
+ *
1487
+ * m = /(.)(.)(\d+)(\d)/.match("THX1138.")
1488
+ * m.end( 0) #=> 7
1489
+ * m.end #=> 7
1490
+ * m.end( 2) #=> 3
1491
+ */
1492
+
1493
+ VALUE
1494
+ rb_match_end( int argc, VALUE *argv, VALUE match)
1495
+ {
1496
+ VALUE val;
1497
+ int i;
1498
+
1499
+ if (rb_scan_args( argc, argv, "01", &val) == 1) {
1500
+ i = NIL_P( val) ? 0 : NUM2INT( val);
1501
+ } else
1502
+ i = 0;
1503
+
1504
+ if (i < 0 || RMATCH_REGS( match)->num_regs <= i)
1505
+ rb_raise( rb_eIndexError, "index %d out of matches", i);
1506
+
1507
+ if (RMATCH_REGS( match)->beg[i] < 0)
1508
+ return Qnil;
1509
+
1510
+ return INT2FIX( RMATCH_REGS( match)->end[i]);
1511
+ }
1512
+
1513
+
1514
+ #ifdef FEATURE_THREAD_EXCLUSIVE
1515
+
1516
+ /*
1517
+ * Document-class: Thread
1518
+ */
1519
+
1520
+ /*
1521
+ * call-seq:
1522
+ * Thread.exclusive { ... } -> obj
1523
+ *
1524
+ * Sets the global ``thread critical'' condition temporarily. Return
1525
+ * value is the object returned by the <em>block</em>.
1526
+ */
1527
+
1528
+ VALUE
1529
+ rb_thread_exclusive( void)
1530
+ {
1531
+ VALUE old_tc = rb_thread_critical;
1532
+
1533
+ rb_thread_critical = Qtrue;
1534
+ return rb_ensure( rb_yield, Qnil, bsruby_set_thread_critical, old_tc);
1535
+ }
1536
+
1537
+ VALUE
1538
+ bsruby_set_thread_critical( VALUE c)
1539
+ {
1540
+ rb_thread_critical = c;
1541
+ return Qnil;
1542
+ }
1543
+
1544
+ #endif
1545
+
1546
+
1547
+
1548
+ /*
1549
+ * Document-class: Struct
1550
+ */
1551
+
1552
+ /*
1553
+ * Document-method: []
1554
+ *
1555
+ * call-seq:
1556
+ * Struct[ ...] -> cls
1557
+ *
1558
+ * Alias for Struct.new; This applies to Struct subclass generation
1559
+ * as well as to the subclasses instance creation.
1560
+ *
1561
+ * S = Struct[ :a, :b] #=> S
1562
+ * s = S[ 'A', 'B'] #=> #<struct S a="A", b="B">
1563
+ *
1564
+ */
1565
+
1566
+
1567
+ void Init_supplement( void)
1568
+ {
1569
+ rb_define_alias( rb_cObject, "cls", "class");
1570
+ rb_define_method( rb_cObject, "new_string", rb_obj_new_string, 0);
1571
+ rb_define_method( rb_cObject, "nil_if", rb_obj_nil_if, 1);
1572
+ #ifdef FEATURE_KERNEL_TAP
1573
+ rb_define_method( rb_mKernel, "tap", rb_krn_tap, 0);
1574
+ #endif
1575
+ rb_define_method( rb_mKernel, "tap!", rb_krn_tap_bang, 0);
1576
+
1577
+ rb_define_method( rb_cNilClass, "notempty?", rb_nil_notempty_p, 0);
1578
+ rb_define_method( rb_cNilClass, "nonzero?", rb_nil_notempty_p, 0);
1579
+ rb_define_method( rb_cNilClass, "each_line", rb_nil_each_line, 0);
1580
+
1581
+ rb_define_method( rb_cString, "new_string", rb_str_new_string, 0);
1582
+ rb_define_method( rb_cString, "notempty?", rb_str_notempty_p, 0);
1583
+ rb_define_method( rb_cString, "eat", rb_str_eat, -1);
1584
+ rb_define_method( rb_cString, "cut!", rb_str_cut_bang, 1);
1585
+ #ifdef FEATURE_STRING_CLEAR
1586
+ rb_define_method( rb_cString, "clear", rb_str_clear, 0);
1587
+ #endif
1588
+ rb_define_method( rb_cString, "head", rb_str_head, -1);
1589
+ rb_define_method( rb_cString, "rest", rb_str_rest, -1);
1590
+ rb_define_method( rb_cString, "tail", rb_str_tail, -1);
1591
+ #ifdef FEATURE_STRING_START_WITH
1592
+ rb_define_method( rb_cString, "start_with?", rb_str_start_with_p, 1);
1593
+ rb_define_method( rb_cString, "end_with?", rb_str_end_with_p, 1);
1594
+ #endif
1595
+ rb_define_method( rb_cString, "starts_with?", rb_str_starts_with_p, 1);
1596
+ rb_define_method( rb_cString, "ends_with?", rb_str_ends_with_p, 1);
1597
+ rb_define_alias( rb_cString, "starts_with", "start_with?");
1598
+ rb_define_alias( rb_cString, "ends_with", "end_with?");
1599
+ #ifdef FEATURE_STRING_ORD
1600
+ rb_define_method( rb_cString, "ord", rb_str_ord, 0);
1601
+ #endif
1602
+ rb_define_method( rb_cString, "axe", rb_str_axe, -1);
1603
+
1604
+ rb_define_method( rb_cNumeric, "pos?", rb_num_pos_p, 0);
1605
+ rb_define_method( rb_cNumeric, "neg?", rb_num_neg_p, 0);
1606
+ rb_define_method( rb_cNumeric, "grammatical", rb_num_grammatical, 2);
1607
+ rb_define_method( rb_cNumeric, "sqrt", rb_num_sqrt, 0);
1608
+ rb_define_method( rb_cNumeric, "cbrt", rb_num_cbrt, 0);
1609
+
1610
+ rb_define_method( rb_cArray, "notempty?", rb_ary_notempty_p, 0);
1611
+ rb_define_method( rb_cArray, "indexes", rb_ary_indexes, 0);
1612
+ rb_define_alias( rb_cArray, "keys", "indexes");
1613
+ rb_define_method( rb_cArray, "pick", rb_ary_pick, 0);
1614
+ rb_define_method( rb_cArray, "rpick", rb_ary_rpick, 0);
1615
+ #ifdef FEATURE_ARRAY_INDEX_WITH_BLOCK
1616
+ rb_define_method( rb_cArray, "index", rb_ary_index, -1);
1617
+ rb_define_method( rb_cArray, "rindex", rb_ary_rindex, -1);
1618
+ #endif
1619
+ #ifdef FEATURE_ARRAY_SELECT_BANG
1620
+ rb_define_method( rb_cArray, "select!", rb_ary_select_bang, 0);
1621
+ #endif
1622
+
1623
+ rb_define_method( rb_cHash, "notempty?", rb_hash_notempty_p, 0);
1624
+
1625
+ rb_define_method( rb_cFile, "size", rb_file_size, 0);
1626
+ rb_define_method( rb_cFile, "flockb", rb_file_flockb, -1);
1627
+ rb_define_singleton_method( rb_cFile, "umask", rb_file_s_umask, -1);
1628
+
1629
+ rb_define_singleton_method( rb_cDir, "current", rb_dir_s_current, 0);
1630
+ rb_define_singleton_method( rb_cDir, "mkdir!", rb_dir_s_mkdir_bang, -1);
1631
+ rb_define_method( rb_cDir, "entries!", rb_dir_entries_bang, 0);
1632
+ rb_define_method( rb_cDir, "chdir", rb_dir_chdir, 0);
1633
+
1634
+ rb_define_method( rb_cMatch, "begin", rb_match_begin, -1);
1635
+ rb_define_method( rb_cMatch, "end", rb_match_end, -1);
1636
+
1637
+ #ifdef FEATURE_THREAD_EXCLUSIVE
1638
+ rb_define_singleton_method( rb_cThread, "exclusive",
1639
+ rb_thread_exclusive, 0);
1640
+ #endif
1641
+
1642
+ rb_define_alias( rb_singleton_class( rb_cStruct), "[]", "new");
1643
+
1644
+ id_delete_at = rb_intern( "delete_at");
1645
+ id_cmp = rb_intern( "<=>");
1646
+ id_eqq = 0;
1647
+ #ifdef FEATURE_ARRAY_SELECT_BANG
1648
+ id_reject_bang = 0;
1649
+ #endif
1650
+ id_chdir = 0;
1651
+ id_path = 0;
1652
+ id_mkdir = 0;
1653
+ id_index = 0;
1654
+
1655
+ Init_supplement_sync();
1656
+ }
1657
+