ruby-magic 0.3.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,51 +11,68 @@ static int rb_mgc_warning;
11
11
  static ID id_at_flags;
12
12
  static ID id_at_paths;
13
13
 
14
- static VALUE rb_cMagic = Qundef;
14
+ static VALUE rb_cMagic;
15
15
 
16
- static VALUE rb_mgc_eError = Qundef;
17
- static VALUE rb_mgc_eMagicError = Qundef;
18
- static VALUE rb_mgc_eLibraryError = Qundef;
19
- static VALUE rb_mgc_eParameterError = Qundef;
20
- static VALUE rb_mgc_eFlagsError = Qundef;
21
- static VALUE rb_mgc_eNotImplementedError = Qundef;
16
+ static VALUE rb_mgc_eError;
17
+ static VALUE rb_mgc_eMagicError;
18
+ static VALUE rb_mgc_eLibraryError;
19
+ static VALUE rb_mgc_eNotImplementedError;
20
+ static VALUE rb_mgc_eParameterError;
21
+ static VALUE rb_mgc_eFlagsError;
22
22
 
23
- void Init_magic(void);
23
+ static const rb_data_type_t rb_mgc_type;
24
24
 
25
25
  static VALUE magic_get_parameter_internal(void *data);
26
26
  static VALUE magic_set_parameter_internal(void *data);
27
+
27
28
  static VALUE magic_get_flags_internal(void *data);
28
29
  static VALUE magic_set_flags_internal(void *data);
30
+
29
31
  static VALUE magic_load_internal(void *data);
30
32
  static VALUE magic_load_buffers_internal(void *data);
33
+
31
34
  static VALUE magic_compile_internal(void *data);
32
35
  static VALUE magic_check_internal(void *data);
36
+
33
37
  static VALUE magic_file_internal(void *data);
34
38
  static VALUE magic_buffer_internal(void *data);
35
39
  static VALUE magic_descriptor_internal(void *data);
40
+
36
41
  static VALUE magic_close_internal(void *data);
37
42
 
38
- static void* nogvl_magic_load(void *data);
39
- static void* nogvl_magic_compile(void *data);
40
- static void* nogvl_magic_check(void *data);
41
- static void* nogvl_magic_file(void *data);
42
- static void* nogvl_magic_descriptor(void *data);
43
+ static void *nogvl_magic_load(void *data);
44
+ static void *nogvl_magic_compile(void *data);
45
+ static void *nogvl_magic_check(void *data);
46
+ static void *nogvl_magic_file(void *data);
47
+ static void *nogvl_magic_descriptor(void *data);
48
+
49
+ static void *magic_library_open(void);
50
+ static void magic_library_close(void *data);
43
51
 
44
52
  static VALUE magic_allocate(VALUE klass);
45
53
  static void magic_mark(void *data);
46
54
  static void magic_free(void *data);
55
+ static size_t magic_size(const void *data);
56
+ #if defined(HAVE_RUBY_GC_COMPACT)
57
+ static void magic_compact(void *data);
58
+ #endif
59
+
47
60
  static VALUE magic_exception_wrapper(VALUE value);
48
61
  static VALUE magic_exception(void *data);
49
- static void magic_library_close(void *data);
62
+
50
63
  static VALUE magic_library_error(VALUE klass, void *data);
51
64
  static VALUE magic_generic_error(VALUE klass, int magic_errno,
52
65
  const char *magic_error);
66
+
53
67
  static VALUE magic_lock(VALUE object, VALUE (*function)(ANYARGS),
54
68
  void *data);
55
69
  static VALUE magic_unlock(VALUE object);
70
+
56
71
  static VALUE magic_return(void *data);
57
- static int magic_flags(VALUE object);
58
- static int magic_set_flags(VALUE object, VALUE value);
72
+
73
+ static int magic_get_flags(VALUE object);
74
+ static void magic_set_flags(VALUE object, int flags);
75
+
59
76
  static VALUE magic_set_paths(VALUE object, VALUE value);
60
77
 
