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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/README.md +92 -0
- data/ext/mmap_ruby/extconf.rb +10 -0
- data/ext/mmap_ruby/mmap +0 -0
- data/ext/mmap_ruby/mmap_ruby.c +2804 -0
- data/ext/mmap_ruby/mmap_ruby.h +21 -0
- data/lib/mmap-ruby/mmap.rb +49 -0
- data/lib/mmap-ruby/mmap_ruby.bundle +0 -0
- data/lib/mmap-ruby/version.rb +5 -0
- data/lib/mmap-ruby.rb +6 -0
- data/mmap-ruby.gemspec +23 -0
- data/tmp/arm64-darwin25/stage/CHANGELOG.md +5 -0
- data/tmp/arm64-darwin25/stage/README.md +92 -0
- data/tmp/arm64-darwin25/stage/mmap-ruby.gemspec +23 -0
- metadata +61 -0
@@ -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
|
+
}
|