mmap2 2.2.6

Sign up to get free protection for your applications and to get access to all the features.
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
+ }