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