mmap 0.2.6

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,55 @@
1
+
2
+ -- 0.1.2
3
+
4
+ * fixed some bugs (options & new) (Thanks Joseph McDonald <joe@vpop.net>)
5
+ * added anonymous map
6
+ * added mlock, munlock, etc
7
+
8
+ -- 0.1.3
9
+
10
+ * added #count, #slice, #slice!
11
+ * added #insert, #casecmp (>= 171)
12
+ * corrected NEW2LONG
13
+
14
+ -- 0.1.4
15
+
16
+ * added #lstrip!, #rstrip! for 1.7.1
17
+ * corrected strip!
18
+ * corrected mm_bang_i (reverse!, etc)
19
+ * added a small test (make test)
20
+
21
+ -- 0.1.5
22
+
23
+ * added str[/a(a)/, 1] for 1.7.1
24
+ * corrected mm_aset (mm_update(str, ...))
25
+ * corrected ==, ===, eql?
26
+ * corrected mm_sub_bang, mm_gsub_bang (to_str)
27
+
28
+ -- 0.1.6
29
+
30
+ * adapted for 1.7.2 (mm_str)
31
+ * corrected real for mm_sub_bang
32
+ * protected against old class
33
+
34
+ -- 0.1.7
35
+
36
+ * 1.7.2 (::allocate, #initialize)
37
+ * added "a" for ::new
38
+ * experimental EXP_INCR_SIZE (4096) ("increment" => 4096)
39
+ * tests for RUNIT/Test::Unit
40
+
41
+ -- 0.1.8
42
+
43
+ * test for madvise(2)
44
+ * don't test size for MAP_ANON
45
+ * added syntax Mmap(nil, length)
46
+ * documentation : make rd2; make rdoc
47
+
48
+ -- 0.1.9
49
+
50
+ * String#slice! was modified in 1.6.8
51
+ * added ::new(IO)
52
+
53
+ --- 0.2.0
54
+
55
+ * adapted for 1.8.0
@@ -0,0 +1,11 @@
1
+ Changes
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ b.rb
6
+ ext/mmap/extconf.rb
7
+ ext/mmap/mmap.c
8
+ lib/mmap.rb
9
+ mmap.html
10
+ mmap.rd
11
+ test/test_mmap.rb
@@ -0,0 +1,36 @@
1
+ = Mmap
2
+
3
+ * http://rubyforge.org/frs/?group_id=8350
4
+
5
+ == DESCRIPTION
6
+
7
+ The Mmap class implement memory-mapped file objects
8
+
9
+ == SYNOPSIS
10
+
11
+ require 'mmap'
12
+
13
+ mmap = Mmap.new(__FILE__)
14
+ mmap.advise(Mmap::MADV_SEQUENTIAL)
15
+
16
+ mmap.each do |line|
17
+ puts line
18
+ end
19
+
20
+ == Installation
21
+
22
+ gem install mmap
23
+
24
+ == Documentation
25
+
26
+ rake docs
27
+
28
+ == Copying
29
+
30
+ This extension module is copyrighted free software by Guy Decoux
31
+
32
+ You can redistribute it and/or modify it under the same term as
33
+ Ruby.
34
+
35
+
36
+ Guy Decoux <ts@moulon.inra.fr>
@@ -0,0 +1,27 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ gem 'rake-compiler', '>= 0.4.1'
7
+ require "rake/extensiontask"
8
+
9
+ HOE = Hoe.spec 'mmap' do
10
+ developer('Guy Decoux', 'ts@moulon.inra.fr')
11
+ self.readme_file = 'README.rdoc'
12
+ self.history_file = 'Changes'
13
+ self.extra_rdoc_files = FileList['*.rdoc']
14
+
15
+ %w{ rake-compiler }.each do |dep|
16
+ self.extra_dev_deps << [dep, '>= 0']
17
+ end
18
+
19
+ self.spec_extras = { :extensions => ["ext/mmap/extconf.rb"] }
20
+ end
21
+
22
+ RET = Rake::ExtensionTask.new("mmap", HOE.spec) do |ext|
23
+ ext.lib_dir = File.join('lib', 'mmap')
24
+ end
25
+
26
+ # vim: syntax=ruby
27
+
data/b.rb ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/ruby
2
+ $LOAD_PATH.unshift "."
3
+ require "mmap"
4
+ PAGESIZE = 4096
5
+ f = File.open("aa", "w")
6
+ f.write("\0" * PAGESIZE)
7
+ f.write("b.rb")
8
+ f.write("\0" * PAGESIZE)
9
+ f.close
10
+ m = Mmap.new("aa", "w", "offset" => 0)
11
+ p m.size == "b.rb".size + 2 * PAGESIZE
12
+ p m.scan(/[a-z.]+/) == ["b.rb"]
13
+ p m.index("b.rb") == PAGESIZE
14
+ p m.rindex("b.rb") == PAGESIZE
15
+ p m.sub!(/[a-z.]+/, "toto") == m
16
+ p m.scan(/[a-z.]+/) == ["toto"]
17
+ begin
18
+ m.sub!(/[a-z.]+/, "alpha")
19
+ puts "not OK must give an error"
20
+ rescue
21
+ puts "OK : #$!"
22
+ end
23
+ m.munmap
24
+ m = Mmap.new("aa", "rw")
25
+ p m.index("toto") == PAGESIZE
26
+ p m.sub!(/([a-z.]+)/, "alpha") == m
27
+ p $& == "toto"
28
+ p $1 == "toto"
29
+ p m.index("toto") == nil
30
+ p m.index("alpha") == PAGESIZE
31
+ p m.size == 5 + 2 * PAGESIZE
32
+ m.gsub!(/\0/, "X")
33
+ p m.size == 5 + 2 * PAGESIZE
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/ruby
2
+ ARGV.collect! {|x| x.sub(/^--with-mmap-prefix=/, "--with-mmap-dir=") }
3
+
4
+ require 'mkmf'
5
+
6
+ if unknown = enable_config("unknown")
7
+ libs = if CONFIG.key?("LIBRUBYARG_STATIC")
8
+ Config::expand(CONFIG["LIBRUBYARG_STATIC"].dup).sub(/^-l/, '')
9
+ else
10
+ Config::expand(CONFIG["LIBRUBYARG"].dup).sub(/^lib([^.]*).*/, '\\1')
11
+ end
12
+ unknown = find_library(libs, "ruby_init",
13
+ Config::expand(CONFIG["archdir"].dup))
14
+ end
15
+
16
+ dir_config("mmap")
17
+
18
+ ["lstrip", "match", "insert", "casecmp"].each do |func|
19
+ if "aa".respond_to?(func)
20
+ $CFLAGS += " -DHAVE_RB_STR_#{func.upcase}"
21
+ end
22
+ end
23
+
24
+ if enable_config("ipc")
25
+ unless have_func("semctl") && have_func("shmctl")
26
+ $stderr.puts "\tIPC will not be available"
27
+ end
28
+ end
29
+
30
+ $CFLAGS += " -DRUBYLIBDIR='\"#{CONFIG['rubylibdir']}\"'"
31
+
32
+ create_makefile "mmap"
@@ -0,0 +1,2624 @@
1
+ #include <ruby.h>
2
+ #include <fcntl.h>
3
+ #include <ctype.h>
4
+ #include <sys/types.h>
5
+ #include <sys/stat.h>
6
+ #include <unistd.h>
7
+ #include <sys/mman.h>
8
+
9
+ #if HAVE_SEMCTL && HAVE_SHMCTL
10
+ #include <sys/shm.h>
11
+ #include <sys/ipc.h>
12
+ #include <sys/sem.h>
13
+ #endif
14
+
15
+ #include <rubyio.h>
16
+ #include <intern.h>
17
+ #include <re.h>
18
+
19
+ #ifndef StringValue
20
+ #define StringValue(x) do { \
21
+ if (TYPE(x) != T_STRING) x = rb_str_to_str(x); \
22
+ } while (0)
23
+ #endif
24
+
25
+ #ifndef StringValuePtr
26
+ #define StringValuePtr(x) STR2CSTR(x)
27
+ #endif
28
+
29
+ #ifndef SafeStringValue
30
+ #define SafeStringValue(x) Check_SafeStr(x)
31
+ #endif
32
+
33
+ #ifndef MADV_NORMAL
34
+ #ifdef POSIX_MADV_NORMAL
35
+ #define MADV_NORMAL POSIX_MADV_NORMAL
36
+ #define MADV_RANDOM POSIX_MADV_RANDOM
37
+ #define MADV_SEQUENTIAL POSIX_MADV_SEQUENTIAL
38
+ #define MADV_WILLNEED POSIX_MADV_WILLNEED
39
+ #define MADV_DONTNEED POSIX_MADV_DONTNEED
40
+ #define madvise posix_madvise
41
+ #endif
42
+ #endif
43
+
44
+ #define BEG(no) regs->beg[no]
45
+ #define END(no) regs->end[no]
46
+
47
+ #ifndef MMAP_RETTYPE
48
+ #ifndef _POSIX_C_SOURCE
49
+ #define _POSIX_C_SOURCE 199309
50
+ #endif /* !_POSIX_C_SOURCE */
51
+ #ifdef _POSIX_VERSION
52
+ #if _POSIX_VERSION >= 199309
53
+ #define MMAP_RETTYPE void *
54
+ #endif /* _POSIX_VERSION >= 199309 */
55
+ #endif /* _POSIX_VERSION */
56
+ #endif /* !MMAP_RETTYPE */
57
+
58
+ #ifndef MMAP_RETTYPE
59
+ #define MMAP_RETTYPE caddr_t
60
+ #endif
61
+
62
+ #ifndef MAP_FAILED
63
+ #define MAP_FAILED ((caddr_t)-1)
64
+ #endif /* !MAP_FAILED */
65
+
66
+ #ifndef MAP_ANON
67
+ #ifdef MAP_ANONYMOUS
68
+ #define MAP_ANON MAP_ANONYMOUS
69
+ #endif
70
+ #endif
71
+
72
+ static VALUE mm_cMap;
73
+
74
+ #define EXP_INCR_SIZE 4096
75
+
76
+ typedef struct {
77
+ MMAP_RETTYPE addr;
78
+ int smode, pmode, vscope;
79
+ int advice, flag;
80
+ VALUE key;
81
+ int semid, shmid;
82
+ size_t len, real, incr;
83
+ off_t offset;
84
+ char *path, *template;
85
+ } mm_mmap;
86
+
87
+ typedef struct {
88
+ int count;
89
+ mm_mmap *t;
90
+ } mm_ipc;
91
+
92
+ typedef struct {
93
+ VALUE obj, *argv;
94
+ int flag, id, argc;
95
+ } mm_bang;
96
+
97
+ #define MM_MODIFY 1
98
+ #define MM_ORIGIN 2
99
+ #define MM_CHANGE (MM_MODIFY | 4)
100
+ #define MM_PROTECT 8
101
+
102
+ #define MM_FROZEN (1<<0)
103
+ #define MM_FIXED (1<<1)
104
+ #define MM_ANON (1<<2)
105
+ #define MM_LOCK (1<<3)
106
+ #define MM_IPC (1<<4)
107
+ #define MM_TMP (1<<5)
108
+
109
+ #if HAVE_SEMCTL && HAVE_SHMCTL
110
+ static char template[1024];
111
+
112
+ union semun
113
+ {
114
+ int val;
115
+ struct semid_ds *buf;
116
+ unsigned short int *array;
117
+ struct seminfo *__buf;
118
+ };
119
+ #endif
120
+
121
+ static void
122
+ mm_free(i_mm)
123
+ mm_ipc *i_mm;
124
+ {
125
+ #if HAVE_SEMCTL && HAVE_SHMCTL
126
+ if (i_mm->t->flag & MM_IPC) {
127
+ struct shmid_ds buf;
128
+
129
+ if (shmctl(i_mm->t->shmid, IPC_STAT, &buf) != -1) {
130
+ if (buf.shm_nattch == 1 && (i_mm->t->flag & MM_TMP)) {
131
+ semctl(i_mm->t->semid, 0, IPC_RMID);
132
+ if (i_mm->t->template) {
133
+ unlink(i_mm->t->template);
134
+ free(i_mm->t->template);
135
+ }
136
+ }
137
+ }
138
+ shmdt(i_mm->t);
139
+ }
140
+ else {
141
+ free(i_mm->t);
142
+ }
143
+ #endif
144
+ if (i_mm->t->path) {
145
+ munmap(i_mm->t->addr, i_mm->t->len);
146
+ if (i_mm->t->path != (char *)-1) {
147
+ if (i_mm->t->real < i_mm->t->len && i_mm->t->vscope != MAP_PRIVATE &&
148
+ truncate(i_mm->t->path, i_mm->t->real) == -1) {
149
+ free(i_mm->t->path);
150
+ free(i_mm);
151
+ rb_raise(rb_eTypeError, "truncate");
152
+ }
153
+ free(i_mm->t->path);
154
+ }
155
+ }
156
+ free(i_mm);
157
+ }
158
+
159
+ static void
160
+ mm_lock(i_mm, wait_lock)
161
+ mm_ipc *i_mm;
162
+ int wait_lock;
163
+ {
164
+ #if HAVE_SEMCTL && HAVE_SHMCTL
165
+ struct sembuf sem_op;
166
+
167
+ if (i_mm->t->flag & MM_IPC) {
168
+ i_mm->count++;
169
+ if (i_mm->count == 1) {
170
+ retry:
171
+ sem_op.sem_num = 0;
172
+ sem_op.sem_op = -1;
173
+ sem_op.sem_flg = IPC_NOWAIT;
174
+ if (semop(i_mm->t->semid, &sem_op, 1) == -1) {
175
+ if (errno == EAGAIN) {
176
+ if (!wait_lock) {
177
+ rb_raise(rb_const_get(rb_mErrno, rb_intern("EAGAIN")), "EAGAIN");
178
+ }
179
+ rb_thread_sleep(1);
180
+ goto retry;
181
+ }
182
+ rb_sys_fail("semop()");
183
+ }
184
+ }
185
+ }
186
+ #endif
187
+ }
188
+
189
+ static void
190
+ mm_unlock(i_mm)
191
+ mm_ipc *i_mm;
192
+ {
193
+ #if HAVE_SEMCTL && HAVE_SHMCTL
194
+ struct sembuf sem_op;
195
+
196
+ if (i_mm->t->flag & MM_IPC) {
197
+ i_mm->count--;
198
+ if (!i_mm->count) {
199
+ retry:
200
+ sem_op.sem_num = 0;
201
+ sem_op.sem_op = 1;
202
+ sem_op.sem_flg = IPC_NOWAIT;
203
+ if (semop(i_mm->t->semid, &sem_op, 1) == -1) {
204
+ if (errno == EAGAIN) {
205
+ rb_thread_sleep(1);
206
+ goto retry;
207
+ }
208
+ rb_sys_fail("semop()");
209
+ }
210
+ }
211
+ }
212
+ #endif
213
+ }
214
+
215
+ #define GetMmap(obj, i_mm, t_modify) \
216
+ Data_Get_Struct(obj, mm_ipc, i_mm); \
217
+ if (!i_mm->t->path) { \
218
+ rb_raise(rb_eIOError, "unmapped file"); \
219
+ } \
220
+ if ((t_modify & MM_MODIFY) && (i_mm->t->flag & MM_FROZEN)) { \
221
+ rb_error_frozen("mmap"); \
222
+ }
223
+
224
+ static VALUE
225
+ mm_vunlock(obj)
226
+ VALUE obj;
227
+ {
228
+ mm_ipc *i_mm;
229
+
230
+ GetMmap(obj, i_mm, 0);
231
+ mm_unlock(i_mm);
232
+ return Qnil;
233
+ }
234
+
235
+ /*
236
+ * call-seq: semlock
237
+ *
238
+ * Create a lock
239
+ */
240
+ static VALUE
241
+ mm_semlock(argc, argv, obj)
242
+ int argc;
243
+ VALUE *argv, obj;
244
+ {
245
+ mm_ipc *i_mm;
246
+
247
+ GetMmap(obj, i_mm, 0);
248
+ if (!(i_mm->t->flag & MM_IPC)) {
249
+ rb_warning("useless use of #semlock");
250
+ rb_yield(obj);
251
+ }
252
+ else {
253
+ #if HAVE_SEMCTL && HAVE_SHMCTL
254
+ VALUE a;
255
+ int wait_lock = Qtrue;
256
+
257
+ if (rb_scan_args(argc, argv, "01", &a)) {
258
+ wait_lock = RTEST(a);
259
+ }
260
+ mm_lock(i_mm, wait_lock);
261
+ rb_ensure(rb_yield, obj, mm_vunlock, obj);
262
+ #endif
263
+ }
264
+ return Qnil;
265
+ }
266
+
267
+ /*
268
+ * call-seq: ipc_key
269
+ *
270
+ * Get the ipc key
271
+ */
272
+ static VALUE
273
+ mm_ipc_key(obj)
274
+ VALUE obj;
275
+ {
276
+ mm_ipc *i_mm;
277
+
278
+ GetMmap(obj, i_mm, 0);
279
+ if (i_mm->t->flag & MM_IPC) {
280
+ return INT2NUM(i_mm->t->key);
281
+ }
282
+ return INT2NUM(-1);
283
+ }
284
+
285
+ /*
286
+ * Document-method: munmap
287
+ * Document-method: unmap
288
+ *
289
+ * call-seq: munmap
290
+ *
291
+ * terminate the association
292
+ */
293
+ static VALUE
294
+ mm_unmap(obj)
295
+ VALUE obj;
296
+ {
297
+ mm_ipc *i_mm;
298
+
299
+ GetMmap(obj, i_mm, 0);
300
+ if (i_mm->t->path) {
301
+ mm_lock(i_mm, Qtrue);
302
+ munmap(i_mm->t->addr, i_mm->t->len);
303
+ if (i_mm->t->path != (char *)-1) {
304
+ if (i_mm->t->real < i_mm->t->len && i_mm->t->vscope != MAP_PRIVATE &&
305
+ truncate(i_mm->t->path, i_mm->t->real) == -1) {
306
+ rb_raise(rb_eTypeError, "truncate");
307
+ }
308
+ free(i_mm->t->path);
309
+ }
310
+ i_mm->t->path = '\0';
311
+ mm_unlock(i_mm);
312
+ }
313
+ return Qnil;
314
+ }
315
+
316
+ /*
317
+ * call-seq: freeze
318
+ *
319
+ * freeze the current file
320
+ */
321
+ static VALUE
322
+ mm_freeze(obj)
323
+ VALUE obj;
324
+ {
325
+ mm_ipc *i_mm;
326
+ rb_obj_freeze(obj);
327
+ GetMmap(obj, i_mm, 0);
328
+ i_mm->t->flag |= MM_FROZEN;
329
+ return obj;
330
+ }
331
+
332
+ static VALUE
333
+ mm_str(obj, modify)
334
+ VALUE obj;
335
+ int modify;
336
+ {
337
+ mm_ipc *i_mm;
338
+ VALUE ret = Qnil;
339
+
340
+ GetMmap(obj, i_mm, modify & ~MM_ORIGIN);
341
+ if (modify & MM_MODIFY) {
342
+ if (i_mm->t->flag & MM_FROZEN) rb_error_frozen("mmap");
343
+ if (!OBJ_TAINTED(ret) && rb_safe_level() >= 4)
344
+ rb_raise(rb_eSecurityError, "Insecure: can't modify mmap");
345
+ }
346
+ #if HAVE_RB_DEFINE_ALLOC_FUNC
347
+ ret = rb_obj_alloc(rb_cString);
348
+ if (rb_obj_tainted(obj)) {
349
+ OBJ_TAINT(ret);
350
+ }
351
+ #else
352
+ if (rb_obj_tainted(obj)) {
353
+ ret = rb_tainted_str_new2("");
354
+ }
355
+ else {
356
+ ret = rb_str_new2("");
357
+ }
358
+ free(RSTRING(ret)->ptr);
359
+ #endif
360
+ RSTRING(ret)->ptr = i_mm->t->addr;
361
+ RSTRING(ret)->len = i_mm->t->real;
362
+ if (modify & MM_ORIGIN) {
363
+ #if HAVE_RB_DEFINE_ALLOC_FUNC
364
+ RSTRING(ret)->aux.shared = ret;
365
+ FL_SET(ret, ELTS_SHARED);
366
+ #else
367
+ RSTRING(ret)->orig = ret;
368
+ #endif
369
+ }
370
+ if (i_mm->t->flag & MM_FROZEN) {
371
+ ret = rb_obj_freeze(ret);
372
+ }
373
+ return ret;
374
+ }
375
+
376
+ /*
377
+ * call-seq: to_str
378
+ *
379
+ * Convert object to a string
380
+ */
381
+ static VALUE
382
+ mm_to_str(obj)
383
+ VALUE obj;
384
+ {
385
+ return mm_str(obj, MM_ORIGIN);
386
+ }
387
+
388
+ extern char *ruby_strdup();
389
+
390
+ typedef struct {
391
+ mm_ipc *i_mm;
392
+ size_t len;
393
+ } mm_st;
394
+
395
+ static VALUE
396
+ mm_i_expand(st_mm)
397
+ mm_st *st_mm;
398
+ {
399
+ int fd;
400
+ mm_ipc *i_mm = st_mm->i_mm;
401
+ size_t len = st_mm->len;
402
+
403
+ if (munmap(i_mm->t->addr, i_mm->t->len)) {
404
+ rb_raise(rb_eArgError, "munmap failed");
405
+ }
406
+ if ((fd = open(i_mm->t->path, i_mm->t->smode)) == -1) {
407
+ rb_raise(rb_eArgError, "Can't open %s", i_mm->t->path);
408
+ }
409
+ if (len > i_mm->t->len) {
410
+ if (lseek(fd, len - i_mm->t->len - 1, SEEK_END) == -1) {
411
+ rb_raise(rb_eIOError, "Can't lseek %d", len - i_mm->t->len - 1);
412
+ }
413
+ if (write(fd, "\000", 1) != 1) {
414
+ rb_raise(rb_eIOError, "Can't extend %s", i_mm->t->path);
415
+ }
416
+ }
417
+ else if (len < i_mm->t->len && truncate(i_mm->t->path, len) == -1) {
418
+ rb_raise(rb_eIOError, "Can't truncate %s", i_mm->t->path);
419
+ }
420
+ i_mm->t->addr = mmap(0, len, i_mm->t->pmode, i_mm->t->vscope, fd, i_mm->t->offset);
421
+ close(fd);
422
+ if (i_mm->t->addr == MAP_FAILED) {
423
+ rb_raise(rb_eArgError, "mmap failed");
424
+ }
425
+ #ifdef MADV_NORMAL
426
+ if (i_mm->t->advice && madvise(i_mm->t->addr, len, i_mm->t->advice) == -1) {
427
+ rb_raise(rb_eArgError, "madvise(%d)", errno);
428
+ }
429
+ #endif
430
+ if ((i_mm->t->flag & MM_LOCK) && mlock(i_mm->t->addr, len) == -1) {
431
+ rb_raise(rb_eArgError, "mlock(%d)", errno);
432
+ }
433
+ i_mm->t->len = len;
434
+ return Qnil;
435
+ }
436
+
437
+ static void
438
+ mm_expandf(i_mm, len)
439
+ mm_ipc *i_mm;
440
+ size_t len;
441
+ {
442
+ int status;
443
+ mm_st st_mm;
444
+
445
+ if (i_mm->t->vscope == MAP_PRIVATE) {
446
+ rb_raise(rb_eTypeError, "expand for a private map");
447
+ }
448
+ if (i_mm->t->flag & MM_FIXED) {
449
+ rb_raise(rb_eTypeError, "expand for a fixed map");
450
+ }
451
+ if (!i_mm->t->path || i_mm->t->path == (char *)-1) {
452
+ rb_raise(rb_eTypeError, "expand for an anonymous map");
453
+ }
454
+ st_mm.i_mm = i_mm;
455
+ st_mm.len = len;
456
+ if (i_mm->t->flag & MM_IPC) {
457
+ mm_lock(i_mm, Qtrue);
458
+ rb_protect(mm_i_expand, (VALUE)&st_mm, &status);
459
+ mm_unlock(i_mm);
460
+ if (status) {
461
+ rb_jump_tag(status);
462
+ }
463
+ }
464
+ else {
465
+ mm_i_expand(&st_mm);
466
+ }
467
+ }
468
+
469
+ static void
470
+ mm_realloc(i_mm, len)
471
+ mm_ipc *i_mm;
472
+ size_t len;
473
+ {
474
+ if (i_mm->t->flag & MM_FROZEN) rb_error_frozen("mmap");
475
+ if (len > i_mm->t->len) {
476
+ if ((len - i_mm->t->len) < i_mm->t->incr) {
477
+ len = i_mm->t->len + i_mm->t->incr;
478
+ }
479
+ mm_expandf(i_mm, len);
480
+ }
481
+ }
482
+
483
+ /*
484
+ * call-seq:
485
+ * extend(count)
486
+ *
487
+ * add <em>count</em> bytes to the file (i.e. pre-extend the file)
488
+ */
489
+ static VALUE
490
+ mm_extend(obj, a)
491
+ VALUE obj, a;
492
+ {
493
+ mm_ipc *i_mm;
494
+ long len;
495
+
496
+ GetMmap(obj, i_mm, MM_MODIFY);
497
+ len = NUM2LONG(a);
498
+ if (len > 0) {
499
+ mm_expandf(i_mm, i_mm->t->len + len);
500
+ }
501
+ return UINT2NUM(i_mm->t->len);
502
+ }
503
+
504
+ static VALUE
505
+ mm_i_options(arg, obj)
506
+ VALUE arg, obj;
507
+ {
508
+ mm_ipc *i_mm;
509
+ char *options;
510
+ VALUE key, value;
511
+
512
+ Data_Get_Struct(obj, mm_ipc, i_mm);
513
+ key = rb_ary_entry(arg, 0);
514
+ value = rb_ary_entry(arg, 1);
515
+ key = rb_obj_as_string(key);
516
+ options = StringValuePtr(key);
517
+ if (strcmp(options, "length") == 0) {
518
+ i_mm->t->len = NUM2UINT(value);
519
+ if (i_mm->t->len <= 0) {
520
+ rb_raise(rb_eArgError, "Invalid value for length %d", i_mm->t->len);
521
+ }
522
+ i_mm->t->flag |= MM_FIXED;
523
+ }
524
+ else if (strcmp(options, "offset") == 0) {
525
+ i_mm->t->offset = NUM2INT(value);
526
+ if (i_mm->t->offset < 0) {
527
+ rb_raise(rb_eArgError, "Invalid value for offset %d", i_mm->t->offset);
528
+ }
529
+ i_mm->t->flag |= MM_FIXED;
530
+ }
531
+ else if (strcmp(options, "advice") == 0) {
532
+ i_mm->t->advice = NUM2INT(value);
533
+ }
534
+ else if (strcmp(options, "increment") == 0) {
535
+ int incr = NUM2INT(value);
536
+ if (incr < 0) {
537
+ rb_raise(rb_eArgError, "Invalid value for increment %d", incr);
538
+ }
539
+ i_mm->t->incr = incr;
540
+ }
541
+ else if (strcmp(options, "initialize") == 0) {
542
+ }
543
+ #if HAVE_SEMCTL && HAVE_SHMCTL
544
+ else if (strcmp(options, "ipc") == 0) {
545
+ if (value != Qtrue && TYPE(value) != T_HASH) {
546
+ rb_raise(rb_eArgError, "Expected an Hash for :ipc");
547
+ }
548
+ i_mm->t->shmid = value;
549
+ i_mm->t->flag |= (MM_IPC | MM_TMP);
550
+ }
551
+ #endif
552
+ else {
553
+ rb_warning("Unknown option `%s'", options);
554
+ }
555
+ return Qnil;
556
+ }
557
+
558
+ #if HAVE_SEMCTL && HAVE_SHMCTL
559
+
560
+ static VALUE
561
+ mm_i_ipc(arg, obj)
562
+ VALUE arg, obj;
563
+ {
564
+ mm_ipc *i_mm;
565
+ char *options;
566
+ VALUE key, value;
567
+
568
+ Data_Get_Struct(obj, mm_ipc, i_mm);
569
+ key = rb_ary_entry(arg, 0);
570
+ value = rb_ary_entry(arg, 1);
571
+ key = rb_obj_as_string(key);
572
+ options = StringValuePtr(key);
573
+ if (strcmp(options, "key") == 0) {
574
+ i_mm->t->key = rb_funcall2(value, rb_intern("to_int"), 0, 0);
575
+ }
576
+ else if (strcmp(options, "permanent") == 0) {
577
+ if (RTEST(value)) {
578
+ i_mm->t->flag &= ~MM_TMP;
579
+ }
580
+ }
581
+ else if (strcmp(options, "mode") == 0) {
582
+ i_mm->t->semid = NUM2INT(value);
583
+ }
584
+ else {
585
+ rb_warning("Unknown option `%s'", options);
586
+ }
587
+ return Qnil;
588
+ }
589
+
590
+ #endif
591
+
592
+ /*
593
+ * call-seq:
594
+ * new(file, mode = "r", protection = Mmap::MAP_SHARED, options = {})
595
+ *
596
+ * create a new Mmap object
597
+ *
598
+ * * <em>file</em>
599
+ *
600
+ * Pathname of the file, if <em>nil</em> is given an anonymous map
601
+ * is created <em>Mmanp::MAP_ANON</em>
602
+ *
603
+ * * <em>mode</em>
604
+ *
605
+ * Mode to open the file, it can be "r", "w", "rw", "a"
606
+ *
607
+ * * <em>protection</em>
608
+ *
609
+ * specify the nature of the mapping
610
+ *
611
+ * * <em>Mmap::MAP_SHARED</em>
612
+ *
613
+ * Creates a mapping that's shared with all other processes
614
+ * mapping the same areas of the file.
615
+ * The default value is <em>Mmap::MAP_SHARED</em>
616
+ *
617
+ * * <em>Mmap::MAP_PRIVATE</em>
618
+ *
619
+ * Creates a private copy-on-write mapping, so changes to the
620
+ * contents of the mmap object will be private to this process
621
+ *
622
+ * * <em>options</em>
623
+ *
624
+ * Hash. If one of the options <em>length</em> or <em>offset</em>
625
+ * is specified it will not possible to modify the size of
626
+ * the mapped file.
627
+ *
628
+ * length:: maps <em>length</em> bytes from the file
629
+ *
630
+ * offset:: the mapping begin at <em>offset</em>
631
+ *
632
+ * advice:: the type of the access (see #madvise)
633
+ */
634
+ static VALUE
635
+ mm_s_new(argc, argv, obj)
636
+ int argc;
637
+ VALUE *argv, obj;
638
+ {
639
+ VALUE res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
640
+ rb_obj_call_init(res, argc, argv);
641
+ return res;
642
+ }
643
+
644
+ static VALUE
645
+ mm_s_alloc(obj)
646
+ VALUE obj;
647
+ {
648
+ VALUE res;
649
+ mm_ipc *i_mm;
650
+
651
+ res = Data_Make_Struct(obj, mm_ipc, 0, mm_free, i_mm);
652
+ i_mm->t = ALLOC_N(mm_mmap, 1);
653
+ MEMZERO(i_mm->t, mm_mmap, 1);
654
+ i_mm->t->incr = EXP_INCR_SIZE;
655
+ return res;
656
+ }
657
+
658
+ /*
659
+ * call-seq: initialize
660
+ *
661
+ * Create a new Mmap object
662
+ */
663
+ static VALUE
664
+ mm_init(argc, argv, obj)
665
+ VALUE obj, *argv;
666
+ int argc;
667
+ {
668
+ struct stat st;
669
+ int fd, smode = 0, pmode = 0, vscope, perm, init;
670
+ MMAP_RETTYPE addr;
671
+ VALUE fname, fdv, vmode, scope, options;
672
+ mm_ipc *i_mm;
673
+ char *path, *mode;
674
+ size_t size = 0;
675
+ off_t offset;
676
+ int anonymous;
677
+
678
+ options = Qnil;
679
+ if (argc > 1 && TYPE(argv[argc - 1]) == T_HASH) {
680
+ options = argv[argc - 1];
681
+ argc--;
682
+ }
683
+ rb_scan_args(argc, argv, "12", &fname, &vmode, &scope);
684
+ vscope = 0;
685
+ path = 0;
686
+ fd = -1;
687
+ anonymous = 0;
688
+ fdv = Qnil;
689
+ #ifdef MAP_ANON
690
+ if (NIL_P(fname)) {
691
+ vscope = MAP_ANON | MAP_SHARED;
692
+ anonymous = 1;
693
+ }
694
+ else
695
+ #endif
696
+ {
697
+ if (rb_safe_level() > 0 && OBJ_TAINTED(fname)){
698
+ rb_raise(rb_eSecurityError, "Insecure operation");
699
+ }
700
+ rb_secure(4);
701
+ if (rb_respond_to(fname, rb_intern("fileno"))) {
702
+ fdv = rb_funcall2(fname, rb_intern("fileno"), 0, 0);
703
+ }
704
+ if (NIL_P(fdv)) {
705
+ fname = rb_str_to_str(fname);
706
+ SafeStringValue(fname);
707
+ path = StringValuePtr(fname);
708
+ }
709
+ else {
710
+ fd = NUM2INT(fdv);
711
+ if (fd < 0) {
712
+ rb_raise(rb_eArgError, "invalid file descriptor %d", fd);
713
+ }
714
+ }
715
+ if (!NIL_P(scope)) {
716
+ vscope = NUM2INT(scope);
717
+ #ifdef MAP_ANON
718
+ if (vscope & MAP_ANON) {
719
+ rb_raise(rb_eArgError, "filename specified for an anonymous map");
720
+ }
721
+ #endif
722
+ }
723
+ }
724
+ vscope |= NIL_P(scope) ? MAP_SHARED : NUM2INT(scope);
725
+ size = 0;
726
+ perm = 0666;
727
+ if (!anonymous) {
728
+ if (NIL_P(vmode)) {
729
+ mode = "r";
730
+ }
731
+ else if (rb_respond_to(vmode, rb_intern("to_ary"))) {
732
+ VALUE tmp;
733
+
734
+ vmode = rb_convert_type(vmode, T_ARRAY, "Array", "to_ary");
735
+ if (RARRAY(vmode)->len != 2) {
736
+ rb_raise(rb_eArgError, "Invalid length %d (expected 2)",
737
+ RARRAY(vmode)->len);
738
+ }
739
+ tmp = RARRAY(vmode)->ptr[0];
740
+ mode = StringValuePtr(tmp);
741
+ perm = NUM2INT(RARRAY(vmode)->ptr[1]);
742
+ }
743
+ else {
744
+ mode = StringValuePtr(vmode);
745
+ }
746
+ if (strcmp(mode, "r") == 0) {
747
+ smode = O_RDONLY;
748
+ pmode = PROT_READ;
749
+ }
750
+ else if (strcmp(mode, "w") == 0) {
751
+ smode = O_RDWR | O_TRUNC;
752
+ pmode = PROT_READ | PROT_WRITE;
753
+ }
754
+ else if (strcmp(mode, "rw") == 0 || strcmp(mode, "wr") == 0) {
755
+ smode = O_RDWR;
756
+ pmode = PROT_READ | PROT_WRITE;
757
+ }
758
+ else if (strcmp(mode, "a") == 0) {
759
+ smode = O_RDWR | O_CREAT;
760
+ pmode = PROT_READ | PROT_WRITE;
761
+ }
762
+ else {
763
+ rb_raise(rb_eArgError, "Invalid mode %s", mode);
764
+ }
765
+ if (NIL_P(fdv)) {
766
+ if ((fd = open(path, smode, perm)) == -1) {
767
+ rb_raise(rb_eArgError, "Can't open %s", path);
768
+ }
769
+ }
770
+ if (fstat(fd, &st) == -1) {
771
+ rb_raise(rb_eArgError, "Can't stat %s", path);
772
+ }
773
+ size = st.st_size;
774
+ }
775
+ else {
776
+ fd = -1;
777
+ if (!NIL_P(vmode) && TYPE(vmode) != T_STRING) {
778
+ size = NUM2INT(vmode);
779
+ }
780
+ }
781
+ Data_Get_Struct(obj, mm_ipc, i_mm);
782
+ if (i_mm->t->flag & MM_FROZEN) {
783
+ rb_raise(rb_eArgError, "frozen mmap");
784
+ }
785
+ i_mm->t->shmid = 0;
786
+ i_mm->t->semid = 0;
787
+ offset = 0;
788
+ if (options != Qnil) {
789
+ rb_iterate(rb_each, options, mm_i_options, obj);
790
+ if (path && (i_mm->t->len + i_mm->t->offset) > st.st_size) {
791
+ rb_raise(rb_eArgError, "invalid value for length (%d) or offset (%d)",
792
+ i_mm->t->len, i_mm->t->offset);
793
+ }
794
+ if (i_mm->t->len) size = i_mm->t->len;
795
+ offset = i_mm->t->offset;
796
+ #if HAVE_SEMCTL && HAVE_SHMCTL
797
+ if (i_mm->t->flag & MM_IPC) {
798
+ key_t key;
799
+ int shmid, semid, mode;
800
+ union semun sem_val;
801
+ struct shmid_ds buf;
802
+ mm_mmap *data;
803
+
804
+ if (!(vscope & MAP_SHARED)) {
805
+ rb_warning("Probably it will not do what you expect ...");
806
+ }
807
+ i_mm->t->key = -1;
808
+ i_mm->t->semid = 0;
809
+ if (TYPE(i_mm->t->shmid) == T_HASH) {
810
+ rb_iterate(rb_each, i_mm->t->shmid, mm_i_ipc, obj);
811
+ }
812
+ i_mm->t->shmid = 0;
813
+ if (i_mm->t->semid) {
814
+ mode = i_mm->t->semid;
815
+ i_mm->t->semid = 0;
816
+ }
817
+ else {
818
+ mode = 0644;
819
+ }
820
+ if ((int)i_mm->t->key <= 0) {
821
+ mode |= IPC_CREAT;
822
+ strcpy(template, "/tmp/ruby_mmap.XXXXXX");
823
+ if (mkstemp(template) == -1) {
824
+ rb_sys_fail("mkstemp()");
825
+ }
826
+ if ((key = ftok(template, 'R')) == -1) {
827
+ rb_sys_fail("ftok()");
828
+ }
829
+ }
830
+ else {
831
+ key = (key_t)i_mm->t->key;
832
+ }
833
+ if ((shmid = shmget(key, sizeof(mm_ipc), mode)) == -1) {
834
+ rb_sys_fail("shmget()");
835
+ }
836
+ data = shmat(shmid, (void *)0, 0);
837
+ if (data == (mm_mmap *)-1) {
838
+ rb_sys_fail("shmat()");
839
+ }
840
+ if (i_mm->t->flag & MM_TMP) {
841
+ if (shmctl(shmid, IPC_RMID, &buf) == -1) {
842
+ rb_sys_fail("shmctl()");
843
+ }
844
+ }
845
+ if ((semid = semget(key, 1, mode)) == -1) {
846
+ rb_sys_fail("semget()");
847
+ }
848
+ if (mode & IPC_CREAT) {
849
+ sem_val.val = 1;
850
+ if (semctl(semid, 0, SETVAL, sem_val) == -1) {
851
+ rb_sys_fail("semctl()");
852
+ }
853
+ }
854
+ memcpy(data, i_mm->t, sizeof(mm_mmap));
855
+ free(i_mm->t);
856
+ i_mm->t = data;
857
+ i_mm->t->key = key;
858
+ i_mm->t->semid = semid;
859
+ i_mm->t->shmid = shmid;
860
+ if (i_mm->t->flag & MM_TMP) {
861
+ i_mm->t->template = ALLOC_N(char, strlen(template) + 1);
862
+ strcpy(i_mm->t->template, template);
863
+ }
864
+ }
865
+ #endif
866
+ }
867
+ init = 0;
868
+ if (anonymous) {
869
+ if (size <= 0) {
870
+ rb_raise(rb_eArgError, "length not specified for an anonymous map");
871
+ }
872
+ if (offset) {
873
+ rb_warning("Ignoring offset for an anonymous map");
874
+ offset = 0;
875
+ }
876
+ smode = O_RDWR;
877
+ pmode = PROT_READ | PROT_WRITE;
878
+ i_mm->t->flag |= MM_FIXED | MM_ANON;
879
+ }
880
+ else {
881
+ if (size == 0 && (smode & O_RDWR)) {
882
+ if (lseek(fd, i_mm->t->incr - 1, SEEK_END) == -1) {
883
+ rb_raise(rb_eIOError, "Can't lseek %d", i_mm->t->incr - 1);
884
+ }
885
+ if (write(fd, "\000", 1) != 1) {
886
+ rb_raise(rb_eIOError, "Can't extend %s", path);
887
+ }
888
+ init = 1;
889
+ size = i_mm->t->incr;
890
+ }
891
+ if (!NIL_P(fdv)) {
892
+ i_mm->t->flag |= MM_FIXED;
893
+ }
894
+ }
895
+ addr = mmap(0, size, pmode, vscope, fd, offset);
896
+ if (NIL_P(fdv) && !anonymous) {
897
+ close(fd);
898
+ }
899
+ if (addr == MAP_FAILED || !addr) {
900
+ rb_raise(rb_eArgError, "mmap failed (%d)", errno);
901
+ }
902
+ #ifdef MADV_NORMAL
903
+ if (i_mm->t->advice && madvise(addr, size, i_mm->t->advice) == -1) {
904
+ rb_raise(rb_eArgError, "madvise(%d)", errno);
905
+ }
906
+ #endif
907
+ if (anonymous && TYPE(options) == T_HASH) {
908
+ VALUE val;
909
+ char *ptr;
910
+
911
+ val = rb_hash_aref(options, rb_str_new2("initialize"));
912
+ if (!NIL_P(val)) {
913
+ ptr = StringValuePtr(val);
914
+ memset(addr, ptr[0], size);
915
+ }
916
+ }
917
+ i_mm->t->addr = addr;
918
+ i_mm->t->len = size;
919
+ if (!init) i_mm->t->real = size;
920
+ i_mm->t->pmode = pmode;
921
+ i_mm->t->vscope = vscope;
922
+ i_mm->t->smode = smode & ~O_TRUNC;
923
+ i_mm->t->path = (path)?ruby_strdup(path):(char *)-1;
924
+ if (smode == O_RDONLY) {
925
+ obj = rb_obj_freeze(obj);
926
+ i_mm->t->flag |= MM_FROZEN;
927
+ }
928
+ else {
929
+ if (smode == O_WRONLY) {
930
+ i_mm->t->flag |= MM_FIXED;
931
+ }
932
+ OBJ_TAINT(obj);
933
+ }
934
+ return obj;
935
+ }
936
+
937
+ /*
938
+ * Document-method: msync
939
+ * Document-method: sync
940
+ * Document-method: flush
941
+ *
942
+ * call-seq: msync
943
+ *
944
+ * flush the file
945
+ */
946
+ static VALUE
947
+ mm_msync(argc, argv, obj)
948
+ int argc;
949
+ VALUE *argv, obj;
950
+ {
951
+ mm_ipc *i_mm;
952
+ VALUE oflag;
953
+ int ret;
954
+ int flag = MS_SYNC;
955
+
956
+ if (argc) {
957
+ rb_scan_args(argc, argv, "01", &oflag);
958
+ flag = NUM2INT(oflag);
959
+ }
960
+ GetMmap(obj, i_mm, MM_MODIFY);
961
+ if ((ret = msync(i_mm->t->addr, i_mm->t->len, flag)) != 0) {
962
+ rb_raise(rb_eArgError, "msync(%d)", ret);
963
+ }
964
+ if (i_mm->t->real < i_mm->t->len && i_mm->t->vscope != MAP_PRIVATE)
965
+ mm_expandf(i_mm, i_mm->t->real);
966
+ return obj;
967
+ }
968
+
969
+ /*
970
+ * Document-method: mprotect
971
+ * Document-method: protect
972
+ *
973
+ * call-seq: mprotect(mode)
974
+ *
975
+ * change the mode, value must be "r", "w" or "rw"
976
+ */
977
+ static VALUE
978
+ mm_mprotect(obj, a)
979
+ VALUE obj, a;
980
+ {
981
+ mm_ipc *i_mm;
982
+ int ret, pmode;
983
+ char *smode;
984
+
985
+ GetMmap(obj, i_mm, 0);
986
+ if (TYPE(a) == T_STRING) {
987
+ smode = StringValuePtr(a);
988
+ if (strcmp(smode, "r") == 0) pmode = PROT_READ;
989
+ else if (strcmp(smode, "w") == 0) pmode = PROT_WRITE;
990
+ else if (strcmp(smode, "rw") == 0 || strcmp(smode, "wr") == 0)
991
+ pmode = PROT_READ | PROT_WRITE;
992
+ else {
993
+ rb_raise(rb_eArgError, "Invalid mode %s", smode);
994
+ }
995
+ }
996
+ else {
997
+ pmode = NUM2INT(a);
998
+ }
999
+ if ((pmode & PROT_WRITE) && (i_mm->t->flag & MM_FROZEN))
1000
+ rb_error_frozen("mmap");
1001
+ if ((ret = mprotect(i_mm->t->addr, i_mm->t->len, pmode | PROT_READ)) != 0) {
1002
+ rb_raise(rb_eArgError, "mprotect(%d)", ret);
1003
+ }
1004
+ i_mm->t->pmode = pmode;
1005
+ if (pmode & PROT_READ) {
1006
+ if (pmode & PROT_WRITE) i_mm->t->smode = O_RDWR;
1007
+ else {
1008
+ i_mm->t->smode = O_RDONLY;
1009
+ obj = rb_obj_freeze(obj);
1010
+ i_mm->t->flag |= MM_FROZEN;
1011
+ }
1012
+ }
1013
+ else if (pmode & PROT_WRITE) {
1014
+ i_mm->t->flag |= MM_FIXED;
1015
+ i_mm->t->smode = O_WRONLY;
1016
+ }
1017
+ return obj;
1018
+ }
1019
+
1020
+ #ifdef MADV_NORMAL
1021
+ /*
1022
+ * Document-method: madvise
1023
+ * Document-method: advise
1024
+ *
1025
+ * call-seq: madvise(advice)
1026
+ *
1027
+ * <em>advice</em> can have the value <em>Mmap::MADV_NORMAL</em>,
1028
+ * <em>Mmap::MADV_RANDOM</em>, <em>Mmap::MADV_SEQUENTIAL</em>,
1029
+ * <em>Mmap::MADV_WILLNEED</em>, <em>Mmap::MADV_DONTNEED</em>
1030
+ *
1031
+ */
1032
+ static VALUE
1033
+ mm_madvise(obj, a)
1034
+ VALUE obj, a;
1035
+ {
1036
+ mm_ipc *i_mm;
1037
+
1038
+ GetMmap(obj, i_mm, 0);
1039
+ if (madvise(i_mm->t->addr, i_mm->t->len, NUM2INT(a)) == -1) {
1040
+ rb_raise(rb_eTypeError, "madvise(%d)", errno);
1041
+ }
1042
+ i_mm->t->advice = NUM2INT(a);
1043
+ return Qnil;
1044
+ }
1045
+ #endif
1046
+
1047
+ #define StringMmap(b, bp, bl) \
1048
+ do { \
1049
+ if (TYPE(b) == T_DATA && RDATA(b)->dfree == (RUBY_DATA_FUNC)mm_free) { \
1050
+ mm_ipc *b_mm; \
1051
+ GetMmap(b, b_mm, 0); \
1052
+ bp = b_mm->t->addr; \
1053
+ bl = b_mm->t->real; \
1054
+ } \
1055
+ else { \
1056
+ bp = StringValuePtr(b); \
1057
+ bl = RSTRING(b)->len; \
1058
+ } \
1059
+ } while (0);
1060
+
1061
+ static void
1062
+ mm_update(str, beg, len, val)
1063
+ mm_ipc *str;
1064
+ VALUE val;
1065
+ long beg;
1066
+ long len;
1067
+ {
1068
+ char *valp;
1069
+ long vall;
1070
+
1071
+ if (str->t->flag & MM_FROZEN) rb_error_frozen("mmap");
1072
+ if (len < 0) rb_raise(rb_eIndexError, "negative length %d", len);
1073
+ mm_lock(str);
1074
+ if (beg < 0) {
1075
+ beg += str->t->real;
1076
+ }
1077
+ if (beg < 0 || str->t->real < (size_t)beg) {
1078
+ if (beg < 0) {
1079
+ beg -= str->t->real;
1080
+ }
1081
+ mm_unlock(str);
1082
+ rb_raise(rb_eIndexError, "index %d out of string", beg);
1083
+ }
1084
+ if (str->t->real < (size_t)(beg + len)) {
1085
+ len = str->t->real - beg;
1086
+ }
1087
+
1088
+ mm_unlock(str);
1089
+ StringMmap(val, valp, vall);
1090
+ mm_lock(str);
1091
+
1092
+ if ((str->t->flag & MM_FIXED) && vall != len) {
1093
+ mm_unlock(str);
1094
+ rb_raise(rb_eTypeError, "try to change the size of a fixed map");
1095
+ }
1096
+ if (len < vall) {
1097
+ mm_realloc(str, str->t->real + vall - len);
1098
+ }
1099
+
1100
+ if (vall != len) {
1101
+ memmove((char *)str->t->addr + beg + vall,
1102
+ (char *)str->t->addr + beg + len,
1103
+ str->t->real - (beg + len));
1104
+ }
1105
+ if (str->t->real < (size_t)beg && len < 0) {
1106
+ MEMZERO(str->t->addr + str->t->real, char, -len);
1107
+ }
1108
+ if (vall > 0) {
1109
+ memmove((char *)str->t->addr + beg, valp, vall);
1110
+ }
1111
+ str->t->real += vall - len;
1112
+ mm_unlock(str);
1113
+ }
1114
+
1115
+ /*
1116
+ * call-seq: =~(other)
1117
+ *
1118
+ * return an index of the match
1119
+ */
1120
+ static VALUE
1121
+ mm_match(x, y)
1122
+ VALUE x, y;
1123
+ {
1124
+ VALUE reg, res;
1125
+ long start;
1126
+
1127
+ x = mm_str(x, MM_ORIGIN);
1128
+ if (TYPE(y) == T_DATA && RDATA(y)->dfree == (RUBY_DATA_FUNC)mm_free) {
1129
+ y = mm_to_str(y);
1130
+ }
1131
+ switch (TYPE(y)) {
1132
+ case T_REGEXP:
1133
+ res = rb_reg_match(y, x);
1134
+ break;
1135
+
1136
+ case T_STRING:
1137
+ reg = rb_reg_regcomp(y);
1138
+ start = rb_reg_search(reg, x, 0, 0);
1139
+ if (start == -1) res = Qnil;
1140
+ else res = INT2NUM(start);
1141
+ break;
1142
+
1143
+ default:
1144
+ res = rb_funcall(y, rb_intern("=~"), 1, x);
1145
+ break;
1146
+ }
1147
+ return res;
1148
+ }
1149
+
1150
+ static VALUE
1151
+ get_pat(pat)
1152
+ VALUE pat;
1153
+ {
1154
+ switch (TYPE(pat)) {
1155
+ case T_REGEXP:
1156
+ break;
1157
+
1158
+ case T_STRING:
1159
+ pat = rb_reg_regcomp(pat);
1160
+ break;
1161
+
1162
+ default:
1163
+ /* type failed */
1164
+ Check_Type(pat, T_REGEXP);
1165
+ }
1166
+ return pat;
1167
+ }
1168
+
1169
+ static int
1170
+ mm_correct_backref()
1171
+ {
1172
+ VALUE match;
1173
+ int i, start;
1174
+
1175
+ match = rb_backref_get();
1176
+ if (NIL_P(match)) return 0;
1177
+ if (RMATCH(match)->BEG(0) == -1) return 0;
1178
+ start = RMATCH(match)->BEG(0);
1179
+ RMATCH(match)->str = rb_str_new(StringValuePtr(RMATCH(match)->str) + start,
1180
+ RMATCH(match)->END(0) - start);
1181
+ if (OBJ_TAINTED(match)) OBJ_TAINT(RMATCH(match)->str);
1182
+ for (i = 0; i < RMATCH(match)->regs->num_regs && RMATCH(match)->BEG(i) != -1; i++) {
1183
+ RMATCH(match)->BEG(i) -= start;
1184
+ RMATCH(match)->END(i) -= start;
1185
+ }
1186
+ rb_backref_set(match);
1187
+ return start;
1188
+ }
1189
+
1190
+ static VALUE
1191
+ mm_sub_bang_int(bang_st)
1192
+ mm_bang *bang_st;
1193
+ {
1194
+ int argc = bang_st->argc;
1195
+ VALUE *argv = bang_st->argv;
1196
+ VALUE obj = bang_st->obj;
1197
+ VALUE pat, repl = Qnil, match, str, res;
1198
+ struct re_registers *regs;
1199
+ int start, iter = 0;
1200
+ int tainted = 0;
1201
+ long plen;
1202
+ mm_ipc *i_mm;
1203
+
1204
+ if (argc == 1 && rb_block_given_p()) {
1205
+ iter = 1;
1206
+ }
1207
+ else if (argc == 2) {
1208
+ repl = rb_str_to_str(argv[1]);
1209
+ if (OBJ_TAINTED(repl)) tainted = 1;
1210
+ }
1211
+ else {
1212
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 2)", argc);
1213
+ }
1214
+ GetMmap(obj, i_mm, MM_MODIFY);
1215
+ str = mm_str(obj, MM_MODIFY | MM_ORIGIN);
1216
+
1217
+ pat = get_pat(argv[0]);
1218
+ res = Qnil;
1219
+ if (rb_reg_search(pat, str, 0, 0) >= 0) {
1220
+ start = mm_correct_backref();
1221
+ match = rb_backref_get();
1222
+ regs = RMATCH(match)->regs;
1223
+ if (iter) {
1224
+ rb_match_busy(match);
1225
+ repl = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match)));
1226
+ rb_backref_set(match);
1227
+ }
1228
+ else {
1229
+ RSTRING(str)->ptr += start;
1230
+ repl = rb_reg_regsub(repl, str, regs);
1231
+ RSTRING(str)->ptr -= start;
1232
+ }
1233
+ if (OBJ_TAINTED(repl)) tainted = 1;
1234
+ plen = END(0) - BEG(0);
1235
+ if (RSTRING(repl)->len > plen) {
1236
+ mm_realloc(i_mm, RSTRING(str)->len + RSTRING(repl)->len - plen);
1237
+ RSTRING(str)->ptr = i_mm->t->addr;
1238
+ }
1239
+ if (RSTRING(repl)->len != plen) {
1240
+ if (i_mm->t->flag & MM_FIXED) {
1241
+ rb_raise(rb_eTypeError, "try to change the size of a fixed map");
1242
+ }
1243
+ memmove(RSTRING(str)->ptr + start + BEG(0) + RSTRING(repl)->len,
1244
+ RSTRING(str)->ptr + start + BEG(0) + plen,
1245
+ RSTRING(str)->len - start - BEG(0) - plen);
1246
+ }
1247
+ memcpy(RSTRING(str)->ptr + start + BEG(0),
1248
+ RSTRING(repl)->ptr, RSTRING(repl)->len);
1249
+ i_mm->t->real += RSTRING(repl)->len - plen;
1250
+ if (tainted) OBJ_TAINT(obj);
1251
+
1252
+ res = obj;
1253
+ }
1254
+ rb_gc_force_recycle(str);
1255
+ return res;
1256
+ }
1257
+
1258
+ /*
1259
+ * call-seq:
1260
+ * str.sub!(pattern, replacement) => str or nil
1261
+ * str.sub!(pattern) {|match| block } => str or nil
1262
+ *
1263
+ * substitution
1264
+ */
1265
+ static VALUE
1266
+ mm_sub_bang(argc, argv, obj)
1267
+ int argc;
1268
+ VALUE *argv;
1269
+ VALUE obj;
1270
+ {
1271
+ VALUE res;
1272
+ mm_bang bang_st;
1273
+ mm_ipc *i_mm;
1274
+
1275
+ bang_st.argc = argc;
1276
+ bang_st.argv = argv;
1277
+ bang_st.obj = obj;
1278
+ GetMmap(obj, i_mm, MM_MODIFY);
1279
+ if (i_mm->t->flag & MM_IPC) {
1280
+ mm_lock(i_mm, Qtrue);
1281
+ res = rb_ensure(mm_sub_bang_int, (VALUE)&bang_st, mm_vunlock, obj);
1282
+ }
1283
+ else {
1284
+ res = mm_sub_bang_int(&bang_st);
1285
+ }
1286
+ return res;
1287
+ }
1288
+
1289
+ static VALUE
1290
+ mm_gsub_bang_int(bang_st)
1291
+ mm_bang *bang_st;
1292
+ {
1293
+ int argc = bang_st->argc;
1294
+ VALUE *argv = bang_st->argv;
1295
+ VALUE obj = bang_st->obj;
1296
+ VALUE pat, val, repl = Qnil, match, str;
1297
+ struct re_registers *regs;
1298
+ long beg, offset;
1299
+ int start, iter = 0;
1300
+ int tainted = 0;
1301
+ long plen;
1302
+ mm_ipc *i_mm;
1303
+
1304
+ if (argc == 1 && rb_block_given_p()) {
1305
+ iter = 1;
1306
+ }
1307
+ else if (argc == 2) {
1308
+ repl = rb_str_to_str(argv[1]);
1309
+ if (OBJ_TAINTED(repl)) tainted = 1;
1310
+ }
1311
+ else {
1312
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 2)", argc);
1313
+ }
1314
+ GetMmap(obj, i_mm, MM_MODIFY);
1315
+ str = mm_str(obj, MM_MODIFY | MM_ORIGIN);
1316
+
1317
+ pat = get_pat(argv[0]);
1318
+ offset = 0;
1319
+ beg = rb_reg_search(pat, str, 0, 0);
1320
+ if (beg < 0) {
1321
+ rb_gc_force_recycle(str);
1322
+ return Qnil;
1323
+ }
1324
+ while (beg >= 0) {
1325
+ start = mm_correct_backref();
1326
+ match = rb_backref_get();
1327
+ regs = RMATCH(match)->regs;
1328
+ if (iter) {
1329
+ rb_match_busy(match);
1330
+ val = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match)));
1331
+ rb_backref_set(match);
1332
+ }
1333
+ else {
1334
+ RSTRING(str)->ptr += start;
1335
+ val = rb_reg_regsub(repl, str, regs);
1336
+ RSTRING(str)->ptr -= start;
1337
+ }
1338
+ if (OBJ_TAINTED(repl)) tainted = 1;
1339
+ plen = END(0) - BEG(0);
1340
+ if ((i_mm->t->real + RSTRING(val)->len - plen) > i_mm->t->len) {
1341
+ mm_realloc(i_mm, RSTRING(str)->len + RSTRING(val)->len - plen);
1342
+ }
1343
+ if (RSTRING(val)->len != plen) {
1344
+ if (i_mm->t->flag & MM_FIXED) {
1345
+ rb_raise(rb_eTypeError, "try to change the size of a fixed map");
1346
+ }
1347
+ memmove(RSTRING(str)->ptr + start + BEG(0) + RSTRING(val)->len,
1348
+ RSTRING(str)->ptr + start + BEG(0) + plen,
1349
+ RSTRING(str)->len - start - BEG(0) - plen);
1350
+ }
1351
+ memcpy(RSTRING(str)->ptr + start + BEG(0),
1352
+ RSTRING(val)->ptr, RSTRING(val)->len);
1353
+ RSTRING(str)->len += RSTRING(val)->len - plen;
1354
+ i_mm->t->real = RSTRING(str)->len;
1355
+ if (BEG(0) == END(0)) {
1356
+ offset = start + END(0) + mbclen2(RSTRING(str)->ptr[END(0)], pat);
1357
+ offset += RSTRING(val)->len - plen;
1358
+ }
1359
+ else {
1360
+ offset = start + END(0) + RSTRING(val)->len - plen;
1361
+ }
1362
+ if (offset > RSTRING(str)->len) break;
1363
+ beg = rb_reg_search(pat, str, offset, 0);
1364
+ }
1365
+ rb_backref_set(match);
1366
+ if (tainted) OBJ_TAINT(obj);
1367
+ rb_gc_force_recycle(str);
1368
+ return obj;
1369
+ }
1370
+
1371
+ /*
1372
+ * call-seq:
1373
+ * str.gsub!(pattern, replacement) => str or nil
1374
+ * str.gsub!(pattern) {|match| block } => str or nil
1375
+ *
1376
+ * global substitution
1377
+ */
1378
+ static VALUE
1379
+ mm_gsub_bang(argc, argv, obj)
1380
+ int argc;
1381
+ VALUE *argv;
1382
+ VALUE obj;
1383
+ {
1384
+ VALUE res;
1385
+ mm_bang bang_st;
1386
+ mm_ipc *i_mm;
1387
+
1388
+ bang_st.argc = argc;
1389
+ bang_st.argv = argv;
1390
+ bang_st.obj = obj;
1391
+ GetMmap(obj, i_mm, MM_MODIFY);
1392
+ if (i_mm->t->flag & MM_IPC) {
1393
+ mm_lock(i_mm, Qtrue);
1394
+ res = rb_ensure(mm_gsub_bang_int, (VALUE)&bang_st, mm_vunlock, obj);
1395
+ }
1396
+ else {
1397
+ res = mm_gsub_bang_int(&bang_st);
1398
+ }
1399
+ return res;
1400
+ }
1401
+
1402
+ static VALUE mm_index __((int, VALUE *, VALUE));
1403
+
1404
+ #if HAVE_RB_DEFINE_ALLOC_FUNC
1405
+
1406
+ static void
1407
+ mm_subpat_set(obj, re, offset, val)
1408
+ VALUE obj, re;
1409
+ int offset;
1410
+ VALUE val;
1411
+ {
1412
+ VALUE str, match;
1413
+ int start, end, len;
1414
+ mm_ipc *i_mm;
1415
+
1416
+ str = mm_str(obj, MM_MODIFY | MM_ORIGIN);
1417
+ if (rb_reg_search(re, str, 0, 0) < 0) {
1418
+ rb_raise(rb_eIndexError, "regexp not matched");
1419
+ }
1420
+ match = rb_backref_get();
1421
+ if (offset >= RMATCH(match)->regs->num_regs) {
1422
+ rb_raise(rb_eIndexError, "index %d out of regexp", offset);
1423
+ }
1424
+
1425
+ start = RMATCH(match)->BEG(offset);
1426
+ if (start == -1) {
1427
+ rb_raise(rb_eIndexError, "regexp group %d not matched", offset);
1428
+ }
1429
+ end = RMATCH(match)->END(offset);
1430
+ len = end - start;
1431
+ GetMmap(obj, i_mm, MM_MODIFY);
1432
+ mm_update(i_mm, start, len, val);
1433
+ }
1434
+
1435
+ #endif
1436
+
1437
+ static VALUE
1438
+ mm_aset(str, indx, val)
1439
+ VALUE str;
1440
+ VALUE indx, val;
1441
+ {
1442
+ long idx;
1443
+ mm_ipc *i_mm;
1444
+
1445
+ GetMmap(str, i_mm, MM_MODIFY);
1446
+ switch (TYPE(indx)) {
1447
+ case T_FIXNUM:
1448
+ num_index:
1449
+ idx = NUM2INT(indx);
1450
+ if (idx < 0) {
1451
+ idx += i_mm->t->real;
1452
+ }
1453
+ if (idx < 0 || i_mm->t->real <= (size_t)idx) {
1454
+ rb_raise(rb_eIndexError, "index %d out of string", idx);
1455
+ }
1456
+ if (FIXNUM_P(val)) {
1457
+ if (i_mm->t->real == (size_t)idx) {
1458
+ i_mm->t->real += 1;
1459
+ mm_realloc(i_mm, i_mm->t->real);
1460
+ }
1461
+ ((char *)i_mm->t->addr)[idx] = NUM2INT(val) & 0xff;
1462
+ }
1463
+ else {
1464
+ mm_update(i_mm, idx, 1, val);
1465
+ }
1466
+ return val;
1467
+
1468
+ case T_REGEXP:
1469
+ #if HAVE_RB_DEFINE_ALLOC_FUNC
1470
+ mm_subpat_set(str, indx, 0, val);
1471
+ #else
1472
+ {
1473
+ VALUE args[2];
1474
+ args[0] = indx;
1475
+ args[1] = val;
1476
+ mm_sub_bang(2, args, str);
1477
+ }
1478
+ #endif
1479
+ return val;
1480
+
1481
+ case T_STRING:
1482
+ {
1483
+ VALUE res;
1484
+
1485
+ res = mm_index(1, &indx, str);
1486
+ if (!NIL_P(res)) {
1487
+ mm_update(i_mm, NUM2LONG(res), RSTRING(indx)->len, val);
1488
+ }
1489
+ return val;
1490
+ }
1491
+
1492
+ default:
1493
+ /* check if indx is Range */
1494
+ {
1495
+ long beg, len;
1496
+ if (rb_range_beg_len(indx, &beg, &len, i_mm->t->real, 2)) {
1497
+ mm_update(i_mm, beg, len, val);
1498
+ return val;
1499
+ }
1500
+ }
1501
+ idx = NUM2LONG(indx);
1502
+ goto num_index;
1503
+ }
1504
+ }
1505
+
1506
+ /*
1507
+ * call-seq: []=(args)
1508
+ *
1509
+ * Element assignement - with the following syntax
1510
+ *
1511
+ * self[nth] = val
1512
+ *
1513
+ * change the <em>nth</em> character with <em>val</em>
1514
+ *
1515
+ * self[start..last] = val
1516
+ *
1517
+ * change substring from <em>start</em> to <em>last</em> with <em>val</em>
1518
+ *
1519
+ * self[start, len] = val
1520
+ *
1521
+ * replace <em>length</em> characters from <em>start</em> with <em>val</em>.
1522
+ *
1523
+ */
1524
+ static VALUE
1525
+ mm_aset_m(argc, argv, str)
1526
+ int argc;
1527
+ VALUE *argv;
1528
+ VALUE str;
1529
+ {
1530
+ mm_ipc *i_mm;
1531
+
1532
+ GetMmap(str, i_mm, MM_MODIFY);
1533
+ if (argc == 3) {
1534
+ long beg, len;
1535
+
1536
+ #if HAVE_RB_DEFINE_ALLOC_FUNC
1537
+ if (TYPE(argv[0]) == T_REGEXP) {
1538
+ mm_subpat_set(str, argv[0], NUM2INT(argv[1]), argv[2]);
1539
+ }
1540
+ else
1541
+ #endif
1542
+ {
1543
+ beg = NUM2INT(argv[0]);
1544
+ len = NUM2INT(argv[1]);
1545
+ mm_update(i_mm, beg, len, argv[2]);
1546
+ }
1547
+ return argv[2];
1548
+ }
1549
+ if (argc != 2) {
1550
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 2)", argc);
1551
+ }
1552
+ return mm_aset(str, argv[0], argv[1]);
1553
+ }
1554
+
1555
+ #if HAVE_RB_STR_INSERT
1556
+
1557
+ /*
1558
+ * call-seq: insert(index, str)
1559
+ *
1560
+ * insert <em>str</em> at <em>index</em>
1561
+ */
1562
+ static VALUE
1563
+ mm_insert(str, idx, str2)
1564
+ VALUE str, idx, str2;
1565
+ {
1566
+ mm_ipc *i_mm;
1567
+ long pos = NUM2LONG(idx);
1568
+
1569
+ GetMmap(str, i_mm, MM_MODIFY);
1570
+ if (pos == -1) {
1571
+ pos = RSTRING(str)->len;
1572
+ }
1573
+ else if (pos < 0) {
1574
+ pos++;
1575
+ }
1576
+ mm_update(i_mm, pos, 0, str2);
1577
+ return str;
1578
+ }
1579
+
1580
+ #endif
1581
+
1582
+ static VALUE mm_aref_m _((int, VALUE *, VALUE));
1583
+
1584
+ /*
1585
+ * call-seq: slice!(str)
1586
+ *
1587
+ * delete the specified portion of the file
1588
+ */
1589
+ static VALUE
1590
+ mm_slice_bang(argc, argv, str)
1591
+ int argc;
1592
+ VALUE *argv;
1593
+ VALUE str;
1594
+ {
1595
+ VALUE result;
1596
+ VALUE buf[3];
1597
+ int i;
1598
+
1599
+ if (argc < 1 || 2 < argc) {
1600
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 1)", argc);
1601
+ }
1602
+ for (i = 0; i < argc; i++) {
1603
+ buf[i] = argv[i];
1604
+ }
1605
+ buf[i] = rb_str_new(0,0);
1606
+ result = mm_aref_m(argc, buf, str);
1607
+ if (!NIL_P(result)) {
1608
+ mm_aset_m(argc+1, buf, str);
1609
+ }
1610
+ return result;
1611
+ }
1612
+
1613
+ static VALUE
1614
+ mm_cat(str, ptr, len)
1615
+ VALUE str;
1616
+ const char *ptr;
1617
+ long len;
1618
+ {
1619
+ mm_ipc *i_mm;
1620
+ char *sptr;
1621
+
1622
+ GetMmap(str, i_mm, MM_MODIFY);
1623
+ if (len > 0) {
1624
+ int poffset = -1;
1625
+ sptr = (char *)i_mm->t->addr;
1626
+
1627
+ if (sptr <= ptr &&
1628
+ ptr < sptr + i_mm->t->real) {
1629
+ poffset = ptr - sptr;
1630
+ }
1631
+ mm_lock(i_mm, Qtrue);
1632
+ mm_realloc(i_mm, i_mm->t->real + len);
1633
+ sptr = (char *)i_mm->t->addr;
1634
+ if (ptr) {
1635
+ if (poffset >= 0) ptr = sptr + poffset;
1636
+ memcpy(sptr + i_mm->t->real, ptr, len);
1637
+ }
1638
+ i_mm->t->real += len;
1639
+ mm_unlock(i_mm);
1640
+ }
1641
+ return str;
1642
+ }
1643
+
1644
+ static VALUE
1645
+ mm_append(str1, str2)
1646
+ VALUE str1, str2;
1647
+ {
1648
+ str2 = rb_str_to_str(str2);
1649
+ str1 = mm_cat(str1, StringValuePtr(str2), RSTRING(str2)->len);
1650
+ return str1;
1651
+ }
1652
+
1653
+ /*
1654
+ * Document-method: concat
1655
+ * Document-method: <<
1656
+ *
1657
+ * call-seq: concat(other)
1658
+ *
1659
+ * append the contents of <em>other</em>
1660
+ */
1661
+ static VALUE
1662
+ mm_concat(str1, str2)
1663
+ VALUE str1, str2;
1664
+ {
1665
+ if (FIXNUM_P(str2)) {
1666
+ int i = FIX2INT(str2);
1667
+ if (0 <= i && i <= 0xff) { /* byte */
1668
+ char c = i;
1669
+ return mm_cat(str1, &c, 1);
1670
+ }
1671
+ }
1672
+ str1 = mm_append(str1, str2);
1673
+ return str1;
1674
+ }
1675
+
1676
+ #ifndef HAVE_RB_STR_LSTRIP
1677
+
1678
+ /*
1679
+ * call-seq: strip!
1680
+ *
1681
+ * removes leading and trailing whitespace
1682
+ */
1683
+ static VALUE
1684
+ mm_strip_bang(str)
1685
+ VALUE str;
1686
+ {
1687
+ char *s, *t, *e;
1688
+ mm_ipc *i_mm;
1689
+
1690
+ GetMmap(str, i_mm, MM_MODIFY);
1691
+ mm_lock(i_mm, Qtrue);
1692
+ s = (char *)i_mm->t->addr;
1693
+ e = t = s + i_mm->t->real;
1694
+ while (s < t && ISSPACE(*s)) s++;
1695
+ t--;
1696
+ while (s <= t && ISSPACE(*t)) t--;
1697
+ t++;
1698
+
1699
+ if (i_mm->t->real != (t - s) && (i_mm->t->flag & MM_FIXED)) {
1700
+ mm_unlock(i_mm);
1701
+ rb_raise(rb_eTypeError, "try to change the size of a fixed map");
1702
+ }
1703
+ i_mm->t->real = t-s;
1704
+ if (s > (char *)i_mm->t->addr) {
1705
+ memmove(i_mm->t->addr, s, i_mm->t->real);
1706
+ ((char *)i_mm->t->addr)[i_mm->t->real] = '\0';
1707
+ }
1708
+ else if (t < e) {
1709
+ ((char *)i_mm->t->addr)[i_mm->t->real] = '\0';
1710
+ }
1711
+ else {
1712
+ str = Qnil;
1713
+ }
1714
+ mm_unlock(i_mm);
1715
+ return str;
1716
+ }
1717
+
1718
+ #else
1719
+
1720
+ /*
1721
+ * call-seq: lstrip!
1722
+ *
1723
+ * removes leading whitespace
1724
+ */
1725
+ static VALUE
1726
+ mm_lstrip_bang(str)
1727
+ VALUE str;
1728
+ {
1729
+ char *s, *t, *e;
1730
+ mm_ipc *i_mm;
1731
+
1732
+ GetMmap(str, i_mm, MM_MODIFY);
1733
+ mm_lock(i_mm, Qtrue);
1734
+ s = (char *)i_mm->t->addr;
1735
+ e = t = s + i_mm->t->real;
1736
+ while (s < t && ISSPACE(*s)) s++;
1737
+
1738
+ if (i_mm->t->real != (size_t)(t - s) && (i_mm->t->flag & MM_FIXED)) {
1739
+ mm_unlock(i_mm);
1740
+ rb_raise(rb_eTypeError, "try to change the size of a fixed map");
1741
+ }
1742
+ i_mm->t->real = t - s;
1743
+ if (s > (char *)i_mm->t->addr) {
1744
+ memmove(i_mm->t->addr, s, i_mm->t->real);
1745
+ ((char *)i_mm->t->addr)[i_mm->t->real] = '\0';
1746
+ mm_unlock(i_mm);
1747
+ return str;
1748
+ }
1749
+ mm_unlock(i_mm);
1750
+ return Qnil;
1751
+ }
1752
+
1753
+ /*
1754
+ * call-seq: rstrip!
1755
+ *
1756
+ * removes trailing whitespace
1757
+ */
1758
+ static VALUE
1759
+ mm_rstrip_bang(str)
1760
+ VALUE str;
1761
+ {
1762
+ char *s, *t, *e;
1763
+ mm_ipc *i_mm;
1764
+
1765
+ GetMmap(str, i_mm, MM_MODIFY);
1766
+ mm_lock(i_mm, Qtrue);
1767
+ s = (char *)i_mm->t->addr;
1768
+ e = t = s + i_mm->t->real;
1769
+ t--;
1770
+ while (s <= t && ISSPACE(*t)) t--;
1771
+ t++;
1772
+ if (i_mm->t->real != (size_t)(t - s) && (i_mm->t->flag & MM_FIXED)) {
1773
+ mm_unlock(i_mm);
1774
+ rb_raise(rb_eTypeError, "try to change the size of a fixed map");
1775
+ }
1776
+ i_mm->t->real = t - s;
1777
+ if (t < e) {
1778
+ ((char *)i_mm->t->addr)[i_mm->t->real] = '\0';
1779
+ mm_unlock(i_mm);
1780
+ return str;
1781
+ }
1782
+ mm_unlock(i_mm);
1783
+ return Qnil;
1784
+ }
1785
+
1786
+ static VALUE
1787
+ mm_strip_bang(str)
1788
+ VALUE str;
1789
+ {
1790
+ VALUE l = mm_lstrip_bang(str);
1791
+ VALUE r = mm_rstrip_bang(str);
1792
+
1793
+ if (NIL_P(l) && NIL_P(r)) return Qnil;
1794
+ return str;
1795
+ }
1796
+
1797
+ #endif
1798
+
1799
+ #define MmapStr(b, recycle) \
1800
+ do { \
1801
+ recycle = 0; \
1802
+ if (TYPE(b) == T_DATA && RDATA(b)->dfree == (RUBY_DATA_FUNC)mm_free) { \
1803
+ recycle = 1; \
1804
+ b = mm_str(b, MM_ORIGIN); \
1805
+ } \
1806
+ else { \
1807
+ b = rb_str_to_str(b); \
1808
+ } \
1809
+ } while (0);
1810
+
1811
+
1812
+ /*
1813
+ * call-seq: <=>(other)
1814
+ *
1815
+ * comparison : return -1, 0, 1
1816
+ */
1817
+ static VALUE
1818
+ mm_cmp(a, b)
1819
+ VALUE a, b;
1820
+ {
1821
+ int result;
1822
+ int recycle = 0;
1823
+
1824
+ a = mm_str(a, MM_ORIGIN);
1825
+ MmapStr(b, recycle);
1826
+ result = rb_str_cmp(a, b);
1827
+ rb_gc_force_recycle(a);
1828
+ if (recycle) rb_gc_force_recycle(b);
1829
+ return INT2FIX(result);
1830
+ }
1831
+
1832
+ #if HAVE_RB_STR_CASECMP
1833
+
1834
+ /*
1835
+ * call-seq: casecmp(other)
1836
+ *
1837
+ * only with ruby >= 1.7.1
1838
+ */
1839
+ static VALUE
1840
+ mm_casecmp(a, b)
1841
+ VALUE a, b;
1842
+ {
1843
+ VALUE result;
1844
+ int recycle = 0;
1845
+
1846
+ a = mm_str(a, MM_ORIGIN);
1847
+ MmapStr(b, recycle);
1848
+ result = rb_funcall2(a, rb_intern("casecmp"), 1, &b);
1849
+ rb_gc_force_recycle(a);
1850
+ if (recycle) rb_gc_force_recycle(b);
1851
+ return result;
1852
+ }
1853
+
1854
+ #endif
1855
+
1856
+ /*
1857
+ * Document-method: ==
1858
+ * Document-method: ===
1859
+ *
1860
+ * call-seq: ==
1861
+ *
1862
+ * comparison
1863
+ */
1864
+ static VALUE
1865
+ mm_equal(a, b)
1866
+ VALUE a, b;
1867
+ {
1868
+ VALUE result;
1869
+ mm_ipc *i_mm, *u_mm;
1870
+
1871
+ if (a == b) return Qtrue;
1872
+ if (TYPE(b) != T_DATA || RDATA(b)->dfree != (RUBY_DATA_FUNC)mm_free)
1873
+ return Qfalse;
1874
+
1875
+ GetMmap(a, i_mm, 0);
1876
+ GetMmap(b, u_mm, 0);
1877
+ if (i_mm->t->real != u_mm->t->real)
1878
+ return Qfalse;
1879
+ a = mm_str(a, MM_ORIGIN);
1880
+ b = mm_str(b, MM_ORIGIN);
1881
+ result = rb_funcall2(a, rb_intern("=="), 1, &b);
1882
+ rb_gc_force_recycle(a);
1883
+ rb_gc_force_recycle(b);
1884
+ return result;
1885
+ }
1886
+
1887
+ /*
1888
+ * call-seq: eql?(other)
1889
+ *
1890
+ * Is this eql? to +other+ ?
1891
+ */
1892
+ static VALUE
1893
+ mm_eql(a, b)
1894
+ VALUE a, b;
1895
+ {
1896
+ VALUE result;
1897
+ mm_ipc *i_mm, *u_mm;
1898
+
1899
+ if (a == b) return Qtrue;
1900
+ if (TYPE(b) != T_DATA || RDATA(b)->dfree != (RUBY_DATA_FUNC)mm_free)
1901
+ return Qfalse;
1902
+
1903
+ GetMmap(a, i_mm, 0);
1904
+ GetMmap(b, u_mm, 0);
1905
+ if (i_mm->t->real != u_mm->t->real)
1906
+ return Qfalse;
1907
+ a = mm_str(a, MM_ORIGIN);
1908
+ b = mm_str(b, MM_ORIGIN);
1909
+ result = rb_funcall2(a, rb_intern("eql?"), 1, &b);
1910
+ rb_gc_force_recycle(a);
1911
+ rb_gc_force_recycle(b);
1912
+ return result;
1913
+ }
1914
+
1915
+ /*
1916
+ * call-seq: hash
1917
+ *
1918
+ * Get the hash value
1919
+ */
1920
+ static VALUE
1921
+ mm_hash(a)
1922
+ VALUE a;
1923
+ {
1924
+ VALUE b;
1925
+ int res;
1926
+
1927
+ b = mm_str(a, MM_ORIGIN);
1928
+ res = rb_str_hash(b);
1929
+ rb_gc_force_recycle(b);
1930
+ return INT2FIX(res);
1931
+ }
1932
+
1933
+ /*
1934
+ * Document-method: length
1935
+ * Document-method: size
1936
+ *
1937
+ * return the size of the file
1938
+ */
1939
+ static VALUE
1940
+ mm_size(a)
1941
+ VALUE a;
1942
+ {
1943
+ mm_ipc *i_mm;
1944
+
1945
+ GetMmap(a, i_mm, 0);
1946
+ return UINT2NUM(i_mm->t->real);
1947
+ }
1948
+
1949
+ /*
1950
+ * call-seq: empty?
1951
+ *
1952
+ * return <em>true</em> if the file is empty
1953
+ */
1954
+ static VALUE
1955
+ mm_empty(a)
1956
+ VALUE a;
1957
+ {
1958
+ mm_ipc *i_mm;
1959
+
1960
+ GetMmap(a, i_mm, 0);
1961
+ if (i_mm->t->real == 0) return Qtrue;
1962
+ return Qfalse;
1963
+ }
1964
+
1965
+ static VALUE
1966
+ mm_protect_bang(t)
1967
+ VALUE *t;
1968
+ {
1969
+ return rb_funcall2(t[0], (ID)t[1], (int)t[2], (VALUE *)t[3]);
1970
+ }
1971
+
1972
+ static VALUE
1973
+ mm_recycle(str)
1974
+ VALUE str;
1975
+ {
1976
+ rb_gc_force_recycle(str);
1977
+ return str;
1978
+ }
1979
+
1980
+ static VALUE
1981
+ mm_i_bang(bang_st)
1982
+ mm_bang *bang_st;
1983
+ {
1984
+ VALUE str, res;
1985
+ mm_ipc *i_mm;
1986
+
1987
+ str = mm_str(bang_st->obj, bang_st->flag);
1988
+ if (bang_st->flag & MM_PROTECT) {
1989
+ VALUE tmp[4];
1990
+ tmp[0] = str;
1991
+ tmp[1] = (VALUE)bang_st->id;
1992
+ tmp[2] = (VALUE)bang_st->argc;
1993
+ tmp[3] = (VALUE)bang_st->argv;
1994
+ res = rb_ensure(mm_protect_bang, (VALUE)tmp, mm_recycle, str);
1995
+ }
1996
+ else {
1997
+ res = rb_funcall2(str, bang_st->id, bang_st->argc, bang_st->argv);
1998
+ rb_gc_force_recycle(str);
1999
+ }
2000
+ if (res != Qnil) {
2001
+ GetMmap(bang_st->obj, i_mm, 0);
2002
+ i_mm->t->real = RSTRING(str)->len;
2003
+ }
2004
+ return res;
2005
+ }
2006
+
2007
+
2008
+ static VALUE
2009
+ mm_bang_i(obj, flag, id, argc, argv)
2010
+ VALUE obj, *argv;
2011
+ int flag, id, argc;
2012
+ {
2013
+ VALUE res;
2014
+ mm_ipc *i_mm;
2015
+ mm_bang bang_st;
2016
+
2017
+ GetMmap(obj, i_mm, 0);
2018
+ if ((flag & MM_CHANGE) && (i_mm->t->flag & MM_FIXED)) {
2019
+ rb_raise(rb_eTypeError, "try to change the size of a fixed map");
2020
+ }
2021
+ bang_st.obj = obj;
2022
+ bang_st.flag = flag;
2023
+ bang_st.id = id;
2024
+ bang_st.argc = argc;
2025
+ bang_st.argv = argv;
2026
+ if (i_mm->t->flag & MM_IPC) {
2027
+ mm_lock(i_mm, Qtrue);
2028
+ res = rb_ensure(mm_i_bang, (VALUE)&bang_st, mm_vunlock, obj);
2029
+ }
2030
+ else {
2031
+ res = mm_i_bang(&bang_st);
2032
+ }
2033
+ if (res == Qnil) return res;
2034
+ return (flag & MM_ORIGIN)?res:obj;
2035
+
2036
+ }
2037
+
2038
+ #if HAVE_RB_STR_MATCH
2039
+
2040
+ /*
2041
+ * call-seq: match(pattern)
2042
+ *
2043
+ * convert <em>pattern</em> to a <em>Regexp</em> and then call
2044
+ * <em>match</em> on <em>self</em>
2045
+ */
2046
+ static VALUE
2047
+ mm_match_m(a, b)
2048
+ VALUE a, b;
2049
+ {
2050
+ return mm_bang_i(a, MM_ORIGIN, rb_intern("match"), 1, &b);
2051
+ }
2052
+
2053
+ #endif
2054
+
2055
+ /*
2056
+ * call-seq: upcase!
2057
+ *
2058
+ * replaces all lowercase characters to downcase characters
2059
+ */
2060
+ static VALUE
2061
+ mm_upcase_bang(a)
2062
+ VALUE a;
2063
+ {
2064
+ return mm_bang_i(a, MM_MODIFY, rb_intern("upcase!"), 0, 0);
2065
+ }
2066
+
2067
+ /*
2068
+ * call-seq: downcase!
2069
+ *
2070
+ * change all uppercase character to lowercase character
2071
+ */
2072
+ static VALUE
2073
+ mm_downcase_bang(a)
2074
+ VALUE a;
2075
+ {
2076
+ return mm_bang_i(a, MM_MODIFY, rb_intern("downcase!"), 0, 0);
2077
+ }
2078
+
2079
+ /*
2080
+ * call-seq: capitalize!
2081
+ *
2082
+ * change the first character to uppercase letter
2083
+ */
2084
+ static VALUE
2085
+ mm_capitalize_bang(a)
2086
+ VALUE a;
2087
+ {
2088
+ return mm_bang_i(a, MM_MODIFY, rb_intern("capitalize!"), 0, 0);
2089
+ }
2090
+
2091
+ /*
2092
+ * call-seq: swapcase!
2093
+ *
2094
+ * replaces all lowercase characters to uppercase characters, and vice-versa
2095
+ */
2096
+ static VALUE
2097
+ mm_swapcase_bang(a)
2098
+ VALUE a;
2099
+ {
2100
+ return mm_bang_i(a, MM_MODIFY, rb_intern("swapcase!"), 0, 0);
2101
+ }
2102
+
2103
+ /*
2104
+ * call-seq: reverse!
2105
+ *
2106
+ * reverse the content of the file
2107
+ */
2108
+ static VALUE
2109
+ mm_reverse_bang(a)
2110
+ VALUE a;
2111
+ {
2112
+ return mm_bang_i(a, MM_MODIFY, rb_intern("reverse!"), 0, 0);
2113
+ }
2114
+
2115
+ /*
2116
+ * call-seq: chop!
2117
+ *
2118
+ * chop off the last character
2119
+ */
2120
+ static VALUE
2121
+ mm_chop_bang(a)
2122
+ VALUE a;
2123
+ {
2124
+ return mm_bang_i(a, MM_CHANGE, rb_intern("chop!"), 0, 0);
2125
+ }
2126
+
2127
+ /*
2128
+ * call-seq: chomp!(rs = $/)
2129
+ *
2130
+ * chop off the line ending character, specified by <em>rs</em>
2131
+ */
2132
+ static VALUE
2133
+ mm_chomp_bang(argc, argv, obj)
2134
+ int argc;
2135
+ VALUE *argv, obj;
2136
+ {
2137
+ return mm_bang_i(obj, MM_CHANGE | MM_PROTECT, rb_intern("chomp!"), argc, argv);
2138
+ }
2139
+
2140
+ /*
2141
+ * call-seq: delete!(str)
2142
+ *
2143
+ * delete every characters included in <em>str</em>
2144
+ */
2145
+ static VALUE
2146
+ mm_delete_bang(argc, argv, obj)
2147
+ int argc;
2148
+ VALUE *argv, obj;
2149
+ {
2150
+ return mm_bang_i(obj, MM_CHANGE | MM_PROTECT, rb_intern("delete!"), argc, argv);
2151
+ }
2152
+
2153
+ /*
2154
+ * squeeze!(str)
2155
+ *
2156
+ * squeezes sequences of the same characters which is included in <em>str</em>
2157
+ */
2158
+ static VALUE
2159
+ mm_squeeze_bang(argc, argv, obj)
2160
+ int argc;
2161
+ VALUE *argv, obj;
2162
+ {
2163
+ return mm_bang_i(obj, MM_CHANGE | MM_PROTECT, rb_intern("squeeze!"), argc, argv);
2164
+ }
2165
+
2166
+ /*
2167
+ * call-seq: tr!(search, replace)
2168
+ *
2169
+ * translate the character from <em>search</em> to <em>replace</em>
2170
+ */
2171
+ static VALUE
2172
+ mm_tr_bang(obj, a, b)
2173
+ VALUE obj, a, b;
2174
+ {
2175
+ VALUE tmp[2];
2176
+ tmp[0] = a;
2177
+ tmp[1] = b;
2178
+ return mm_bang_i(obj, MM_MODIFY | MM_PROTECT, rb_intern("tr!"), 2, tmp);
2179
+ }
2180
+
2181
+ /*
2182
+ * call-seq: tr_s!(search, replace)
2183
+ *
2184
+ * translate the character from <em>search</em> to <em>replace</em>, then
2185
+ * squeeze sequence of the same characters
2186
+ */
2187
+ static VALUE
2188
+ mm_tr_s_bang(obj, a, b)
2189
+ VALUE obj, a, b;
2190
+ {
2191
+ VALUE tmp[2];
2192
+ tmp[0] = a;
2193
+ tmp[1] = b;
2194
+ return mm_bang_i(obj, MM_CHANGE | MM_PROTECT, rb_intern("tr_s!"), 2, tmp);
2195
+ }
2196
+
2197
+ /*
2198
+ * call-seq: crypt
2199
+ *
2200
+ * crypt with <em>salt</em>
2201
+ */
2202
+ static VALUE
2203
+ mm_crypt(a, b)
2204
+ VALUE a, b;
2205
+ {
2206
+ return mm_bang_i(a, MM_ORIGIN, rb_intern("crypt"), 1, &b);
2207
+ }
2208
+
2209
+ /*
2210
+ * call-seq: include?(other)
2211
+ *
2212
+ * return <em>true</em> if <em>other</em> is found
2213
+ */
2214
+ static VALUE
2215
+ mm_include(a, b)
2216
+ VALUE a, b;
2217
+ {
2218
+ return mm_bang_i(a, MM_ORIGIN, rb_intern("include?"), 1, &b);
2219
+ }
2220
+
2221
+ /*
2222
+ * call-seq: index
2223
+ *
2224
+ * return the index of <em>substr</em>
2225
+ */
2226
+ static VALUE
2227
+ mm_index(argc, argv, obj)
2228
+ int argc;
2229
+ VALUE *argv, obj;
2230
+ {
2231
+ return mm_bang_i(obj, MM_ORIGIN, rb_intern("index"), argc, argv);
2232
+ }
2233
+
2234
+ /*
2235
+ * call-seq: rindex(sibstr, pos = nil)
2236
+ *
2237
+ * return the index of the last occurrence of <em>substr</em>
2238
+ */
2239
+ static VALUE
2240
+ mm_rindex(argc, argv, obj)
2241
+ int argc;
2242
+ VALUE *argv, obj;
2243
+ {
2244
+ return mm_bang_i(obj, MM_ORIGIN, rb_intern("rindex"), argc, argv);
2245
+ }
2246
+
2247
+ /*
2248
+ * Document-method: []
2249
+ * Document-method: slice
2250
+ *
2251
+ * call-seq: [](args)
2252
+ *
2253
+ * Element reference - with the following syntax:
2254
+ *
2255
+ * self[nth]
2256
+ *
2257
+ * retrieve the <em>nth</em> character
2258
+ *
2259
+ * self[start..last]
2260
+ *
2261
+ * return a substring from <em>start</em> to <em>last</em>
2262
+ *
2263
+ * self[start, length]
2264
+ *
2265
+ * return a substring of <em>lenght</em> characters from <em>start</em>
2266
+ */
2267
+ static VALUE
2268
+ mm_aref_m(argc, argv, obj)
2269
+ int argc;
2270
+ VALUE *argv, obj;
2271
+ {
2272
+ return mm_bang_i(obj, MM_ORIGIN, rb_intern("[]"), argc, argv);
2273
+ }
2274
+
2275
+ /*
2276
+ * call-seq: sum(bits = 16)
2277
+ *
2278
+ * return a checksum
2279
+ */
2280
+ static VALUE
2281
+ mm_sum(argc, argv, obj)
2282
+ int argc;
2283
+ VALUE *argv, obj;
2284
+ {
2285
+ return mm_bang_i(obj, MM_ORIGIN, rb_intern("sum"), argc, argv);
2286
+ }
2287
+
2288
+ /*
2289
+ * call-seq: split(sep, limit = 0)
2290
+ *
2291
+ * splits into a list of strings and return this array
2292
+ */
2293
+ static VALUE
2294
+ mm_split(argc, argv, obj)
2295
+ int argc;
2296
+ VALUE *argv, obj;
2297
+ {
2298
+ return mm_bang_i(obj, MM_ORIGIN, rb_intern("split"), argc, argv);
2299
+ }
2300
+
2301
+ /*
2302
+ * call-seq: count(o1, *args)
2303
+ *
2304
+ * each parameter defines a set of character to count
2305
+ */
2306
+ static VALUE
2307
+ mm_count(argc, argv, obj)
2308
+ int argc;
2309
+ VALUE *argv, obj;
2310
+ {
2311
+ return mm_bang_i(obj, MM_ORIGIN, rb_intern("count"), argc, argv);
2312
+ }
2313
+
2314
+ static VALUE
2315
+ mm_internal_each(tmp)
2316
+ VALUE *tmp;
2317
+ {
2318
+ return rb_funcall2(tmp[0], (ID)tmp[1], (int)tmp[2], (VALUE *)tmp[3]);
2319
+ }
2320
+
2321
+ /*
2322
+ * call-seq: scan(pattern, &block)
2323
+ *
2324
+ * return an array of all occurence matched by <em>pattern</em>
2325
+ */
2326
+ static VALUE
2327
+ mm_scan(obj, a)
2328
+ VALUE obj, a;
2329
+ {
2330
+ VALUE tmp[4];
2331
+
2332
+ if (!rb_block_given_p()) {
2333
+ return rb_funcall(mm_str(obj, MM_ORIGIN), rb_intern("scan"), 1, a);
2334
+ }
2335
+ tmp[0] = mm_str(obj, MM_ORIGIN);
2336
+ tmp[1] = (VALUE)rb_intern("scan");
2337
+ tmp[2] = (VALUE)1;
2338
+ tmp[3] = (VALUE)&a;
2339
+ rb_iterate(mm_internal_each, (VALUE)tmp, rb_yield, 0);
2340
+ return obj;
2341
+ }
2342
+
2343
+ /*
2344
+ * Document-method: each
2345
+ * Document-method: each_line
2346
+ *
2347
+ * call-seq:
2348
+ * each(rs = $/, &block)
2349
+ *
2350
+ * iterate on each line
2351
+ */
2352
+ static VALUE
2353
+ mm_each_line(argc, argv, obj)
2354
+ int argc;
2355
+ VALUE obj, *argv;
2356
+ {
2357
+ VALUE tmp[4];
2358
+
2359
+ tmp[0] = mm_str(obj, MM_ORIGIN);
2360
+ tmp[1] = (VALUE)rb_intern("each_line");
2361
+ tmp[2] = (VALUE)argc;
2362
+ tmp[3] = (VALUE)argv;
2363
+ rb_iterate(mm_internal_each, (VALUE)tmp, rb_yield, 0);
2364
+ return obj;
2365
+ }
2366
+
2367
+ /*
2368
+ * call-seq: each_byte(&block)
2369
+ *
2370
+ * iterate on each byte
2371
+ */
2372
+ static VALUE
2373
+ mm_each_byte(argc, argv, obj)
2374
+ int argc;
2375
+ VALUE obj, *argv;
2376
+ {
2377
+ VALUE tmp[4];
2378
+
2379
+ tmp[0] = mm_str(obj, MM_ORIGIN);
2380
+ tmp[1] = (VALUE)rb_intern("each_byte");
2381
+ tmp[2] = (VALUE)argc;
2382
+ tmp[3] = (VALUE)argv;
2383
+ rb_iterate(mm_internal_each, (VALUE)tmp, rb_yield, 0);
2384
+ return obj;
2385
+ }
2386
+
2387
+ /*
2388
+ * Document-method: lockall
2389
+ * Document-method: mlockall
2390
+ *
2391
+ * call-seq:
2392
+ * lockall(flag)
2393
+ *
2394
+ * disable paging of all pages mapped. <em>flag</em> can be
2395
+ * <em>Mmap::MCL_CURRENT</em> or <em>Mmap::MCL_FUTURE</em>
2396
+ */
2397
+ static VALUE
2398
+ mm_mlockall(obj, flag)
2399
+ VALUE obj, flag;
2400
+ {
2401
+ if (mlockall(NUM2INT(flag)) == -1) {
2402
+ rb_raise(rb_eArgError, "mlockall(%d)", errno);
2403
+ }
2404
+ return Qnil;
2405
+ }
2406
+
2407
+ /*
2408
+ * Document-method: unlockall
2409
+ * Document-method: munlockall
2410
+ *
2411
+ * call-seq: unlockall
2412
+ *
2413
+ * reenable paging
2414
+ */
2415
+ static VALUE
2416
+ mm_munlockall(obj)
2417
+ VALUE obj;
2418
+ {
2419
+ if (munlockall() == -1) {
2420
+ rb_raise(rb_eArgError, "munlockall(%d)", errno);
2421
+ }
2422
+ return Qnil;
2423
+ }
2424
+
2425
+ /*
2426
+ * Document-method: lock
2427
+ * Document-method: mlock
2428
+ *
2429
+ * call-seq: mlock
2430
+ *
2431
+ * disable paging
2432
+ */
2433
+ static VALUE
2434
+ mm_mlock(obj)
2435
+ VALUE obj;
2436
+ {
2437
+ mm_ipc *i_mm;
2438
+
2439
+ Data_Get_Struct(obj, mm_ipc, i_mm);
2440
+ if (i_mm->t->flag & MM_LOCK) {
2441
+ return obj;
2442
+ }
2443
+ if (i_mm->t->flag & MM_ANON) {
2444
+ rb_raise(rb_eArgError, "mlock(anonymous)");
2445
+ }
2446
+ if (mlock(i_mm->t->addr, i_mm->t->len) == -1) {
2447
+ rb_raise(rb_eArgError, "mlock(%d)", errno);
2448
+ }
2449
+ i_mm->t->flag |= MM_LOCK;
2450
+ return obj;
2451
+ }
2452
+
2453
+ /*
2454
+ * Document-method: munlock
2455
+ * Document-method: unlock
2456
+ *
2457
+ * call-seq: unlock
2458
+ *
2459
+ * reenable paging
2460
+ */
2461
+ static VALUE
2462
+ mm_munlock(obj)
2463
+ VALUE obj;
2464
+ {
2465
+ mm_ipc *i_mm;
2466
+
2467
+ Data_Get_Struct(obj, mm_ipc, i_mm);
2468
+ if (!(i_mm->t->flag & MM_LOCK)) {
2469
+ return obj;
2470
+ }
2471
+ if (munlock(i_mm->t->addr, i_mm->t->len) == -1) {
2472
+ rb_raise(rb_eArgError, "munlock(%d)", errno);
2473
+ }
2474
+ i_mm->t->flag &= ~MM_LOCK;
2475
+ return obj;
2476
+ }
2477
+
2478
+ void
2479
+ Init_mmap()
2480
+ {
2481
+ if (rb_const_defined_at(rb_cObject, rb_intern("Mmap"))) {
2482
+ rb_raise(rb_eNameError, "class already defined");
2483
+ }
2484
+ mm_cMap = rb_define_class("Mmap", rb_cObject);
2485
+ rb_define_const(mm_cMap, "MS_SYNC", INT2FIX(MS_SYNC));
2486
+ rb_define_const(mm_cMap, "MS_ASYNC", INT2FIX(MS_ASYNC));
2487
+ rb_define_const(mm_cMap, "MS_INVALIDATE", INT2FIX(MS_INVALIDATE));
2488
+ rb_define_const(mm_cMap, "PROT_READ", INT2FIX(PROT_READ));
2489
+ rb_define_const(mm_cMap, "PROT_WRITE", INT2FIX(PROT_WRITE));
2490
+ rb_define_const(mm_cMap, "PROT_EXEC", INT2FIX(PROT_EXEC));
2491
+ rb_define_const(mm_cMap, "PROT_NONE", INT2FIX(PROT_NONE));
2492
+ rb_define_const(mm_cMap, "MAP_SHARED", INT2FIX(MAP_SHARED));
2493
+ rb_define_const(mm_cMap, "MAP_PRIVATE", INT2FIX(MAP_PRIVATE));
2494
+ #ifdef MADV_NORMAL
2495
+ rb_define_const(mm_cMap, "MADV_NORMAL", INT2FIX(MADV_NORMAL));
2496
+ rb_define_const(mm_cMap, "MADV_RANDOM", INT2FIX(MADV_RANDOM));
2497
+ rb_define_const(mm_cMap, "MADV_SEQUENTIAL", INT2FIX(MADV_SEQUENTIAL));
2498
+ rb_define_const(mm_cMap, "MADV_WILLNEED", INT2FIX(MADV_WILLNEED));
2499
+ rb_define_const(mm_cMap, "MADV_DONTNEED", INT2FIX(MADV_DONTNEED));
2500
+ #endif
2501
+ #ifdef MAP_DENYWRITE
2502
+ rb_define_const(mm_cMap, "MAP_DENYWRITE", INT2FIX(MAP_DENYWRITE));
2503
+ #endif
2504
+ #ifdef MAP_EXECUTABLE
2505
+ rb_define_const(mm_cMap, "MAP_EXECUTABLE", INT2FIX(MAP_EXECUTABLE));
2506
+ #endif
2507
+ #ifdef MAP_NORESERVE
2508
+ rb_define_const(mm_cMap, "MAP_NORESERVE", INT2FIX(MAP_NORESERVE));
2509
+ #endif
2510
+ #ifdef MAP_LOCKED
2511
+ rb_define_const(mm_cMap, "MAP_LOCKED", INT2FIX(MAP_LOCKED));
2512
+ #endif
2513
+ #ifdef MAP_GROWSDOWN
2514
+ rb_define_const(mm_cMap, "MAP_GROWSDOWN", INT2FIX(MAP_GROWSDOWN));
2515
+ #endif
2516
+ #ifdef MAP_ANON
2517
+ rb_define_const(mm_cMap, "MAP_ANON", INT2FIX(MAP_ANON));
2518
+ #endif
2519
+ #ifdef MAP_ANONYMOUS
2520
+ rb_define_const(mm_cMap, "MAP_ANONYMOUS", INT2FIX(MAP_ANONYMOUS));
2521
+ #endif
2522
+ #ifdef MAP_NOSYNC
2523
+ rb_define_const(mm_cMap, "MAP_NOSYNC", INT2FIX(MAP_NOSYNC));
2524
+ #endif
2525
+ #ifdef MCL_CURRENT
2526
+ rb_define_const(mm_cMap, "MCL_CURRENT", INT2FIX(MCL_CURRENT));
2527
+ rb_define_const(mm_cMap, "MCL_FUTURE", INT2FIX(MCL_FUTURE));
2528
+ #endif
2529
+
2530
+ rb_define_alloc_func(mm_cMap, mm_s_alloc);
2531
+ rb_define_singleton_method(mm_cMap, "new", mm_s_new, -1);
2532
+ rb_define_singleton_method(mm_cMap, "mlockall", mm_mlockall, 1);
2533
+ rb_define_singleton_method(mm_cMap, "lockall", mm_mlockall, 1);
2534
+ rb_define_singleton_method(mm_cMap, "munlockall", mm_munlockall, 0);
2535
+ rb_define_singleton_method(mm_cMap, "unlockall", mm_munlockall, 0);
2536
+
2537
+ rb_define_method(mm_cMap, "initialize", mm_init, -1);
2538
+
2539
+ rb_define_method(mm_cMap, "unmap", mm_unmap, 0);
2540
+ rb_define_method(mm_cMap, "munmap", mm_unmap, 0);
2541
+ rb_define_method(mm_cMap, "msync", mm_msync, -1);
2542
+ rb_define_method(mm_cMap, "sync", mm_msync, -1);
2543
+ rb_define_method(mm_cMap, "flush", mm_msync, -1);
2544
+ rb_define_method(mm_cMap, "mprotect", mm_mprotect, 1);
2545
+ rb_define_method(mm_cMap, "protect", mm_mprotect, 1);
2546
+ #ifdef MADV_NORMAL
2547
+ rb_define_method(mm_cMap, "madvise", mm_madvise, 1);
2548
+ rb_define_method(mm_cMap, "advise", mm_madvise, 1);
2549
+ #endif
2550
+ rb_define_method(mm_cMap, "mlock", mm_mlock, 0);
2551
+ rb_define_method(mm_cMap, "lock", mm_mlock, 0);
2552
+ rb_define_method(mm_cMap, "munlock", mm_munlock, 0);
2553
+ rb_define_method(mm_cMap, "unlock", mm_munlock, 0);
2554
+
2555
+ rb_define_method(mm_cMap, "extend", mm_extend, 1);
2556
+ rb_define_method(mm_cMap, "freeze", mm_freeze, 0);
2557
+ rb_define_method(mm_cMap, "<=>", mm_cmp, 1);
2558
+ rb_define_method(mm_cMap, "==", mm_equal, 1);
2559
+ rb_define_method(mm_cMap, "===", mm_equal, 1);
2560
+ rb_define_method(mm_cMap, "eql?", mm_eql, 1);
2561
+ rb_define_method(mm_cMap, "hash", mm_hash, 0);
2562
+ #if HAVE_RB_STR_CASECMP
2563
+ rb_define_method(mm_cMap, "casecmp", mm_casecmp, 1);
2564
+ #endif
2565
+ rb_define_method(mm_cMap, "[]", mm_aref_m, -1);
2566
+ rb_define_method(mm_cMap, "[]=", mm_aset_m, -1);
2567
+ #if HAVE_RB_STR_INSERT
2568
+ rb_define_method(mm_cMap, "insert", mm_insert, 2);
2569
+ #endif
2570
+ rb_define_method(mm_cMap, "length", mm_size, 0);
2571
+ rb_define_method(mm_cMap, "size", mm_size, 0);
2572
+ rb_define_method(mm_cMap, "empty?", mm_empty, 0);
2573
+ rb_define_method(mm_cMap, "=~", mm_match, 1);
2574
+ #if HAVE_RB_STR_MATCH
2575
+ rb_define_method(mm_cMap, "match", mm_match_m, 1);
2576
+ #endif
2577
+ rb_define_method(mm_cMap, "index", mm_index, -1);
2578
+ rb_define_method(mm_cMap, "rindex", mm_rindex, -1);
2579
+
2580
+ rb_define_method(mm_cMap, "to_str", mm_to_str, 0);
2581
+
2582
+ rb_define_method(mm_cMap, "upcase!", mm_upcase_bang, 0);
2583
+ rb_define_method(mm_cMap, "downcase!", mm_downcase_bang, 0);
2584
+ rb_define_method(mm_cMap, "capitalize!", mm_capitalize_bang, 0);
2585
+ rb_define_method(mm_cMap, "swapcase!", mm_swapcase_bang, 0);
2586
+
2587
+ rb_define_method(mm_cMap, "split", mm_split, -1);
2588
+ rb_define_method(mm_cMap, "reverse!", mm_reverse_bang, 0);
2589
+ rb_define_method(mm_cMap, "concat", mm_concat, 1);
2590
+ rb_define_method(mm_cMap, "<<", mm_concat, 1);
2591
+ rb_define_method(mm_cMap, "crypt", mm_crypt, 1);
2592
+
2593
+ rb_define_method(mm_cMap, "include?", mm_include, 1);
2594
+
2595
+ rb_define_method(mm_cMap, "scan", mm_scan, 1);
2596
+
2597
+ rb_define_method(mm_cMap, "sub!", mm_sub_bang, -1);
2598
+ rb_define_method(mm_cMap, "gsub!", mm_gsub_bang, -1);
2599
+ rb_define_method(mm_cMap, "strip!", mm_strip_bang, 0);
2600
+ #if HAVE_RB_STR_LSTRIP
2601
+ rb_define_method(mm_cMap, "lstrip!", mm_lstrip_bang, 0);
2602
+ rb_define_method(mm_cMap, "rstrip!", mm_rstrip_bang, 0);
2603
+ #endif
2604
+ rb_define_method(mm_cMap, "chop!", mm_chop_bang, 0);
2605
+ rb_define_method(mm_cMap, "chomp!", mm_chomp_bang, -1);
2606
+
2607
+ rb_define_method(mm_cMap, "count", mm_count, -1);
2608
+
2609
+ rb_define_method(mm_cMap, "tr!", mm_tr_bang, 2);
2610
+ rb_define_method(mm_cMap, "tr_s!", mm_tr_s_bang, 2);
2611
+ rb_define_method(mm_cMap, "delete!", mm_delete_bang, -1);
2612
+ rb_define_method(mm_cMap, "squeeze!", mm_squeeze_bang, -1);
2613
+
2614
+ rb_define_method(mm_cMap, "each_line", mm_each_line, -1);
2615
+ rb_define_method(mm_cMap, "each", mm_each_line, -1);
2616
+ rb_define_method(mm_cMap, "each_byte", mm_each_byte, -1);
2617
+
2618
+ rb_define_method(mm_cMap, "sum", mm_sum, -1);
2619
+
2620
+ rb_define_method(mm_cMap, "slice", mm_aref_m, -1);
2621
+ rb_define_method(mm_cMap, "slice!", mm_slice_bang, -1);
2622
+ rb_define_method(mm_cMap, "semlock", mm_semlock, -1);
2623
+ rb_define_method(mm_cMap, "ipc_key", mm_ipc_key, 0);
2624
+ }