rb-wartslib 0.9.10

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,52 @@
1
+ /*
2
+ ** Ruby bindings to the functions in libscamperfile.a that are needed to
3
+ ** sort scamper trace files (a la sc_sorter).
4
+ **
5
+ ** --------------------------------------------------------------------------
6
+ ** Copyright (C) 2007 The Regents of the University of California.
7
+ **
8
+ ** This program is free software; you can redistribute it and/or modify
9
+ ** it under the terms of the GNU General Public License as published by
10
+ ** the Free Software Foundation; either version 2 of the License, or
11
+ ** (at your option) any later version.
12
+ **
13
+ ** This program is distributed in the hope that it will be useful,
14
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ ** GNU General Public License for more details.
17
+ **
18
+ ** You should have received a copy of the GNU General Public License
19
+ ** along with this program; if not, write to the Free Software
20
+ ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
+ **
22
+ ** $Id: scext.c,v 1.18 2007/11/29 01:51:54 youngh Exp $
23
+ **/
24
+
25
+ #include "ruby.h"
26
+
27
+ #if defined(__HAVE_STDINT_H__)
28
+ #include <stdint.h>
29
+ #endif
30
+
31
+ #include "scamper.h"
32
+
33
+ #include "scaddr.h"
34
+ #include "sclist.h"
35
+ #include "sctrace.h"
36
+ #include "scfile.h"
37
+
38
+ VALUE mWarts;
39
+
40
+ void Init_wartslibext(void)
41
+ {
42
+ mWarts = rb_define_module("Warts");
43
+
44
+ rb_define_const(mWarts, "WARTS_LIB_VERSION", rb_str_new2("0.9.10"));
45
+ rb_define_const(mWarts, "SCAMPER_VERSION", rb_str_new2(SCAMPER_VERSION));
46
+
47
+ Init_scaddr();
48
+ Init_sclist();
49
+ Init_sccycle();
50
+ Init_sctrace();
51
+ Init_scfile();
52
+ }
@@ -0,0 +1,688 @@
1
+ /*
2
+ ** Ruby bindings to scamper file operations in scamper_file.c.
3
+ **
4
+ ** --------------------------------------------------------------------------
5
+ ** Copyright (C) 2007 The Regents of the University of California.
6
+ **
7
+ ** This program is free software; you can redistribute it and/or modify
8
+ ** it under the terms of the GNU General Public License as published by
9
+ ** the Free Software Foundation; either version 2 of the License, or
10
+ ** (at your option) any later version.
11
+ **
12
+ ** This program is distributed in the hope that it will be useful,
13
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ ** GNU General Public License for more details.
16
+ **
17
+ ** You should have received a copy of the GNU General Public License
18
+ ** along with this program; if not, write to the Free Software
19
+ ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
+ **
21
+ ** $Id: scfile.c,v 1.30 2007/11/29 01:42:07 youngh Exp $
22
+ **/
23
+
24
+ #include <unistd.h>
25
+ #include <string.h>
26
+ #include <strings.h>
27
+
28
+ #include "ruby.h"
29
+
30
+ #include "scfile.h"
31
+ #include "scaddr.h"
32
+
33
+ #if defined(__HAVE_STDINT_H__)
34
+ #include <stdint.h>
35
+ #endif
36
+
37
+ #include "scamper_list.h"
38
+ #include "scamper_addr.h"
39
+ #include "scamper_trace.h"
40
+ #include "scamper_file.h"
41
+
42
+ extern VALUE mWarts;
43
+ extern VALUE cTrace;
44
+ extern VALUE cCycle;
45
+
46
+ static VALUE cFile;
47
+ static ID iv_readable, iv_filters, iv_filters_changed;
48
+ static ID meth_write_to;
49
+ static ID meth_kind_of;
50
+ static ID meth_fileno;
51
+
52
+ typedef struct {
53
+ scamper_file_t *file;
54
+ scamper_file_filter_t *filters;
55
+ } file_data_t;
56
+
57
+ typedef struct {
58
+ const char* name;
59
+ int value;
60
+ } sctype_info_t;
61
+
62
+ sctype_info_t all_sctypes[] = {
63
+ { "LIST", SCAMPER_FILE_OBJ_LIST },
64
+ { "CYCLE_START", SCAMPER_FILE_OBJ_CYCLE_START },
65
+ { "CYCLE_DEF", SCAMPER_FILE_OBJ_CYCLE_DEF },
66
+ { "CYCLE_STOP", SCAMPER_FILE_OBJ_CYCLE_STOP },
67
+ { "ADDR", SCAMPER_FILE_OBJ_ADDR },
68
+ { "TRACE", SCAMPER_FILE_OBJ_TRACE },
69
+ { "PING", SCAMPER_FILE_OBJ_PING }
70
+ };
71
+
72
+ size_t num_sctypes = sizeof(all_sctypes) / sizeof(sctype_info_t);
73
+
74
+ #define MIN_SCTYPE_VALUE SCAMPER_FILE_OBJ_LIST
75
+ #define MAX_SCTYPE_VALUE SCAMPER_FILE_OBJ_PING
76
+
77
+ #define CHECK_WRITABLE(self) \
78
+ if (RTEST(rb_ivar_get(self, iv_readable))) { \
79
+ rb_fatal("attempt to write to a file opened for reading"); \
80
+ }
81
+
82
+ #define CHECK_READABLE(self) \
83
+ if (!RTEST(rb_ivar_get(self, iv_readable))) { \
84
+ rb_fatal("attempt to read from a file opened for writing"); \
85
+ }
86
+
87
+
88
+ /***************************************************************************/
89
+
90
+ static void sf_free(void *arg)
91
+ {
92
+ file_data_t *data = (file_data_t *)arg;
93
+ if (data) {
94
+ if (data->file) {
95
+ scamper_file_close(data->file);
96
+ data->file = NULL;
97
+ }
98
+ if (data->filters) {
99
+ scamper_file_filter_free(data->filters);
100
+ data->filters = NULL;
101
+ }
102
+ free(data);
103
+ }
104
+ }
105
+
106
+ static VALUE scfile_alloc(VALUE klass)
107
+ {
108
+ return Data_Wrap_Struct(klass, 0, (RUBY_DATA_FUNC)sf_free, 0);
109
+ }
110
+
111
+
112
+ /*
113
+ ** Opens either a path or a fd, depending on the type of the first argument.
114
+ ** A file descriptor can be given as either a FIXNUM or as an instance of
115
+ ** IO.
116
+ **
117
+ ** NOTE: It is the responsibility of the caller to (eventually) close any
118
+ ** passed in file descriptor. See comments below for the reason.
119
+ */
120
+ static VALUE scfile_init(int argc, VALUE *argv, VALUE self)
121
+ {
122
+ VALUE path_or_fd, mode, type;
123
+ VALUE path = Qnil;
124
+ int fd = -1, fd_dup = -1;
125
+ char mode_char = 'r';
126
+ char *type_str = NULL;
127
+ scamper_file_t *file = NULL;
128
+ file_data_t *data = NULL;
129
+
130
+ rb_scan_args(argc, argv, "12", &path_or_fd, &mode, &type);
131
+ if (NIL_P(path_or_fd)) {
132
+ rb_raise(rb_eArgError, "missing path or fd");
133
+ }
134
+
135
+ if (TYPE(path_or_fd) == T_FIXNUM || TYPE(path_or_fd) == T_BIGNUM) {
136
+ fd = NUM2INT(path_or_fd);
137
+ }
138
+ else if (RTEST(rb_funcall(path_or_fd, meth_kind_of, 1, rb_cIO))) {
139
+ VALUE fileno = rb_funcall(path_or_fd, meth_fileno, 0);
140
+ fd = FIX2INT(fileno);
141
+ }
142
+ else {
143
+ path = path_or_fd;
144
+ SafeStringValue(path);
145
+ }
146
+
147
+ if (NIL_P(mode)) {
148
+ mode_char = 'r';
149
+ }
150
+ else {
151
+ /* Since scamper_file_open() doesn't return any distinguishable error for
152
+ an invalid mode, we check for validity here. */
153
+ const char *mode_str;
154
+
155
+ StringValue(mode);
156
+ mode_str = RSTRING(mode)->ptr;
157
+ if (strlen(mode_str) != 1 || !index("rwa", mode_str[0])) {
158
+ rb_raise(rb_eArgError, "invalid open mode");
159
+ }
160
+ mode_char = mode_str[0];
161
+ }
162
+
163
+ rb_ivar_set(self, iv_readable, (mode_char == 'r' ? Qtrue : Qfalse));
164
+
165
+ if (NIL_P(type)) {
166
+ if (fd >= 0) {
167
+ type_str = "warts";
168
+ }
169
+ else {
170
+ if (mode_char == 'w' || mode_char == 'a') {
171
+ type_str = "warts";
172
+ }
173
+ /* else let scamper_file_open do file type detection */
174
+ }
175
+ }
176
+ else {
177
+ StringValue(type);
178
+ type_str = RSTRING(type)->ptr;
179
+
180
+ /* Since scamper_file_open() doesn't return any distinguishable error for
181
+ an invalid type, we check for validity here. */
182
+ if (strcmp(type_str, "warts") && strcmp(type_str, "arts")
183
+ && strcmp(type_str, "traceroute")) {
184
+ rb_raise(rb_eArgError, "invalid file type");
185
+ }
186
+ }
187
+
188
+ if (type_str) {
189
+ if ((mode_char == 'w' || mode_char == 'a') && strcmp(type_str, "arts")==0){
190
+ rb_raise(rb_eArgError,"writing or appending to arts files not supported");
191
+ }
192
+
193
+ if (mode_char == 'r' && strcmp(type_str, "traceroute") == 0) {
194
+ rb_raise(rb_eArgError, "reading from traceroute files not supported");
195
+ }
196
+ }
197
+
198
+ data = ALLOC(file_data_t);
199
+ data->file = NULL;
200
+ data->filters = NULL;
201
+ DATA_PTR(self) = data;
202
+
203
+ /*
204
+ ** NOTE: We must be careful when calling scamper_file_openfd(). We
205
+ ** should NOT simply pass in the file descriptor supplied to
206
+ ** scfile_init because the policy of scamper_file_openfd is to
207
+ ** take ownership of the passed-in file descriptor. This means
208
+ ** that, eventually, scamper_file_close closes the file
209
+ ** descriptor. Normally, this "takes-ownership-of-argument"
210
+ ** policy is what you want, but when interfacing the scamper warts
211
+ ** library to Ruby, this policy can cause problems.
212
+ **
213
+ ** An open file in Ruby is more than simply a file
214
+ ** descriptor--there's an allocated object associated with the
215
+ ** file descriptor. Hence, we need to free the object in addition
216
+ ** to closing the file descriptor when closing an open file in
217
+ ** Ruby. So it causes problems when scamper_file_close does half
218
+ ** of this work (by closing the file descriptor) without getting
219
+ ** the Ruby object involved. This results in close() being called
220
+ ** twice on the file descriptor. The first time, the call closes
221
+ ** the actual file; the second time, it closes any unreleated open
222
+ ** file that happens to be re-using the same file descriptor
223
+ ** number (which can be particularly insidious if the extra
224
+ ** close() is delayed till the next garbage collection).
225
+ **
226
+ ** When piping in the output of 'gzip -dc' (in order to
227
+ ** transparently read a compressed warts file), simply closing the
228
+ ** file descriptor isn't sufficient to free up the resource. At
229
+ ** some point after closing the file descriptor, we have to call
230
+ ** waitpid(). Thus, in this case, the takes-ownership policy of
231
+ ** scamper_file_openfd is problematic--the Ruby object needs to
232
+ ** do the resource deallocation itself.
233
+ **
234
+ ** Fortunately, there's an easy solution to the mismatch. We
235
+ ** simply dup the file descriptor and pass the dup to
236
+ ** scamper_file_openfd (and let it take ownership and do what it
237
+ ** will of it).
238
+ */
239
+ if (NIL_P(path)) {
240
+ if ((fd_dup = dup(fd)) < 0) {
241
+ rb_raise(rb_eRuntimeError, "couldn't duplicate file descriptor");
242
+ }
243
+ file = scamper_file_openfd(fd_dup, NULL, mode_char, type_str);
244
+ }
245
+ else {
246
+ file = scamper_file_open(RSTRING(path)->ptr, mode_char, type_str);
247
+ }
248
+
249
+ if (file) {
250
+ data->file = file;
251
+ return self;
252
+ }
253
+ else {
254
+ if (fd_dup >= 0) {
255
+ close(fd_dup);
256
+ }
257
+ return Qnil;
258
+ }
259
+ }
260
+
261
+
262
+ static VALUE scfile_type(VALUE self)
263
+ {
264
+ file_data_t *data = NULL;
265
+
266
+ Data_Get_Struct(self, file_data_t, data);
267
+ if (data->file) {
268
+ char buf [128];
269
+ return rb_str_new2(scamper_file_type_tostr(data->file, buf, 128));
270
+ }
271
+ return Qnil;
272
+ }
273
+
274
+
275
+ static VALUE scfile_path(VALUE self)
276
+ {
277
+ file_data_t *data = NULL;
278
+
279
+ Data_Get_Struct(self, file_data_t, data);
280
+ if (data->file) {
281
+ return rb_str_new2(scamper_file_getfilename(data->file));
282
+ }
283
+ return Qnil;
284
+ }
285
+
286
+
287
+ static VALUE scfile_close(VALUE self)
288
+ {
289
+ file_data_t *data = NULL;
290
+
291
+ Data_Get_Struct(self, file_data_t, data);
292
+
293
+ if (data->file) {
294
+ scamper_file_close(data->file);
295
+ data->file = NULL;
296
+ }
297
+
298
+ return self;
299
+ }
300
+
301
+
302
+ static VALUE scfile_closed(VALUE self)
303
+ {
304
+ file_data_t *data = NULL;
305
+
306
+ Data_Get_Struct(self, file_data_t, data);
307
+
308
+ return (data->file ? Qfalse : Qtrue);
309
+ }
310
+
311
+
312
+ static VALUE scfile_s_open(int argc, VALUE *argv, VALUE klass)
313
+ {
314
+ VALUE obj = Data_Wrap_Struct(klass, 0, sf_free, 0);
315
+
316
+ if (NIL_P(scfile_init(argc, argv, obj))) {
317
+ return Qnil;
318
+ }
319
+
320
+ return (rb_block_given_p() ? rb_ensure(rb_yield, obj, scfile_close, obj)
321
+ : obj);
322
+ }
323
+
324
+
325
+ static void update_filters(VALUE self)
326
+ {
327
+ file_data_t *data = NULL;
328
+ VALUE filters;
329
+ int i;
330
+
331
+ if (RTEST(rb_ivar_get(self, iv_filters_changed))) {
332
+ uint16_t filter_values[MAX_SCTYPE_VALUE];
333
+ uint16_t num_values = 0;
334
+
335
+ rb_ivar_set(self, iv_filters_changed, Qnil);
336
+
337
+ Data_Get_Struct(self, file_data_t, data);
338
+ if (data->filters) {
339
+ scamper_file_filter_free(data->filters);
340
+ data->filters = NULL;
341
+ }
342
+
343
+ filters = rb_ivar_get(self, iv_filters);
344
+ if (!NIL_P(filters) && RARRAY(filters)->len > 0) {
345
+ for (i = 0; i < RARRAY(filters)->len; i++) {
346
+ if (RTEST(rb_ary_entry(filters, i))) {
347
+ filter_values[num_values++] = i;
348
+ }
349
+ }
350
+
351
+ if (num_values > 0) {
352
+ data->filters = scamper_file_filter_alloc(filter_values, num_values);
353
+ }
354
+ }
355
+ }
356
+ }
357
+
358
+
359
+ #define RETURN(value) \
360
+ if (rb_block_given_p()) { \
361
+ rb_yield(value); \
362
+ goto loop; \
363
+ } else return (value)
364
+
365
+ static VALUE scfile_read(VALUE self)
366
+ {
367
+ file_data_t *data = NULL;
368
+ uint16_t obj_type = 0;
369
+ void *obj_data = NULL;
370
+ VALUE obj;
371
+ int result;
372
+
373
+ Data_Get_Struct(self, file_data_t, data);
374
+ if (!data->file) {
375
+ return Qnil;
376
+ }
377
+ CHECK_READABLE(self)
378
+
379
+ update_filters(self);
380
+
381
+ loop:
382
+ result = scamper_file_read(data->file, data->filters, &obj_type, &obj_data);
383
+ if (result == -1) {
384
+ rb_raise(rb_eIOError, "couldn't read warts file data");
385
+ }
386
+ if (!obj_data) {
387
+ return Qnil; /* EOF */
388
+ }
389
+
390
+ switch (obj_type) {
391
+ case SCAMPER_FILE_OBJ_LIST:
392
+ RETURN(sclist_create((scamper_list_t *)obj_data));
393
+
394
+ case SCAMPER_FILE_OBJ_CYCLE_START:
395
+ case SCAMPER_FILE_OBJ_CYCLE_DEF:
396
+ case SCAMPER_FILE_OBJ_CYCLE_STOP:
397
+ RETURN(sccycle_create((scamper_cycle_t *)obj_data, obj_type));
398
+
399
+ case SCAMPER_FILE_OBJ_ADDR:
400
+ RETURN(scaddr_create((scamper_addr_t *)obj_data));
401
+
402
+ case SCAMPER_FILE_OBJ_TRACE:
403
+ RETURN(sctrace_create((scamper_trace_t *)obj_data));
404
+
405
+ default:
406
+ rb_notimplement();
407
+ }
408
+ }
409
+
410
+ #undef RETURN
411
+
412
+
413
+ /*
414
+ ** This method initiates multiple dispatch with obj. Obj.write_to(file)
415
+ ** should turn around and invoke a suitable write_xxx method; e.g., a trace
416
+ ** object should call file.write_trace(self), and a ping object should call
417
+ ** file.write_ping(self).
418
+ */
419
+ static VALUE scfile_write(VALUE self, VALUE obj)
420
+ {
421
+ rb_funcall(obj, meth_write_to, 1, self);
422
+ }
423
+
424
+
425
+ /*
426
+ ** There's a bug in scamper_file_warts.c:warts_list_write
427
+ ** (scamper-cvs-20070523e & f):
428
+ **
429
+ ** $ split-traces-by-type trmethod-20071106-list.one24.100000.warts
430
+ ** scamper_file_warts.c:1523: failed assertion `off == len'
431
+ ** Abort trap
432
+ **
433
+ ** This bug is triggered when a list object is missing BOTH
434
+ ** a description and a monitor name. As a workaround, we set the
435
+ ** description and monitor name to empty strings if they aren't
436
+ ** already set.
437
+ */
438
+ static void warts_list_write_bug_workaround(scamper_list_t *list)
439
+ {
440
+ if (!list) return;
441
+ if (!list->descr) list->descr = strdup("");
442
+ if (!list->monitor) list->monitor = strdup("");
443
+ }
444
+
445
+
446
+ static VALUE scfile_write_trace(VALUE self, VALUE obj)
447
+ {
448
+ file_data_t *data = NULL;
449
+ scamper_trace_t *trace = NULL;
450
+ int result;
451
+
452
+ if (TYPE(obj) != T_DATA || !RTEST(rb_obj_is_instance_of(obj, cTrace))) {
453
+ rb_raise(rb_eArgError, "argument must be instance of Warts::Trace");
454
+ }
455
+
456
+ Data_Get_Struct(self, file_data_t, data);
457
+ if (!data->file) {
458
+ return Qnil;
459
+ }
460
+ CHECK_WRITABLE(self)
461
+
462
+ Data_Get_Struct(obj, scamper_trace_t, trace);
463
+ warts_list_write_bug_workaround(trace->list);
464
+ if (trace->cycle) {
465
+ warts_list_write_bug_workaround(trace->cycle->list);
466
+ }
467
+
468
+ result = scamper_file_write_trace(data->file, trace);
469
+ if (result == -1) {
470
+ rb_raise(rb_eIOError, "couldn't write warts file data");
471
+ }
472
+ return self;
473
+ }
474
+
475
+
476
+ /*
477
+ ** NOTE: We could have gone with a single scfile_write_cycle() function
478
+ ** that determines what scamper function to call based on the type
479
+ ** of the cycle object. However, such a design might prove
480
+ ** inconvenient for the user since cycle objects are immutable
481
+ ** in this extension. If there were only a single function, then
482
+ ** users would have to be careful to hang onto the START/STOP
483
+ ** cycle objects when sorting traces into files.
484
+ */
485
+ static VALUE scfile_write_cycle_start(VALUE self, VALUE obj)
486
+ {
487
+ file_data_t *data = NULL;
488
+ scamper_cycle_t *cycle = NULL;
489
+ int result;
490
+
491
+ if (TYPE(obj) != T_DATA || !RTEST(rb_obj_is_instance_of(obj, cCycle))) {
492
+ rb_raise(rb_eArgError, "argument must be instance of Warts::Cycle");
493
+ }
494
+
495
+ Data_Get_Struct(self, file_data_t, data);
496
+ if (!data->file) {
497
+ return Qnil;
498
+ }
499
+ CHECK_WRITABLE(self)
500
+
501
+ Data_Get_Struct(obj, scamper_cycle_t, cycle);
502
+ warts_list_write_bug_workaround(cycle->list);
503
+
504
+ result = scamper_file_write_cycle_start(data->file, cycle);
505
+ if (result == -1) {
506
+ rb_raise(rb_eIOError, "couldn't write warts file data");
507
+ }
508
+ return self;
509
+ }
510
+
511
+
512
+ static VALUE scfile_write_cycle_stop(VALUE self, VALUE obj)
513
+ {
514
+ file_data_t *data = NULL;
515
+ scamper_cycle_t *cycle = NULL;
516
+ int result;
517
+
518
+ if (TYPE(obj) != T_DATA || !RTEST(rb_obj_is_instance_of(obj, cCycle))) {
519
+ rb_raise(rb_eArgError, "argument must be instance of Warts::Cycle");
520
+ }
521
+
522
+ Data_Get_Struct(self, file_data_t, data);
523
+ if (!data->file) {
524
+ return Qnil;
525
+ }
526
+ CHECK_WRITABLE(self)
527
+
528
+ Data_Get_Struct(obj, scamper_cycle_t, cycle);
529
+ warts_list_write_bug_workaround(cycle->list);
530
+
531
+ result = scamper_file_write_cycle_stop(data->file, cycle);
532
+ if (result == -1) {
533
+ rb_raise(rb_eIOError, "couldn't write warts file data");
534
+ }
535
+ return self;
536
+ }
537
+
538
+
539
+ /*-------------------------------------------------------------------------*/
540
+
541
+ static VALUE get_iv_filters(VALUE self)
542
+ {
543
+ VALUE filters = rb_ivar_get(self, iv_filters);
544
+ if (NIL_P(filters)) {
545
+ filters = rb_ary_new();
546
+ rb_ivar_set(self, iv_filters, filters);
547
+ }
548
+ return filters;
549
+ }
550
+
551
+
552
+ /* NOTE: This is a helper function: don't directly invoke as a Ruby method. */
553
+ static VALUE scfile_set_filters(int argc, VALUE *argv, VALUE self, VALUE value)
554
+ {
555
+ VALUE filters, given_filters, filter;
556
+ int i, filter_value;
557
+
558
+ filters = get_iv_filters(self);
559
+
560
+ rb_scan_args(argc, argv, "*", &given_filters);
561
+ for (i = 0; i < RARRAY(given_filters)->len; i++) {
562
+ filter = rb_ary_entry(given_filters, i);
563
+ if (RTEST(filter)) {
564
+ filter_value = NUM2INT(filter);
565
+ if (filter_value < MIN_SCTYPE_VALUE || filter_value > MAX_SCTYPE_VALUE) {
566
+ rb_raise(rb_eArgError, "invalid filter value %d", filter_value);
567
+ }
568
+
569
+ rb_ary_store(filters, filter_value, value);
570
+ }
571
+ }
572
+
573
+ rb_ivar_set(self, iv_filters_changed, Qtrue);
574
+ return self;
575
+ }
576
+
577
+
578
+ static VALUE scfile_add_all_filters(VALUE self)
579
+ {
580
+ VALUE filters;
581
+ int i;
582
+
583
+ filters = get_iv_filters(self);
584
+
585
+ for (i = 0; i < num_sctypes; i++) {
586
+ rb_ary_store(filters, all_sctypes[i].value, Qtrue);
587
+ }
588
+
589
+ rb_ivar_set(self, iv_filters_changed, Qtrue);
590
+ return self;
591
+ }
592
+
593
+
594
+ static VALUE scfile_add_filters(int argc, VALUE *argv, VALUE self)
595
+ {
596
+ return scfile_set_filters(argc, argv, self, Qtrue);
597
+ }
598
+
599
+
600
+ static VALUE scfile_clear_all_filters(VALUE self)
601
+ {
602
+ rb_ivar_set(self, iv_filters, Qnil);
603
+ rb_ivar_set(self, iv_filters_changed, Qtrue);
604
+ return self;
605
+ }
606
+
607
+
608
+ static VALUE scfile_clear_filters(int argc, VALUE *argv, VALUE self)
609
+ {
610
+ return scfile_set_filters(argc, argv, self, Qnil);
611
+ }
612
+
613
+
614
+ static VALUE scfile_get_filters(VALUE self)
615
+ {
616
+ VALUE retval, filters;
617
+ int i;
618
+
619
+ retval = rb_ary_new();
620
+
621
+ filters = rb_ivar_get(self, iv_filters);
622
+ if (!NIL_P(filters)) {
623
+ for (i = 0; i < RARRAY(filters)->len; i++) {
624
+ if (RTEST(rb_ary_entry(filters, i))) {
625
+ rb_ary_push(retval, INT2FIX(i));
626
+ }
627
+ }
628
+ }
629
+ return retval;
630
+ }
631
+
632
+
633
+ /***************************************************************************/
634
+ /***************************************************************************/
635
+
636
+ void Init_scfile(void)
637
+ {
638
+ ID private_ID, dup_ID, clone_ID;
639
+ int i;
640
+
641
+ iv_readable = rb_intern("@readable");
642
+ iv_filters = rb_intern("@filters");
643
+ iv_filters_changed = rb_intern("@filters_changed");
644
+ meth_write_to = rb_intern("write_to");
645
+ meth_kind_of = rb_intern("kind_of?");
646
+ meth_fileno = rb_intern("fileno");
647
+
648
+ cFile = rb_define_class_under(mWarts, "File", rb_cObject);
649
+
650
+ for (i = 0; i < num_sctypes; i++) {
651
+ rb_define_const(cFile, all_sctypes[i].name,
652
+ INT2FIX(all_sctypes[i].value));
653
+ }
654
+
655
+ rb_define_const(cFile, "TRACEROUTE", rb_str_new2("traceroute"));
656
+ rb_define_const(cFile, "ARTS", rb_str_new2("arts"));
657
+ rb_define_const(cFile, "WARTS", rb_str_new2("warts"));
658
+
659
+ rb_define_singleton_method(cFile, "open", scfile_s_open, -1);
660
+
661
+ rb_define_alloc_func(cFile, scfile_alloc);
662
+
663
+ rb_define_method(cFile, "initialize", scfile_init, -1);
664
+ rb_define_method(cFile, "type", scfile_type, 0);
665
+ rb_define_method(cFile, "path", scfile_path, 0);
666
+ rb_define_method(cFile, "close", scfile_close, 0);
667
+ rb_define_method(cFile, "closed?", scfile_closed, 0);
668
+ rb_define_method(cFile, "read", scfile_read, 0);
669
+ rb_define_method(cFile, "write", scfile_write, 1);
670
+ rb_define_method(cFile, "write_trace", scfile_write_trace, 1);
671
+ rb_define_method(cFile, "write_cycle_start", scfile_write_cycle_start, 1);
672
+ rb_define_method(cFile, "write_cycle_stop", scfile_write_cycle_stop, 1);
673
+
674
+ rb_define_alias(cFile, "each", "read");
675
+
676
+ rb_define_method(cFile, "add_all_filters", scfile_add_all_filters, 0);
677
+ rb_define_method(cFile, "add_filters", scfile_add_filters, -1);
678
+ rb_define_method(cFile, "clear_all_filters", scfile_clear_all_filters, 0);
679
+ rb_define_method(cFile, "clear_filters", scfile_clear_filters, -1);
680
+ rb_define_method(cFile, "filters", scfile_get_filters, 0);
681
+
682
+ private_ID = rb_intern("private");
683
+ dup_ID = rb_intern("dup");
684
+ clone_ID = rb_intern("clone");
685
+
686
+ rb_funcall(cFile, private_ID, 1, ID2SYM(dup_ID));
687
+ rb_funcall(cFile, private_ID, 1, ID2SYM(clone_ID));
688
+ }