mmap-ruby 0.1.0

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