61
78
  /*
@@ -110,6 +127,7 @@ VALUE
110
127
  rb_mgc_set_do_not_auto_load_global(RB_UNUSED_VAR(VALUE object), VALUE value)
111
128
  {
112
129
  rb_mgc_do_not_auto_load = RVAL2CBOOL(value);
130
+
113
131
  return value;
114
132
  }
115
133
 
@@ -150,6 +168,7 @@ VALUE
150
168
  rb_mgc_set_do_not_stop_on_error_global(RB_UNUSED_VAR(VALUE object), VALUE value)
151
169
  {
152
170
  rb_mgc_do_not_stop_on_error = RVAL2CBOOL(value);
171
+
153
172
  return value;
154
173
  }
155
174
 
@@ -171,7 +190,7 @@ rb_mgc_set_do_not_stop_on_error_global(RB_UNUSED_VAR(VALUE object), VALUE value)
171
190
  VALUE
172
191
  rb_mgc_initialize(VALUE object, VALUE arguments)
173
192
  {
174
- magic_object_t *mo;
193
+ rb_mgc_object_t *mgc;
175
194
  const char *klass = "Magic";
176
195
 
177
196
  if (!NIL_P(object))
@@ -181,21 +200,22 @@ rb_mgc_initialize(VALUE object, VALUE arguments)
181
200
  MAGIC_WARNING(0, "%s::new() does not take block; use %s::open() instead",
182
201
  klass, klass);
183
202
 
184
- if(RTEST(rb_eval_string("ENV['MAGIC_DO_NOT_STOP_ON_ERROR']")))
203
+ if (RTEST(rb_eval_string("ENV['MAGIC_DO_NOT_STOP_ON_ERROR']")))
185
204
  rb_mgc_do_not_stop_on_error = 1;
186
205
 
187
- if(RTEST(rb_eval_string("ENV['MAGIC_DO_NOT_AUTOLOAD']")))
206
+ if (RTEST(rb_eval_string("ENV['MAGIC_DO_NOT_AUTOLOAD']")))
188
207
  rb_mgc_do_not_auto_load = 1;
189
208
 
190
- MAGIC_OBJECT(mo);
191
- mo->stop_on_errors = 1;
209
+ MAGIC_OBJECT(object, mgc);
210
+
211
+ mgc->stop_on_errors = 1;
192
212
  if (rb_mgc_do_not_stop_on_error)
193
- mo->stop_on_errors = 0;
213
+ mgc->stop_on_errors = 0;
194
214
 
195
- mo->mutex = rb_class_new_instance(0, 0, rb_const_get(rb_cObject,
196
- rb_intern("Mutex")));
215
+ mgc->mutex = rb_class_new_instance(0, 0, rb_const_get(rb_cObject,
216
+ rb_intern("Mutex")));
197
217
 
198
- magic_set_flags(object, INT2NUM(MAGIC_NONE));
218
+ magic_set_flags(object, MAGIC_NONE);
199
219
  magic_set_paths(object, RARRAY_EMPTY);
200
220
 
201
221
  if (rb_mgc_do_not_auto_load) {
@@ -207,6 +227,7 @@ rb_mgc_initialize(VALUE object, VALUE arguments)
207
227
  }
208
228
 
209
229
  rb_mgc_load(object, arguments);
230
+
210
231
  return object;
211
232
  }
212
233
 
@@ -219,12 +240,12 @@ rb_mgc_initialize(VALUE object, VALUE arguments)
219
240
  VALUE
220
241
  rb_mgc_get_do_not_stop_on_error(VALUE object)
221
242
  {
222
- magic_object_t *mo;
243
+ rb_mgc_object_t *mgc;
223
244
 
224
245
  MAGIC_CHECK_OPEN(object);
225
- MAGIC_OBJECT(mo);
246
+ MAGIC_OBJECT(object, mgc);
226
247
 
227
- return CBOOL2RVAL(!mo->stop_on_errors);
248
+ return CBOOL2RVAL(!mgc->stop_on_errors);
228
249
  }
229
250
 
230
251
  /*
@@ -236,12 +257,13 @@ rb_mgc_get_do_not_stop_on_error(VALUE object)
236
257
  VALUE
237
258
  rb_mgc_set_do_not_stop_on_error(VALUE object, VALUE value)
238
259
  {
239
- magic_object_t *mo;
260
+ rb_mgc_object_t *mgc;
240
261
 
241
262
  MAGIC_CHECK_OPEN(object);
242
- MAGIC_OBJECT(mo);
263
+ MAGIC_OBJECT(object, mgc);
264
+
265
+ mgc->stop_on_errors = !RVAL2CBOOL(value);
243
266
 
244
- mo->stop_on_errors = !RVAL2CBOOL(value);
245
267
  return value;
246
268
  }
247
269
 
@@ -283,14 +305,15 @@ rb_mgc_open_p(VALUE object)
283
305
  VALUE
284
306
  rb_mgc_close(VALUE object)
285
307
  {
286
- magic_object_t *mo;
308
+ rb_mgc_object_t *mgc;
287
309
 
288
310
  if (MAGIC_CLOSED_P(object))
289
311
  return Qnil;
290
312
 
291
- MAGIC_OBJECT(mo);
292
- if (mo) {
293
- MAGIC_SYNCHRONIZED(magic_close_internal, mo);
313
+ MAGIC_OBJECT(object, mgc);
314
+
315
+ if (mgc) {
316
+ MAGIC_SYNCHRONIZED(magic_close_internal, mgc);
294
317
  if (DATA_P(object))
295
318
  DATA_PTR(object) = NULL;
296
319
  }
@@ -317,12 +340,13 @@ rb_mgc_close(VALUE object)
317
340
  VALUE
318
341
  rb_mgc_close_p(VALUE object)
319
342
  {
320
- magic_object_t *mo;
343
+ rb_mgc_object_t *mgc;
321
344
  magic_t cookie = NULL;
322
345
 
323
- MAGIC_OBJECT(mo);
324
- if (mo)
325
- cookie = mo->cookie;
346
+ MAGIC_OBJECT(object, mgc);
347
+
348
+ if (mgc)
349
+ cookie = mgc->cookie;
326
350
 
327
351
  if (DATA_P(object) && cookie)
328
352
  return Qfalse;
@@ -349,14 +373,17 @@ rb_mgc_get_paths(VALUE object)
349
373
  MAGIC_CHECK_OPEN(object);
350
374
 
351
375
  value = rb_ivar_get(object, id_at_paths);
352
- if (!NIL_P(value) && !RARRAY_EMPTY_P(value) && !getenv("MAGIC"))
376
+ if (!NIL_P(value) && !RARRAY_EMPTY_P(value))
353
377
  return value;
354
378
 
355
- cstring = magic_getpath_wrapper();
356
- value = magic_split(CSTR2RVAL(cstring), CSTR2RVAL(":"));
357
- RB_GC_GUARD(value);
379
+ value = rb_funcall(rb_cMagic, rb_intern("default_paths"), 0);
380
+ if (getenv("MAGIC") || NIL_P(value)) {
381
+ cstring = magic_getpath_wrapper();
382
+ value = magic_split(CSTR2RVAL(cstring), CSTR2RVAL(":"));
383
+ RB_GC_GUARD(value);
384
+ }
358
385
 
359
- return value;
386
+ return magic_set_paths(object, value);
360
387
  }
361
388
 
362
389
  /*
@@ -367,28 +394,34 @@ VALUE
367
394
  rb_mgc_get_parameter(VALUE object, VALUE tag)
368
395
  {
369
396
  int local_errno;
370
- magic_object_t *mo;
371
- magic_arguments_t ma;
397
+ rb_mgc_object_t *mgc;
398
+ rb_mgc_arguments_t mga;
372
399
 
373
400
  MAGIC_CHECK_INTEGER_TYPE(tag);
401
+
374
402
  MAGIC_CHECK_OPEN(object);
375
- MAGIC_COOKIE(mo, ma.cookie);
403
+ MAGIC_OBJECT(object, mgc);
376
404
 
377
- ma.type.parameter.tag = NUM2INT(tag);
405
+ mga = (rb_mgc_arguments_t) {
406
+ .magic_object = mgc,
407
+ .parameter = {
408
+ .tag = NUM2INT(tag),
409
+ },
410
+ };
378
411
 
379
- MAGIC_SYNCHRONIZED(magic_get_parameter_internal, &ma);
412
+ MAGIC_SYNCHRONIZED(magic_get_parameter_internal, &mga);
380
413
  local_errno = errno;
381
414
 
382
- if (ma.status < 0) {
415
+ if (mga.status < 0) {
383
416
  if (local_errno == EINVAL)
384
417
  MAGIC_GENERIC_ERROR(rb_mgc_eParameterError,
385
418
  local_errno,
386
419
  E_PARAM_INVALID_TYPE);
387
420
 
388
- MAGIC_LIBRARY_ERROR(ma.cookie);
421
+ MAGIC_LIBRARY_ERROR(mgc);
389
422
  }
390
423
 
391
- return SIZET2NUM(ma.type.parameter.value);
424
+ return SIZET2NUM(mga.parameter.value);
392
425
  }
393
426
 
394
427
  /*
@@ -399,21 +432,27 @@ VALUE
399
432
  rb_mgc_set_parameter(VALUE object, VALUE tag, VALUE value)
400
433
  {
401
434
  int local_errno;
402
- magic_object_t *mo;
403
- magic_arguments_t ma;
435
+ rb_mgc_object_t *mgc;
436
+ rb_mgc_arguments_t mga;
404
437
 
405
438
  MAGIC_CHECK_INTEGER_TYPE(tag);
406
439
  MAGIC_CHECK_INTEGER_TYPE(value);
440
+
407
441
  MAGIC_CHECK_OPEN(object);
408
- MAGIC_COOKIE(mo, ma.cookie);
442
+ MAGIC_OBJECT(object, mgc);
409
443
 
410
- ma.type.parameter.tag = NUM2INT(tag);
411
- ma.type.parameter.value = NUM2SIZET(value);
444
+ mga = (rb_mgc_arguments_t) {
445
+ .magic_object = mgc,
446
+ .parameter = {
447
+ .tag = NUM2INT(tag),
448
+ .value = NUM2SIZET(value),
449
+ },
450
+ };
412
451
 
413
- MAGIC_SYNCHRONIZED(magic_set_parameter_internal, &ma);
452
+ MAGIC_SYNCHRONIZED(magic_set_parameter_internal, &mga);
414
453
  local_errno = errno;
415
454
 
416
- if (ma.status < 0) {
455
+ if (mga.status < 0) {
417
456
  switch (local_errno) {
418
457
  case EINVAL:
419
458
  MAGIC_GENERIC_ERROR(rb_mgc_eParameterError,
@@ -424,7 +463,8 @@ rb_mgc_set_parameter(VALUE object, VALUE tag, VALUE value)
424
463
  local_errno,
425
464
  E_PARAM_INVALID_VALUE);
426
465
  }
427
- MAGIC_LIBRARY_ERROR(ma.cookie);
466
+
467
+ MAGIC_LIBRARY_ERROR(mgc);
428
468
  }
429
469
 
430
470
  return Qnil;
@@ -447,19 +487,23 @@ VALUE
447
487
  rb_mgc_get_flags(VALUE object)
448
488
  {
449
489
  int local_errno;
450
- magic_object_t *mo;
451
- magic_arguments_t ma;
490
+ rb_mgc_object_t *mgc;
491
+ rb_mgc_arguments_t mga;
452
492
 
453
493
  MAGIC_CHECK_OPEN(object);
454
- MAGIC_COOKIE(mo, ma.cookie);
494
+ MAGIC_OBJECT(object, mgc);
495
+
496
+ mga = (rb_mgc_arguments_t) {
497
+ .magic_object = mgc,
498
+ };
455
499
 
456
- MAGIC_SYNCHRONIZED(magic_get_flags_internal, &ma);
500
+ MAGIC_SYNCHRONIZED(magic_get_flags_internal, &mga);
457
501
  local_errno = errno;
458
502
 
459
- if (ma.flags < 0 && local_errno == ENOSYS)
503
+ if (mga.status < 0 && local_errno == ENOSYS)
460
504
  return rb_ivar_get(object, id_at_flags);
461
505
 
462
- return INT2NUM(ma.flags);
506
+ return INT2NUM(mga.flags);
463
507
  }
464
508
 
465
509
  /*
@@ -476,19 +520,43 @@ VALUE
476
520
  rb_mgc_set_flags(VALUE object, VALUE value)
477
521
  {
478
522
  int local_errno;
479
- magic_object_t *mo;
480
- magic_arguments_t ma;
523
+ rb_mgc_object_t *mgc;
524
+ rb_mgc_arguments_t mga;
525
+ const char *klass = "Magic";
526
+ const char *flag = NULL;
481
527
 
482
528
  MAGIC_CHECK_INTEGER_TYPE(value);
529
+
483
530
  MAGIC_CHECK_OPEN(object);
484
- MAGIC_COOKIE(mo, ma.cookie);
531
+ MAGIC_OBJECT(object, mgc);
532
+
533
+ mga = (rb_mgc_arguments_t) {
534
+ .magic_object = mgc,
535
+ .flags = NUM2INT(value),
536
+ };
537
+
538
+ if (mga.flags < 0)
539
+ MAGIC_GENERIC_ERROR(rb_mgc_eFlagsError, EINVAL,
540
+ E_FLAG_INVALID_TYPE);
541
+
542
+ if (mga.flags & MAGIC_DEBUG)
543
+ flag = "DEBUG";
544
+ else if (mga.flags & MAGIC_CHECK)
545
+ flag = "CHECK";
546
+
547
+ if (flag) {
548
+ if (!NIL_P(object))
549
+ klass = rb_obj_classname(object);
485
550
 
486
- ma.flags = NUM2INT(value);
551
+ MAGIC_WARNING(0, "%s::%s flag is set; verbose information will "
552
+ "now be printed to the standard error output",
553
+ klass, flag);
554
+ }
487
555
 
488
- MAGIC_SYNCHRONIZED(magic_set_flags_internal, &ma);
556
+ MAGIC_SYNCHRONIZED(magic_set_flags_internal, &mga);
489
557
  local_errno = errno;
490
558
 
491
- if (ma.status < 0) {
559
+ if (mga.status < 0) {
492
560
  switch (local_errno) {
493
561
  case EINVAL:
494
562
  MAGIC_GENERIC_ERROR(rb_mgc_eFlagsError,
@@ -499,10 +567,11 @@ rb_mgc_set_flags(VALUE object, VALUE value)
499
567
  local_errno,
500
568
  E_FLAG_NOT_IMPLEMENTED);
501
569
  }
502
- MAGIC_LIBRARY_ERROR(ma.cookie);
570
+
571
+ MAGIC_LIBRARY_ERROR(mgc);
503
572
  }
504
573
 
505
- return rb_ivar_set(object, id_at_flags, INT2NUM(ma.flags));
574
+ return rb_ivar_set(object, id_at_flags, INT2NUM(mga.flags));
506
575
  }
507
576
 
508
577
  /*
@@ -518,8 +587,8 @@ rb_mgc_set_flags(VALUE object, VALUE value)
518
587
  VALUE
519
588
  rb_mgc_load(VALUE object, VALUE arguments)
520
589
  {
521
- magic_object_t *mo;
522
- magic_arguments_t ma;
590
+ rb_mgc_object_t *mgc;
591
+ rb_mgc_arguments_t mga;
523
592
  const char *klass = "Magic";
524
593
  VALUE value = Qundef;
525
594
 
@@ -527,40 +596,48 @@ rb_mgc_load(VALUE object, VALUE arguments)
527
596
  arguments = magic_flatten(arguments);
528
597
 
529
598
  MAGIC_CHECK_ARRAY_OF_STRINGS(arguments);
599
+
530
600
  MAGIC_CHECK_OPEN(object);
531
- MAGIC_COOKIE(mo, ma.cookie);
601
+ MAGIC_OBJECT(object, mgc);
532
602
 
533
603
  if (rb_mgc_do_not_auto_load) {
534
604
  if (!NIL_P(object))
535
605
  klass = rb_obj_classname(object);
536
606
 
537
607
  MAGIC_WARNING(2, "%s::do_not_auto_load is set; using %s#load "
538
- "will load Magic database from a file",
539
- klass, klass);
608
+ "will load Magic database from a file",
609
+ klass, klass);
540
610
  }
541
611
 
542
- ma.flags = magic_flags(object);
612
+ if (RARRAY_EMPTY_P(arguments))
613
+ arguments = rb_mgc_get_paths(object);
543
614
 
544
- if (!RARRAY_EMPTY_P(arguments)) {
545
- value = magic_join(arguments, CSTR2RVAL(":"));
546
- ma.type.file.path = RVAL2CSTR(value);
547
- }
548
- else
549
- ma.type.file.path = magic_getpath_wrapper();
615
+ value = magic_join(arguments, CSTR2RVAL(":"));
616
+ RB_GC_GUARD(value);
550
617
 
551
618
  magic_set_paths(object, RARRAY_EMPTY);
552
619
 
553
- MAGIC_SYNCHRONIZED(magic_load_internal, &ma);
554
- if (ma.status < 0) {
555
- mo->database_loaded = 0;
556
- MAGIC_LIBRARY_ERROR(ma.cookie);
620
+ mga = (rb_mgc_arguments_t) {
621
+ .magic_object = mgc,
622
+ .file = {
623
+ .path = RVAL2CSTR(value),
624
+ },
625
+ .flags = magic_get_flags(object),
626
+ };
627
+
628
+ MAGIC_SYNCHRONIZED(magic_load_internal, &mga);
629
+ if (mga.status < 0) {
630
+ mgc->database_loaded = 0;
631
+ MAGIC_LIBRARY_ERROR(mgc);
557
632
  }
558
- mo->database_loaded = 1;
559
633
 
560
- value = magic_split(CSTR2RVAL(ma.type.file.path), CSTR2RVAL(":"));
561
- magic_set_paths(object, value);
634
+ mgc->database_loaded = 1;
635
+
636
+ value = magic_split(CSTR2RVAL(mga.file.path), CSTR2RVAL(":"));
562
637
  RB_GC_GUARD(value);
563
638
 
639
+ magic_set_paths(object, value);
640
+
564
641
  return Qnil;
565
642
  }
566
643
 
@@ -576,8 +653,8 @@ rb_mgc_load_buffers(VALUE object, VALUE arguments)
576
653
  {
577
654
  size_t count;
578
655
  int local_errno;
579
- magic_object_t *mo;
580
- magic_arguments_t ma;
656
+ rb_mgc_object_t *mgc;
657
+ rb_mgc_arguments_t mga;
581
658
  void **pointers = NULL;
582
659
  size_t *sizes = NULL;
583
660
  VALUE value = Qundef;
@@ -592,8 +669,9 @@ rb_mgc_load_buffers(VALUE object, VALUE arguments)
592
669
 
593
670
  MAGIC_CHECK_ARRAY_EMPTY(arguments);
594
671
  MAGIC_CHECK_ARRAY_OF_STRINGS(arguments);
672
+
595
673
  MAGIC_CHECK_OPEN(object);
596
- MAGIC_COOKIE(mo, ma.cookie);
674
+ MAGIC_OBJECT(object, mgc);
597
675
 
598
676
  pointers = ALLOC_N(void *, count);
599
677
  if (!pointers) {
@@ -614,35 +692,41 @@ rb_mgc_load_buffers(VALUE object, VALUE arguments)
614
692
  sizes[i] = (size_t)RSTRING_LEN(value);
615
693
  }
616
694
 
617
- ma.flags = magic_flags(object);
618
- ma.type.buffers.count = count;
619
- ma.type.buffers.pointers = pointers;
620
- ma.type.buffers.sizes = sizes;
621
-
622
695
  magic_set_paths(object, RARRAY_EMPTY);
623
696
 
624
- MAGIC_SYNCHRONIZED(magic_load_buffers_internal, &ma);
625
- if (ma.status < 0) {
697
+ mga = (rb_mgc_arguments_t) {
698
+ .magic_object = mgc,
699
+ .buffers = {
700
+ .count = count,
701
+ .pointers = pointers,
702
+ .sizes = sizes,
703
+ },
704
+ .flags = magic_get_flags(object),
705
+ };
706
+
707
+ MAGIC_SYNCHRONIZED(magic_load_buffers_internal, &mga);
708
+ if (mga.status < 0) {
626
709
  local_errno = errno;
627
710
  ruby_xfree(pointers);
628
711
  ruby_xfree(sizes);
629
712
  goto error;
630
713
  }
631
- mo->database_loaded = 1;
714
+
715
+ mgc->database_loaded = 1;
632
716
 
633
717
  ruby_xfree(pointers);
634
718
  ruby_xfree(sizes);
635
719
 
636
720
  return Qnil;
637
721
  error:
638
- mo->database_loaded = 0;
722
+ mgc->database_loaded = 0;
639
723
 
640
724
  if (local_errno == ENOMEM)
641
725
  MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError,
642
726
  local_errno,
643
727
  E_NOT_ENOUGH_MEMORY);
644
728
 
645
- MAGIC_LIBRARY_ERROR(ma.cookie);
729
+ MAGIC_LIBRARY_ERROR(mgc);
646
730
  }
647
731
 
648
732
  /*
@@ -669,12 +753,12 @@ error:
669
753
  VALUE
670
754
  rb_mgc_load_p(VALUE object)
671
755
  {
672
- magic_object_t *mo;
756
+ rb_mgc_object_t *mgc;
673
757
 
674
758
  MAGIC_CHECK_OPEN(object);
675
- MAGIC_OBJECT(mo);
759
+ MAGIC_OBJECT(object, mgc);
676
760
 
677
- return CBOOL2RVAL(mo->database_loaded);
761
+ return CBOOL2RVAL(mgc->database_loaded);
678
762
  }
679
763
 
680
764
  /*
@@ -687,19 +771,25 @@ rb_mgc_load_p(VALUE object)
687
771
  VALUE
688
772
  rb_mgc_compile(VALUE object, VALUE value)
689
773
  {
690
- magic_object_t *mo;
691
- magic_arguments_t ma;
774
+ rb_mgc_object_t *mgc;
775
+ rb_mgc_arguments_t mga;
692
776
 
693
777
  MAGIC_CHECK_STRING_TYPE(value);
778
+
694
779
  MAGIC_CHECK_OPEN(object);
695
- MAGIC_COOKIE(mo, ma.cookie);
780
+ MAGIC_OBJECT(object, mgc);
696
781
 
697
- ma.flags = magic_flags(object);
698
- ma.type.file.path = RVAL2CSTR(value);
782
+ mga = (rb_mgc_arguments_t) {
783
+ .magic_object = mgc,
784
+ .file = {
785
+ .path = RVAL2CSTR(value),
786
+ },
787
+ .flags = magic_get_flags(object),
788
+ };
699
789
 
700
- MAGIC_SYNCHRONIZED(magic_compile_internal, &ma);
701
- if (ma.status < 0)
702
- MAGIC_LIBRARY_ERROR(ma.cookie);
790
+ MAGIC_SYNCHRONIZED(magic_compile_internal, &mga);
791
+ if (mga.status < 0)
792
+ MAGIC_LIBRARY_ERROR(mgc);
703
793
 
704
794
  return Qnil;
705
795
  }
@@ -714,18 +804,25 @@ rb_mgc_compile(VALUE object, VALUE value)
714
804
  VALUE
715
805
  rb_mgc_check(VALUE object, VALUE value)
716
806
  {
717
- magic_object_t *mo;
718
- magic_arguments_t ma;
807
+ rb_mgc_object_t *mgc;
808
+ rb_mgc_arguments_t mga;
719
809
 
720
810
  MAGIC_CHECK_STRING_TYPE(value);
811
+
721
812
  MAGIC_CHECK_OPEN(object);
722
- MAGIC_COOKIE(mo, ma.cookie);
813
+ MAGIC_OBJECT(object, mgc);
814
+
815
+ mga = (rb_mgc_arguments_t) {
816
+ .magic_object = mgc,
817
+ .file = {
818
+ .path = RVAL2CSTR(value),
819
+ },
820
+ .flags = magic_get_flags(object),
821
+ };
723
822
 
724
- ma.flags = magic_flags(object);
725
- ma.type.file.path = RVAL2CSTR(value);
823
+ MAGIC_SYNCHRONIZED(magic_check_internal, &mga);
726
824
 
727
- MAGIC_SYNCHRONIZED(magic_check_internal, &ma);
728
- return ma.status < 0 ? Qfalse : Qtrue;
825
+ return mga.status < 0 ? Qfalse : Qtrue;
729
826
  }
730
827
 
731
828
  /*
@@ -738,8 +835,8 @@ rb_mgc_check(VALUE object, VALUE value)
738
835
  VALUE
739
836
  rb_mgc_file(VALUE object, VALUE value)
740
837
  {
741
- magic_object_t *mo;
742
- magic_arguments_t ma;
838
+ rb_mgc_object_t *mgc;
839
+ rb_mgc_arguments_t mga;
743
840
  const char *empty = "(null)";
744
841
 
745
842
  UNUSED(empty);
@@ -749,7 +846,7 @@ rb_mgc_file(VALUE object, VALUE value)
749
846
 
750
847
  MAGIC_CHECK_OPEN(object);
751
848
  MAGIC_CHECK_LOADED(object);
752
- MAGIC_COOKIE(mo, ma.cookie);
849
+ MAGIC_OBJECT(object, mgc);
753
850
 
754
851
  if (rb_respond_to(value, rb_intern("to_io")))
755
852
  return rb_mgc_descriptor(object, value);
@@ -758,12 +855,16 @@ rb_mgc_file(VALUE object, VALUE value)
758
855
  if (NIL_P(value))
759
856
  goto error;
760
857
 
761
- ma.stop_on_errors = mo->stop_on_errors;
762
- ma.flags = magic_flags(object);
763
- ma.type.file.path = RVAL2CSTR(value);
858
+ mga = (rb_mgc_arguments_t) {
859
+ .magic_object = mgc,
860
+ .file = {
861
+ .path = RVAL2CSTR(value),
862
+ },
863
+ .flags = magic_get_flags(object),
864
+ };
764
865
 
765
- MAGIC_SYNCHRONIZED(magic_file_internal, &ma);
766
- if (ma.status < 0 && !ma.result) {
866
+ MAGIC_SYNCHRONIZED(magic_file_internal, &mga);
867
+ if (mga.status < 0 && !mga.result) {
767
868
  /*
768
869
  * Handle the case when the "ERROR" flag is set regardless of the
769
870
  * current version of the underlying Magic library.
@@ -777,15 +878,15 @@ rb_mgc_file(VALUE object, VALUE value)
777
878
  * This is an attempt to mitigate the problem and correct it to achieve
778
879
  * the desired behavior as per the standards.
779
880
  */
780
- if (mo->stop_on_errors || (ma.flags & MAGIC_ERROR))
781
- MAGIC_LIBRARY_ERROR(ma.cookie);
881
+ if (mgc->stop_on_errors || (mga.flags & MAGIC_ERROR))
882
+ MAGIC_LIBRARY_ERROR(mgc);
782
883
 
783
- ma.result = magic_error_wrapper(ma.cookie);
884
+ mga.result = magic_error_wrapper(mgc->cookie);
784
885
  }
785
- if (!ma.result)
886
+ if (!mga.result)
786
887
  MAGIC_GENERIC_ERROR(rb_mgc_eMagicError, EINVAL, E_UNKNOWN);
787
888
 
788
- assert(ma.result != NULL && \
889
+ assert(mga.result != NULL &&
789
890
  "Must be a valid pointer to `const char' type");
790
891
 
791
892
  /*
@@ -794,10 +895,10 @@ rb_mgc_file(VALUE object, VALUE value)
794
895
  * string instead. Often this would indicate that an older version of the
795
896
  * Magic library is in use.
796
897
  */
797
- assert(strncmp(ma.result, empty, strlen(empty)) != 0 && \
898
+ assert(strncmp(mga.result, empty, strlen(empty)) != 0 &&
798
899
  "Empty or invalid result");
799
900
 
800
- return magic_return(&ma);
901
+ return magic_return(&mga);
801
902
  error:
802
903
  MAGIC_ARGUMENT_TYPE_ERROR(value, "String or IO-like object");
803
904
  }
@@ -811,28 +912,34 @@ error:
811
912
  VALUE
812
913
  rb_mgc_buffer(VALUE object, VALUE value)
813
914
  {
814
- magic_object_t *mo;
815
- magic_arguments_t ma;
915
+ rb_mgc_object_t *mgc;
916
+ rb_mgc_arguments_t mga;
816
917
 
817
918
  MAGIC_CHECK_STRING_TYPE(value);
919
+
818
920
  MAGIC_CHECK_OPEN(object);
819
921
  MAGIC_CHECK_LOADED(object);
820
- MAGIC_COOKIE(mo, ma.cookie);
922
+ MAGIC_OBJECT(object, mgc);
821
923
 
822
924
  StringValue(value);
823
925
 
824
- ma.flags = magic_flags(object);
825
- ma.type.buffers.pointers = (void **)RSTRING_PTR(value);
826
- ma.type.buffers.sizes = (size_t *)RSTRING_LEN(value);
926
+ mga = (rb_mgc_arguments_t) {
927
+ .magic_object = mgc,
928
+ .buffers = {
929
+ .pointers = (void **)RSTRING_PTR(value),
930
+ .sizes = (size_t *)RSTRING_LEN(value),
931
+ },
932
+ .flags = magic_get_flags(object),
933
+ };
827
934
 
828
- MAGIC_SYNCHRONIZED(magic_buffer_internal, &ma);
829
- if (ma.status < 0)
830
- MAGIC_LIBRARY_ERROR(ma.cookie);
935
+ MAGIC_SYNCHRONIZED(magic_buffer_internal, &mga);
936
+ if (mga.status < 0)
937
+ MAGIC_LIBRARY_ERROR(mgc);
831
938
 
832
- assert(ma.result != NULL && \
939
+ assert(mga.result != NULL &&
833
940
  "Must be a valid pointer to `const char' type");
834
941
 
835
- return magic_return(&ma);
942
+ return magic_return(&mga);
836
943
  }
837
944
 
838
945
  /*
@@ -846,34 +953,40 @@ VALUE
846
953
  rb_mgc_descriptor(VALUE object, VALUE value)
847
954
  {
848
955
  int local_errno;
849
- magic_object_t *mo;
850
- magic_arguments_t ma;
956
+ rb_mgc_object_t *mgc;
957
+ rb_mgc_arguments_t mga;
851
958
 
852
959
  if (rb_respond_to(value, rb_intern("to_io")))
853
960
  value = INT2NUM(magic_fileno(value));
854
961
 
855
962
  MAGIC_CHECK_INTEGER_TYPE(value);
963
+
856
964
  MAGIC_CHECK_OPEN(object);
857
965
  MAGIC_CHECK_LOADED(object);
858
- MAGIC_COOKIE(mo, ma.cookie);
966
+ MAGIC_OBJECT(object, mgc);
859
967
 
860
- ma.flags = magic_flags(object);
861
- ma.type.file.fd = NUM2INT(value);
968
+ mga = (rb_mgc_arguments_t) {
969
+ .magic_object = mgc,
970
+ .file = {
971
+ .fd = NUM2INT(value),
972
+ },
973
+ .flags = magic_get_flags(object),
974
+ };
862
975
 
863
- MAGIC_SYNCHRONIZED(magic_descriptor_internal, &ma);
976
+ MAGIC_SYNCHRONIZED(magic_descriptor_internal, &mga);
864
977
  local_errno = errno;
865
978
 
866
- if (ma.status < 0) {
979
+ if (mga.status < 0) {
867
980
  if (local_errno == EBADF)
868
981
  rb_raise(rb_eIOError, "Bad file descriptor");
869
982
 
870
- MAGIC_LIBRARY_ERROR(ma.cookie);
983
+ MAGIC_LIBRARY_ERROR(mgc);
871
984
  }
872
985
 
873
- assert(ma.result != NULL && \
986
+ assert(mga.result != NULL &&
874
987
  "Must be a valid pointer to `const char' type");
875
988
 
876
- return magic_return(&ma);
989
+ return magic_return(&mga);
877
990
  }
878
991
 
879
992
  /*
@@ -895,59 +1008,69 @@ rb_mgc_version(RB_UNUSED_VAR(VALUE object))
895
1008
  static inline void*
896
1009
  nogvl_magic_load(void *data)
897
1010
  {
898
- magic_arguments_t *ma = data;
1011
+ rb_mgc_arguments_t *mga = data;
1012
+ magic_t cookie = mga->magic_object->cookie;
1013
+
1014
+ mga->status = magic_load_wrapper(cookie,
1015
+ mga->file.path,
1016
+ mga->flags);
899
1017
 
900
- ma->status = magic_load_wrapper(ma->cookie,
901
- ma->type.file.path,
902
- ma->flags);
903
1018
  return NULL;
904
1019
  }
905
1020
 
906
1021
  static inline void*
907
1022
  nogvl_magic_compile(void *data)
908
1023
  {
909
- magic_arguments_t *ma = data;
1024
+ rb_mgc_arguments_t *mga = data;
1025
+ magic_t cookie = mga->magic_object->cookie;
1026
+
1027
+ mga->status = magic_compile_wrapper(cookie,
1028
+ mga->file.path,
1029
+ mga->flags);
910
1030
 
911
- ma->status = magic_compile_wrapper(ma->cookie,
912
- ma->type.file.path,
913
- ma->flags);
914
1031
  return NULL;
915
1032
  }
916
1033
 
917
1034
  static inline void*
918
1035
  nogvl_magic_check(void *data)
919
1036
  {
920
- magic_arguments_t *ma = data;
1037
+ rb_mgc_arguments_t *mga = data;
1038
+ magic_t cookie = mga->magic_object->cookie;
1039
+
1040
+ mga->status = magic_check_wrapper(cookie,
1041
+ mga->file.path,
1042
+ mga->flags);
921
1043
 
922
- ma->status = magic_check_wrapper(ma->cookie,
923
- ma->type.file.path,
924
- ma->flags);
925
1044
  return NULL;
926
1045
  }
927
1046
 
928
1047
  static inline void*
929
1048
  nogvl_magic_file(void *data)
930
1049
  {
931
- magic_arguments_t *ma = data;
1050
+ rb_mgc_arguments_t *mga = data;
1051
+ magic_t cookie = mga->magic_object->cookie;
932
1052
 
933
- ma->result = magic_file_wrapper(ma->cookie,
934
- ma->type.file.path,
935
- ma->flags);
1053
+ mga->result = magic_file_wrapper(cookie,
1054
+ mga->file.path,
1055
+ mga->flags);
1056
+
1057
+ mga->status = !mga->result ? -1 : 0;
936
1058
 
937
- ma->status = !ma->result ? -1 : 0;
938
1059
  return NULL;
939
1060
  }
940
1061
 
941
1062
  static inline void*
942
1063
  nogvl_magic_descriptor(void *data)
943
1064
  {
944
- magic_arguments_t *ma = data;
1065
+ rb_mgc_arguments_t *mga = data;
1066
+ magic_t cookie = mga->magic_object->cookie;
1067
+
1068
+ mga->result = magic_descriptor_wrapper(cookie,
1069
+ mga->file.fd,
1070
+ mga->flags);
945
1071
 
946
- ma->result = magic_descriptor_wrapper(ma->cookie,
947
- ma->type.file.fd,
948
- ma->flags);
1072
+ mga->status = !mga->result ? -1 : 0;
949
1073
 
950
- ma->status = !ma->result ? -1 : 0;
951
1074
  return NULL;
952
1075
  }
953
1076
 
@@ -955,12 +1078,15 @@ static inline VALUE
955
1078
  magic_get_parameter_internal(void *data)
956
1079
  {
957
1080
  size_t value;
958
- magic_arguments_t *ma = data;
1081
+ rb_mgc_arguments_t *mga = data;
1082
+ magic_t cookie = mga->magic_object->cookie;
1083
+
1084
+ mga->status = magic_getparam_wrapper(cookie,
1085
+ mga->parameter.tag,
1086
+ &value);
1087
+
1088
+ mga->parameter.value = value;
959
1089
 
960
- ma->status = magic_getparam_wrapper(ma->cookie,
961
- ma->type.parameter.tag,
962
- &value);
963
- ma->type.parameter.value = value;
964
1090
  return (VALUE)NULL;
965
1091
  }
966
1092
 
@@ -968,30 +1094,44 @@ static inline VALUE
968
1094
  magic_set_parameter_internal(void *data)
969
1095
  {
970
1096
  size_t value;
971
- magic_arguments_t *ma = data;
1097
+ rb_mgc_arguments_t *mga = data;
1098
+ magic_t cookie = mga->magic_object->cookie;
1099
+
1100
+ value = mga->parameter.value;
1101
+
1102
+ mga->status = magic_setparam_wrapper(cookie,
1103
+ mga->parameter.tag,
1104
+ &value);
972
1105
 
973
- value = ma->type.parameter.value;
974
- ma->status = magic_setparam_wrapper(ma->cookie,
975
- ma->type.parameter.tag,
976
- &value);
977
1106
  return (VALUE)NULL;
978
1107
  }
979
1108
 
980
1109
  static inline VALUE
981
1110
  magic_get_flags_internal(void *data)
982
1111
  {
983
- magic_arguments_t *ma = data;
1112
+ int flags;
1113
+ rb_mgc_arguments_t *mga = data;
1114
+ magic_t cookie = mga->magic_object->cookie;
1115
+
1116
+ mga->status = 0;
1117
+
1118
+ flags = magic_getflags_wrapper(cookie);
1119
+ if (flags < 0)
1120
+ mga->status = -1;
1121
+ else
1122
+ mga->flags = flags;
984
1123
 
985
- ma->flags = magic_getflags_wrapper(ma->cookie);
986
1124
  return (VALUE)NULL;
987
1125
  }
988
1126
 
989
1127
  static inline VALUE
990
1128
  magic_set_flags_internal(void *data)
991
1129
  {
992
- magic_arguments_t *ma = data;
1130
+ rb_mgc_arguments_t *mga = data;
1131
+ magic_t cookie = mga->magic_object->cookie;
1132
+
1133
+ mga->status = magic_setflags_wrapper(cookie, mga->flags);
993
1134
 
994
- ma->status = magic_setflags_wrapper(ma->cookie, ma->flags);
995
1135
  return (VALUE)NULL;
996
1136
  }
997
1137
 
@@ -999,18 +1139,21 @@ static inline VALUE
999
1139
  magic_close_internal(void *data)
1000
1140
  {
1001
1141
  magic_library_close(data);
1142
+
1002
1143
  return Qnil;
1003
1144
  }
1004
1145
 
1005
1146
  static inline VALUE
1006
1147
  magic_load_internal(void *data)
1007
1148
  {
1008
- magic_arguments_t *ma = data;
1009
- int old_flags = ma->flags;
1149
+ rb_mgc_arguments_t *mga = data;
1150
+ magic_t cookie = mga->magic_object->cookie;
1151
+ int old_flags = mga->flags;
1152
+
1153
+ NOGVL(nogvl_magic_load, mga);
1010
1154
 
1011
- NOGVL(nogvl_magic_load, ma);
1012
- if (MAGIC_STATUS_CHECK(ma->status < 0))
1013
- magic_setflags_wrapper(ma->cookie, old_flags);
1155
+ if (MAGIC_STATUS_CHECK(mga->status < 0))
1156
+ magic_setflags_wrapper(cookie, old_flags);
1014
1157
 
1015
1158
  return (VALUE)NULL;
1016
1159
  }
@@ -1018,25 +1161,29 @@ magic_load_internal(void *data)
1018
1161
  static inline VALUE
1019
1162
  magic_load_buffers_internal(void *data)
1020
1163
  {
1021
- magic_arguments_t *ma = data;
1164
+ rb_mgc_arguments_t *mga = data;
1165
+ magic_t cookie = mga->magic_object->cookie;
1166
+
1167
+ mga->status = magic_load_buffers_wrapper(cookie,
1168
+ mga->buffers.pointers,
1169
+ mga->buffers.sizes,
1170
+ mga->buffers.count,
1171
+ mga->flags);
1022
1172
 
1023
- ma->status = magic_load_buffers_wrapper(ma->cookie,
1024
- ma->type.buffers.pointers,
1025
- ma->type.buffers.sizes,
1026
- ma->type.buffers.count,
1027
- ma->flags);
1028
1173
  return (VALUE)NULL;
1029
1174
  }
1030
1175
 
1031
1176
  static inline VALUE
1032
1177
  magic_compile_internal(void *data)
1033
1178
  {
1034
- magic_arguments_t *ma = data;
1035
- int old_flags = ma->flags;
1179
+ rb_mgc_arguments_t *mga = data;
1180
+ magic_t cookie = mga->magic_object->cookie;
1181
+ int old_flags = mga->flags;
1036
1182
 
1037
- NOGVL(nogvl_magic_compile, ma);
1038
- if (MAGIC_STATUS_CHECK(ma->status < 0))
1039
- magic_setflags_wrapper(ma->cookie, old_flags);
1183
+ NOGVL(nogvl_magic_compile, mga);
1184
+
1185
+ if (MAGIC_STATUS_CHECK(mga->status < 0))
1186
+ magic_setflags_wrapper(cookie, old_flags);
1040
1187
 
1041
1188
  return (VALUE)NULL;
1042
1189
  }
@@ -1044,12 +1191,14 @@ magic_compile_internal(void *data)
1044
1191
  static inline VALUE
1045
1192
  magic_check_internal(void *data)
1046
1193
  {
1047
- magic_arguments_t *ma = data;
1048
- int old_flags = ma->flags;
1194
+ rb_mgc_arguments_t *mga = data;
1195
+ magic_t cookie = mga->magic_object->cookie;
1196
+ int old_flags = mga->flags;
1197
+
1198
+ NOGVL(nogvl_magic_check, mga);
1049
1199
 
1050
- NOGVL(nogvl_magic_check, ma);
1051
- if (MAGIC_STATUS_CHECK(ma->status < 0))
1052
- magic_setflags_wrapper(ma->cookie, old_flags);
1200
+ if (MAGIC_STATUS_CHECK(mga->status < 0))
1201
+ magic_setflags_wrapper(cookie, old_flags);
1053
1202
 
1054
1203
  return (VALUE)NULL;
1055
1204
  }
@@ -1057,23 +1206,26 @@ magic_check_internal(void *data)
1057
1206
  static VALUE
1058
1207
  magic_file_internal(void *data)
1059
1208
  {
1060
- magic_arguments_t *ma = data;
1061
- int old_flags = ma->flags;
1062
- int restore_flags;
1063
1209
  int local_errno;
1210
+ int restore_flags = 0;
1211
+ rb_mgc_arguments_t *mga = data;
1212
+ rb_mgc_object_t *mgc = mga->magic_object;
1213
+ magic_t cookie = mgc->cookie;
1214
+ int old_flags = mga->flags;
1064
1215
 
1065
- if (ma->stop_on_errors)
1066
- ma->flags |= MAGIC_ERROR;
1216
+ if (mgc->stop_on_errors)
1217
+ mga->flags |= MAGIC_ERROR;
1067
1218
 
1068
- if (ma->flags & MAGIC_CONTINUE)
1069
- ma->flags |= MAGIC_RAW;
1219
+ if (mga->flags & MAGIC_CONTINUE)
1220
+ mga->flags |= MAGIC_RAW;
1070
1221
 
1071
- restore_flags = old_flags != ma->flags;
1222
+ if (old_flags != mga->flags)
1223
+ restore_flags = 1;
1072
1224
 
1073
1225
  if (restore_flags)
1074
- magic_setflags_wrapper(ma->cookie, ma->flags);
1226
+ magic_setflags_wrapper(cookie, mga->flags);
1075
1227
 
1076
- NOGVL(nogvl_magic_file, ma);
1228
+ NOGVL(nogvl_magic_file, mga);
1077
1229
  local_errno = errno;
1078
1230
  /*
1079
1231
  * The Magic library often does not correctly report errors,
@@ -1082,11 +1234,11 @@ magic_file_internal(void *data)
1082
1234
  * Magic library itself, and if that does not work, then from
1083
1235
  * the saved errno value.
1084
1236
  */
1085
- if (magic_errno_wrapper(ma->cookie) || local_errno)
1086
- ma->status = -1;
1237
+ if (magic_errno_wrapper(cookie) || local_errno)
1238
+ mga->status = -1;
1087
1239
 
1088
1240
  if (restore_flags)
1089
- magic_setflags_wrapper(ma->cookie, old_flags);
1241
+ magic_setflags_wrapper(cookie, old_flags);
1090
1242
 
1091
1243
  return (VALUE)NULL;
1092
1244
  }
@@ -1094,27 +1246,29 @@ magic_file_internal(void *data)
1094
1246
  static VALUE
1095
1247
  magic_buffer_internal(void *data)
1096
1248
  {
1097
- magic_arguments_t *ma = data;
1098
- int old_flags = ma->flags;
1099
- int restore_flags;
1249
+ int restore_flags = 0;
1250
+ rb_mgc_arguments_t *mga = data;
1251
+ magic_t cookie = mga->magic_object->cookie;
1252
+ int old_flags = mga->flags;
1100
1253
 
1101
- if (ma->flags & MAGIC_CONTINUE)
1102
- ma->flags |= MAGIC_RAW;
1254
+ if (mga->flags & MAGIC_CONTINUE)
1255
+ mga->flags |= MAGIC_RAW;
1103
1256
 
1104
- restore_flags = old_flags != ma->flags;
1257
+ if (old_flags != mga->flags)
1258
+ restore_flags = 1;
1105
1259
 
1106
1260
  if (restore_flags)
1107
- magic_setflags_wrapper(ma->cookie, ma->flags);
1261
+ magic_setflags_wrapper(cookie, mga->flags);
1108
1262
 
1109
- ma->result = magic_buffer_wrapper(ma->cookie,
1110
- (const void *)ma->type.buffers.pointers,
1111
- (size_t)ma->type.buffers.sizes,
1112
- ma->flags);
1263
+ mga->result = magic_buffer_wrapper(cookie,
1264
+ (const void *)mga->buffers.pointers,
1265
+ (size_t)mga->buffers.sizes,
1266
+ mga->flags);
1113
1267
 
1114
- ma->status = !ma->result ? -1 : 0;
1268
+ mga->status = !mga->result ? -1 : 0;
1115
1269
 
1116
1270
  if (restore_flags)
1117
- magic_setflags_wrapper(ma->cookie, old_flags);
1271
+ magic_setflags_wrapper(cookie, old_flags);
1118
1272
 
1119
1273
  return (VALUE)NULL;
1120
1274
  }
@@ -1122,128 +1276,168 @@ magic_buffer_internal(void *data)
1122
1276
  static VALUE
1123
1277
  magic_descriptor_internal(void *data)
1124
1278
  {
1125
- magic_arguments_t *ma = data;
1126
- int old_flags = ma->flags;
1127
- int restore_flags;
1279
+ int restore_flags = 0;
1280
+ rb_mgc_arguments_t *mga = data;
1281
+ magic_t cookie = mga->magic_object->cookie;
1282
+ int old_flags = mga->flags;
1128
1283
 
1129
- if (ma->flags & MAGIC_CONTINUE)
1130
- ma->flags |= MAGIC_RAW;
1284
+ if (mga->flags & MAGIC_CONTINUE)
1285
+ mga->flags |= MAGIC_RAW;
1131
1286
 
1132
- restore_flags = old_flags != ma->flags;
1287
+ if (old_flags != mga->flags)
1288
+ restore_flags = 1;
1133
1289
 
1134
1290
  if (restore_flags)
1135
- magic_setflags_wrapper(ma->cookie, ma->flags);
1291
+ magic_setflags_wrapper(cookie, mga->flags);
1136
1292
 
1137
- NOGVL(nogvl_magic_descriptor, ma);
1293
+ NOGVL(nogvl_magic_descriptor, mga);
1138
1294
 
1139
1295
  if (restore_flags)
1140
- magic_setflags_wrapper(ma->cookie, old_flags);
1296
+ magic_setflags_wrapper(cookie, old_flags);
1141
1297
 
1142
1298
  return (VALUE)NULL;
1143
1299
  }
1144
1300
 
1301
+ static inline void*
1302
+ magic_library_open(void)
1303
+ {
1304
+ magic_t cookie;
1305
+
1306
+ cookie = magic_open_wrapper(MAGIC_NONE);
1307
+ if (!cookie) {
1308
+ errno = ENOMEM;
1309
+ return NULL;
1310
+ }
1311
+
1312
+ return cookie;
1313
+ }
1314
+
1315
+ static inline void
1316
+ magic_library_close(void *data)
1317
+ {
1318
+ rb_mgc_object_t *mgc = data;
1319
+
1320
+ assert(mgc != NULL &&
1321
+ "Must be a valid pointer to `rb_mgc_object_t' type");
1322
+
1323
+ if (mgc->cookie)
1324
+ magic_close_wrapper(mgc->cookie);
1325
+
1326
+ mgc->cookie = NULL;
1327
+ }
1328
+
1145
1329
  static VALUE
1146
1330
  magic_allocate(VALUE klass)
1147
1331
  {
1148
1332
  int local_errno;
1149
- magic_object_t *mo;
1333
+ rb_mgc_object_t *mgc;
1150
1334
 
1151
- mo = (magic_object_t *)ruby_xmalloc(sizeof(magic_object_t));
1335
+ mgc = RB_ALLOC(rb_mgc_object_t);
1152
1336
  local_errno = ENOMEM;
1153
1337
 
1154
- if (!mo) {
1338
+ if (!mgc) {
1155
1339
  errno = local_errno;
1156
1340
  MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError,
1157
1341
  local_errno,
1158
1342
  E_NOT_ENOUGH_MEMORY);
1159
1343
  }
1160
1344
 
1161
- mo->cookie = NULL;
1162
- mo->mutex = Qundef;
1163
- mo->database_loaded = 0;
1164
- mo->stop_on_errors = 0;
1345
+ mgc->cookie = NULL;
1346
+ mgc->mutex = Qundef;
1347
+ mgc->database_loaded = 0;
1348
+ mgc->stop_on_errors = 0;
1165
1349
 
1166
- mo->cookie = magic_open_wrapper(MAGIC_NONE);
1167
- local_errno = ENOMEM;
1350
+ mgc->cookie = magic_library_open();
1351
+ local_errno = errno;
1168
1352
 
1169
- if (!mo->cookie) {
1170
- ruby_xfree(mo);
1171
- mo = NULL;
1353
+ if (!mgc->cookie) {
1354
+ ruby_xfree(mgc);
1355
+ mgc = NULL;
1172
1356
  errno = local_errno;
1173
1357
  MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError,
1174
1358
  local_errno,
1175
1359
  E_MAGIC_LIBRARY_INITIALIZE);
1176
1360
  }
1177
1361
 
1178
- return Data_Wrap_Struct(klass, magic_mark, magic_free, mo);
1362
+ return TypedData_Wrap_Struct(klass, &rb_mgc_type, mgc);
1179
1363
  }
1180
1364
 
1181
1365
  static inline void
1182
- magic_library_close(void *data)
1366
+ magic_mark(void *data)
1183
1367
  {
1184
- magic_object_t *mo = data;
1368
+ rb_mgc_object_t *mgc = data;
1185
1369
 
1186
- assert(mo != NULL && \
1187
- "Must be a valid pointer to `magic_object_t' type");
1370
+ assert(mgc != NULL &&
1371
+ "Must be a valid pointer to `rb_mgc_object_t' type");
1188
1372
 
1189
- if (mo->cookie)
1190
- magic_close_wrapper(mo->cookie);
1191
-
1192
- mo->cookie = NULL;
1373
+ MAGIC_GC_MARK(mgc->mutex);
1193
1374
  }
1194
1375
 
1195
1376
  static inline void
1196
- magic_mark(void *data)
1377
+ magic_free(void *data)
1197
1378
  {
1198
- magic_object_t *mo = data;
1379
+ rb_mgc_object_t *mgc = data;
1199
1380
 
1200
- assert(mo != NULL && \
1201
- "Must be a valid pointer to `magic_object_t' type");
1381
+ assert(mgc != NULL &&
1382
+ "Must be a valid pointer to `rb_mgc_object_t' type");
1202
1383
 
1203
- rb_gc_mark(mo->mutex);
1384
+ if (mgc->cookie)
1385
+ magic_library_close(data);
1386
+
1387
+ mgc->cookie = NULL;
1388
+ mgc->mutex = Qundef;
1389
+
1390
+ ruby_xfree(mgc);
1204
1391
  }
1205
1392
 
1206
- static inline void
1207
- magic_free(void *data)
1393
+ static inline size_t
1394
+ magic_size(const void *data)
1208
1395
  {
1209
- magic_object_t *mo = data;
1396
+ const rb_mgc_object_t *mgc = data;
1210
1397
 
1211
- assert(mo != NULL && \
1212
- "Must be a valid pointer to `magic_object_t' type");
1398
+ assert(mgc != NULL &&
1399
+ "Must be a valid pointer to `rb_mgc_object_t' type");
1213
1400
 
1214
- if (mo->cookie)
1215
- magic_library_close(data);
1401
+ return sizeof(*mgc);
1402
+ }
1216
1403
 
1217
- mo->cookie = NULL;
1218
- mo->mutex = Qundef;
1404
+ #if defined(HAVE_RUBY_GC_COMPACT)
1405
+ static inline void
1406
+ magic_compact(void *data)
1407
+ {
1408
+ rb_mgc_object_t *mgc = data;
1409
+
1410
+ assert(mgc != NULL &&
1411
+ "Must be a valid pointer to `rb_mgc_object_t' type");
1219
1412
 
1220
- ruby_xfree(mo);
1413
+ mgc->mutex = rb_gc_location(mgc->mutex);
1221
1414
  }
1415
+ #endif /* HAVE_RUBY_GC_COMPACT */
1222
1416
 
1223
1417
  static inline VALUE
1224
1418
  magic_exception_wrapper(VALUE value)
1225
1419
  {
1226
- magic_exception_t *e = (struct magic_exception *)value;
1420
+ rb_mgc_error_t *mge = (rb_mgc_error_t *)value;
1227
1421
 
1228
- return rb_exc_new2(e->klass, e->magic_error);
1422
+ return rb_exc_new2(mge->klass, mge->magic_error);
1229
1423
  }
1230
1424
 
1231
1425
  static VALUE
1232
1426
  magic_exception(void *data)
1233
1427
  {
1234
- magic_exception_t *e = data;
1235
1428
  int exception = 0;
1429
+ rb_mgc_error_t *mge = data;
1236
1430
  VALUE object = Qundef;
1237
1431
 
1238
- assert(e != NULL && \
1239
- "Must be a valid pointer to `magic_exception_t' type");
1432
+ assert(mge != NULL &&
1433
+ "Must be a valid pointer to `rb_mgc_error_t' type");
1240
1434
 
1241
- object = rb_protect(magic_exception_wrapper, (VALUE)e, &exception);
1435
+ object = rb_protect(magic_exception_wrapper, (VALUE)mge, &exception);
1242
1436
 
1243
1437
  if (exception)
1244
1438
  rb_jump_tag(exception);
1245
1439
 
1246
- rb_iv_set(object, "@errno", INT2NUM(e->magic_errno));
1440
+ rb_iv_set(object, "@errno", INT2NUM(mge->magic_errno));
1247
1441
  RB_GC_GUARD(object);
1248
1442
 
1249
1443
  return object;
@@ -1252,51 +1446,56 @@ magic_exception(void *data)
1252
1446
  static inline VALUE
1253
1447
  magic_generic_error(VALUE klass, int magic_errno, const char *magic_error)
1254
1448
  {
1255
- magic_exception_t e;
1449
+ rb_mgc_error_t mge;
1256
1450
 
1257
- e.magic_errno = magic_errno;
1258
- e.magic_error = magic_error;
1259
- e.klass = klass;
1451
+ mge = (rb_mgc_error_t) {
1452
+ .klass = klass,
1453
+ .magic_errno = magic_errno,
1454
+ .magic_error = magic_error,
1455
+ };
1260
1456
 
1261
- return magic_exception(&e);
1457
+ return magic_exception(&mge);
1262
1458
  }
1263
1459
 
1264
1460
  static VALUE
1265
1461
  magic_library_error(VALUE klass, void *data)
1266
1462
  {
1267
- magic_exception_t e;
1463
+ rb_mgc_error_t mge;
1268
1464
  const char *message = NULL;
1269
1465
  const char *empty = "(null)";
1270
1466
  magic_t cookie = data;
1271
1467
 
1272
1468
  UNUSED(empty);
1273
1469
 
1274
- assert(cookie != NULL && \
1470
+ assert(cookie != NULL &&
1275
1471
  "Must be a valid pointer to `magic_t' type");
1276
1472
 
1277
- e.magic_errno = -1;
1278
- e.magic_error = error(E_UNKNOWN);
1279
- e.klass = klass;
1473
+ mge = (rb_mgc_error_t) {
1474
+ .klass = klass,
1475
+ .magic_errno = -1,
1476
+ .magic_error = MAGIC_ERRORS(E_UNKNOWN),
1477
+ };
1280
1478
 
1281
1479
  message = magic_error_wrapper(cookie);
1282
1480
  if (message) {
1283
- e.magic_errno = magic_errno_wrapper(cookie);
1284
- e.magic_error = message;
1481
+ mge.magic_errno = magic_errno_wrapper(cookie);
1482
+ mge.magic_error = message;
1285
1483
  }
1286
1484
 
1287
- assert(strncmp(e.magic_error, empty, strlen(empty)) != 0 && \
1485
+ assert(strncmp(mge.magic_error, empty, strlen(empty)) != 0 &&
1288
1486
  "Empty or invalid error message");
1289
1487
 
1290
- return magic_exception(&e);
1488
+ return magic_exception(&mge);
1291
1489
  }
1292
1490
 
1293
1491
  VALUE
1294
1492
  magic_lock(VALUE object, VALUE(*function)(ANYARGS), void *data)
1295
1493
  {
1296
- magic_object_t *mo;
1494
+ rb_mgc_object_t *mgc;
1495
+
1496
+ MAGIC_OBJECT(object, mgc);
1297
1497
 
1298
- MAGIC_OBJECT(mo);
1299
- rb_funcall(mo->mutex, rb_intern("lock"), 0);
1498
+ rb_funcall(mgc->mutex, rb_intern("lock"), 0);
1300
1499
 
1301
1500
  return rb_ensure(function, (VALUE)data, magic_unlock, object);
1302
1501
  }
@@ -1304,10 +1503,11 @@ magic_lock(VALUE object, VALUE(*function)(ANYARGS), void *data)
1304
1503
  VALUE
1305
1504
  magic_unlock(VALUE object)
1306
1505
  {
1307
- magic_object_t *mo;
1506
+ rb_mgc_object_t *mgc;
1308
1507
 
1309
- MAGIC_OBJECT(mo);
1310
- rb_funcall(mo->mutex, rb_intern("unlock"), 0);
1508
+ MAGIC_OBJECT(object, mgc);
1509
+
1510
+ rb_funcall(mgc->mutex, rb_intern("unlock"), 0);
1311
1511
 
1312
1512
  return Qnil;
1313
1513
  }
@@ -1315,13 +1515,12 @@ magic_unlock(VALUE object)
1315
1515
  static VALUE
1316
1516
  magic_return(void *data)
1317
1517
  {
1318
- magic_arguments_t *ma = data;
1518
+ rb_mgc_arguments_t *mga = data;
1319
1519
  const char *unknown = "???";
1320
1520
  VALUE separator = Qundef;
1321
- VALUE array = Qundef;
1322
- VALUE string = Qundef;
1521
+ VALUE array, string;
1323
1522
 
1324
- string = CSTR2RVAL(ma->result);
1523
+ string = CSTR2RVAL(mga->result);
1325
1524
  RB_GC_GUARD(string);
1326
1525
 
1327
1526
  /*
@@ -1329,15 +1528,15 @@ magic_return(void *data)
1329
1528
  * when the CONTINUE flag is set causing all valid matches found by the
1330
1529
  * Magic library to be returned.
1331
1530
  */
1332
- if (ma->flags & MAGIC_CONTINUE)
1531
+ if (mga->flags & MAGIC_CONTINUE)
1333
1532
  separator = CSTR2RVAL(MAGIC_CONTINUE_SEPARATOR);
1334
1533
 
1335
- if (ma->flags & MAGIC_EXTENSION) {
1534
+ if (mga->flags & MAGIC_EXTENSION) {
1336
1535
  /*
1337
1536
  * A possible I/O-related error has occurred, and there is very
1338
1537
  * little sense processing the results, so return string as-is.
1339
1538
  */
1340
- if (ma->status < 0)
1539
+ if (mga->status < 0)
1341
1540
  return string;
1342
1541
  /*
1343
1542
  * A number of Magic flags that support primarily files e.g.,
@@ -1346,31 +1545,37 @@ magic_return(void *data)
1346
1545
  * return an empty string, to indicate lack of results, rather
1347
1546
  * than a confusing string consisting of three questions marks.
1348
1547
  */
1349
- if (strncmp(ma->result, unknown, strlen(unknown)) == 0)
1548
+ if (strncmp(mga->result, unknown, strlen(unknown)) == 0)
1350
1549
  return CSTR2RVAL("");
1351
1550
 
1352
1551
  separator = CSTR2RVAL(MAGIC_EXTENSION_SEPARATOR);
1353
1552
  }
1354
1553
 
1355
- if (ma->flags & (MAGIC_CONTINUE | MAGIC_EXTENSION)) {
1554
+ RB_GC_GUARD(separator);
1555
+
1556
+ if (mga->flags & (MAGIC_CONTINUE | MAGIC_EXTENSION)) {
1356
1557
  array = magic_split(string, separator);
1357
1558
  RB_GC_GUARD(array);
1358
- return (RARRAY_LEN(array) > 1) ? array : magic_shift(array);
1559
+
1560
+ if (RARRAY_LEN(array) > 1)
1561
+ return magic_strip_array(array);
1562
+
1563
+ string = magic_shift(array);
1359
1564
  }
1360
1565
 
1361
- return string;
1566
+ return magic_strip(string);
1362
1567
  }
1363
1568
 
1364
1569
  static inline int
1365
- magic_flags(VALUE object)
1570
+ magic_get_flags(VALUE object)
1366
1571
  {
1367
1572
  return NUM2INT(rb_ivar_get(object, id_at_flags));
1368
1573
  }
1369
1574
 
1370
- static inline int
1371
- magic_set_flags(VALUE object, VALUE value)
1575
+ static inline void
1576
+ magic_set_flags(VALUE object, int flags)
1372
1577
  {
1373
- return NUM2INT(rb_ivar_set(object, id_at_flags, value));
1578
+ rb_ivar_set(object, id_at_flags, INT2NUM(flags));
1374
1579
  }
1375
1580
 
1376
1581
  static inline VALUE
@@ -1379,6 +1584,19 @@ magic_set_paths(VALUE object, VALUE value)
1379
1584
  return rb_ivar_set(object, id_at_paths, value);
1380
1585
  }
1381
1586
 
1587
+ static const rb_data_type_t rb_mgc_type = {
1588
+ .wrap_struct_name = "magic",
1589
+ .function = {
1590
+ .dmark = magic_mark,
1591
+ .dfree = magic_free,
1592
+ .dsize = magic_size,
1593
+ #if defined(HAVE_RUBY_GC_COMPACT)
1594
+ .dcompact = magic_compact,
1595
+ #endif /* HAVE_RUBY_GC_COMPACT */
1596
+ },
1597
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
1598
+ };
1599
+
1382
1600
  void
1383
1601
  Init_magic(void)
1384
1602
  {