ruby-magic 0.3.0 → 0.5.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.
@@ -8,54 +8,71 @@ static int rb_mgc_do_not_auto_load;
8
8
  static int rb_mgc_do_not_stop_on_error;
9
9
  static int rb_mgc_warning;
10
10
 
11
- ID id_at_flags;
12
- ID id_at_paths;
11
+ static ID id_at_flags;
12
+ static ID id_at_paths;
13
13
 
14
- VALUE rb_cMagic = Qundef;
14
+ static VALUE rb_cMagic;
15
15
 
16
- VALUE rb_mgc_eError = Qundef;
17
- VALUE rb_mgc_eMagicError = Qundef;
18
- VALUE rb_mgc_eLibraryError = Qundef;
19
- VALUE rb_mgc_eParameterError = Qundef;
20
- VALUE rb_mgc_eFlagsError = Qundef;
21
- 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
+ };
485
537
 
486
- ma.flags = NUM2INT(value);
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);
487
550
 
488
- MAGIC_SYNCHRONIZED(magic_set_flags_internal, &ma);
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
+ }
555
+
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,16 +835,18 @@ 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
 
842
+ UNUSED(empty);
843
+
745
844
  if (NIL_P(value))
746
845
  goto error;
747
846
 
748
847
  MAGIC_CHECK_OPEN(object);
749
848
  MAGIC_CHECK_LOADED(object);
750
- MAGIC_COOKIE(mo, ma.cookie);
849
+ MAGIC_OBJECT(object, mgc);
751
850
 
752
851
  if (rb_respond_to(value, rb_intern("to_io")))
753
852
  return rb_mgc_descriptor(object, value);
@@ -756,12 +855,16 @@ rb_mgc_file(VALUE object, VALUE value)
756
855
  if (NIL_P(value))
757
856
  goto error;
758
857
 
759
- ma.stop_on_errors = mo->stop_on_errors;
760
- ma.flags = magic_flags(object);
761
- 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
+ };
762
865
 
763
- MAGIC_SYNCHRONIZED(magic_file_internal, &ma);
764
- if (!ma.result) {
866
+ MAGIC_SYNCHRONIZED(magic_file_internal, &mga);
867
+ if (mga.status < 0 && !mga.result) {
765
868
  /*
766
869
  * Handle the case when the "ERROR" flag is set regardless of the
767
870
  * current version of the underlying Magic library.
@@ -775,15 +878,15 @@ rb_mgc_file(VALUE object, VALUE value)
775
878
  * This is an attempt to mitigate the problem and correct it to achieve
776
879
  * the desired behavior as per the standards.
777
880
  */
778
- if (mo->stop_on_errors || (ma.flags & MAGIC_ERROR))
779
- MAGIC_LIBRARY_ERROR(ma.cookie);
780
- else
781
- ma.result = magic_error_wrapper(ma.cookie);
881
+ if (mgc->stop_on_errors || (mga.flags & MAGIC_ERROR))
882
+ MAGIC_LIBRARY_ERROR(mgc);
883
+
884
+ mga.result = magic_error_wrapper(mgc->cookie);
782
885
  }
783
- if (!ma.result)
886
+ if (!mga.result)
784
887
  MAGIC_GENERIC_ERROR(rb_mgc_eMagicError, EINVAL, E_UNKNOWN);
785
888
 
786
- assert(ma.result != NULL && \
889
+ assert(mga.result != NULL &&
787
890
  "Must be a valid pointer to `const char' type");
788
891
 
789
892
  /*
@@ -792,10 +895,10 @@ rb_mgc_file(VALUE object, VALUE value)
792
895
  * string instead. Often this would indicate that an older version of the
793
896
  * Magic library is in use.
794
897
  */
795
- assert(strncmp(ma.result, empty, strlen(empty)) != 0 && \
898
+ assert(strncmp(mga.result, empty, strlen(empty)) != 0 &&
796
899
  "Empty or invalid result");
797
900
 
798
- return magic_return(&ma);
901
+ return magic_return(&mga);
799
902
  error:
800
903
  MAGIC_ARGUMENT_TYPE_ERROR(value, "String or IO-like object");
801
904
  }
@@ -809,28 +912,34 @@ error:
809
912
  VALUE
810
913
  rb_mgc_buffer(VALUE object, VALUE value)
811
914
  {
812
- magic_object_t *mo;
813
- magic_arguments_t ma;
915
+ rb_mgc_object_t *mgc;
916
+ rb_mgc_arguments_t mga;
814
917
 
815
918
  MAGIC_CHECK_STRING_TYPE(value);
919
+
816
920
  MAGIC_CHECK_OPEN(object);
817
921
  MAGIC_CHECK_LOADED(object);
818
- MAGIC_COOKIE(mo, ma.cookie);
922
+ MAGIC_OBJECT(object, mgc);
819
923
 
820
924
  StringValue(value);
821
925
 
822
- ma.flags = magic_flags(object);
823
- ma.type.buffers.pointers = (void **)RSTRING_PTR(value);
824
- 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
+ };
825
934
 
826
- MAGIC_SYNCHRONIZED(magic_buffer_internal, &ma);
827
- if (!ma.result)
828
- MAGIC_LIBRARY_ERROR(ma.cookie);
935
+ MAGIC_SYNCHRONIZED(magic_buffer_internal, &mga);
936
+ if (mga.status < 0)
937
+ MAGIC_LIBRARY_ERROR(mgc);
829
938
 
830
- assert(ma.result != NULL && \
939
+ assert(mga.result != NULL &&
831
940
  "Must be a valid pointer to `const char' type");
832
941
 
833
- return magic_return(&ma);
942
+ return magic_return(&mga);
834
943
  }
835
944
 
836
945
  /*
@@ -844,34 +953,40 @@ VALUE
844
953
  rb_mgc_descriptor(VALUE object, VALUE value)
845
954
  {
846
955
  int local_errno;
847
- magic_object_t *mo;
848
- magic_arguments_t ma;
956
+ rb_mgc_object_t *mgc;
957
+ rb_mgc_arguments_t mga;
849
958
 
850
959
  if (rb_respond_to(value, rb_intern("to_io")))
851
960
  value = INT2NUM(magic_fileno(value));
852
961
 
853
962
  MAGIC_CHECK_INTEGER_TYPE(value);
963
+
854
964
  MAGIC_CHECK_OPEN(object);
855
965
  MAGIC_CHECK_LOADED(object);
856
- MAGIC_COOKIE(mo, ma.cookie);
966
+ MAGIC_OBJECT(object, mgc);
857
967
 
858
- ma.flags = magic_flags(object);
859
- 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
+ };
860
975
 
861
- MAGIC_SYNCHRONIZED(magic_descriptor_internal, &ma);
976
+ MAGIC_SYNCHRONIZED(magic_descriptor_internal, &mga);
862
977
  local_errno = errno;
863
978
 
864
- if (!ma.result) {
979
+ if (mga.status < 0) {
865
980
  if (local_errno == EBADF)
866
981
  rb_raise(rb_eIOError, "Bad file descriptor");
867
982
 
868
- MAGIC_LIBRARY_ERROR(ma.cookie);
983
+ MAGIC_LIBRARY_ERROR(mgc);
869
984
  }
870
985
 
871
- assert(ma.result != NULL && \
986
+ assert(mga.result != NULL &&
872
987
  "Must be a valid pointer to `const char' type");
873
988
 
874
- return magic_return(&ma);
989
+ return magic_return(&mga);
875
990
  }
876
991
 
877
992
  /*
@@ -893,55 +1008,69 @@ rb_mgc_version(RB_UNUSED_VAR(VALUE object))
893
1008
  static inline void*
894
1009
  nogvl_magic_load(void *data)
895
1010
  {
896
- 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);
897
1017
 
898
- ma->status = magic_load_wrapper(ma->cookie,
899
- ma->type.file.path,
900
- ma->flags);
901
1018
  return NULL;
902
1019
  }
903
1020
 
904
1021
  static inline void*
905
1022
  nogvl_magic_compile(void *data)
906
1023
  {
907
- 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);
908
1030
 
909
- ma->status = magic_compile_wrapper(ma->cookie,
910
- ma->type.file.path,
911
- ma->flags);
912
1031
  return NULL;
913
1032
  }
914
1033
 
915
1034
  static inline void*
916
1035
  nogvl_magic_check(void *data)
917
1036
  {
918
- 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);
919
1043
 
920
- ma->status = magic_check_wrapper(ma->cookie,
921
- ma->type.file.path,
922
- ma->flags);
923
1044
  return NULL;
924
1045
  }
925
1046
 
926
1047
  static inline void*
927
1048
  nogvl_magic_file(void *data)
928
1049
  {
929
- magic_arguments_t *ma = data;
1050
+ rb_mgc_arguments_t *mga = data;
1051
+ magic_t cookie = mga->magic_object->cookie;
1052
+
1053
+ mga->result = magic_file_wrapper(cookie,
1054
+ mga->file.path,
1055
+ mga->flags);
1056
+
1057
+ mga->status = !mga->result ? -1 : 0;
930
1058
 
931
- ma->result = magic_file_wrapper(ma->cookie,
932
- ma->type.file.path,
933
- ma->flags);
934
1059
  return NULL;
935
1060
  }
936
1061
 
937
1062
  static inline void*
938
1063
  nogvl_magic_descriptor(void *data)
939
1064
  {
940
- 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);
1071
+
1072
+ mga->status = !mga->result ? -1 : 0;
941
1073
 
942
- ma->result = magic_descriptor_wrapper(ma->cookie,
943
- ma->type.file.fd,
944
- ma->flags);
945
1074
  return NULL;
946
1075
  }
947
1076
 
@@ -949,12 +1078,15 @@ static inline VALUE
949
1078
  magic_get_parameter_internal(void *data)
950
1079
  {
951
1080
  size_t value;
952
- 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;
953
1089
 
954
- ma->status = magic_getparam_wrapper(ma->cookie,
955
- ma->type.parameter.tag,
956
- &value);
957
- ma->type.parameter.value = value;
958
1090
  return (VALUE)NULL;
959
1091
  }
960
1092
 
@@ -962,30 +1094,44 @@ static inline VALUE
962
1094
  magic_set_parameter_internal(void *data)
963
1095
  {
964
1096
  size_t value;
965
- 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);
966
1105
 
967
- value = ma->type.parameter.value;
968
- ma->status = magic_setparam_wrapper(ma->cookie,
969
- ma->type.parameter.tag,
970
- &value);
971
1106
  return (VALUE)NULL;
972
1107
  }
973
1108
 
974
1109
  static inline VALUE
975
1110
  magic_get_flags_internal(void *data)
976
1111
  {
977
- 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;
978
1123
 
979
- ma->flags = magic_getflags_wrapper(ma->cookie);
980
1124
  return (VALUE)NULL;
981
1125
  }
982
1126
 
983
1127
  static inline VALUE
984
1128
  magic_set_flags_internal(void *data)
985
1129
  {
986
- 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);
987
1134
 
988
- ma->status = magic_setflags_wrapper(ma->cookie, ma->flags);
989
1135
  return (VALUE)NULL;
990
1136
  }
991
1137
 
@@ -993,62 +1139,93 @@ static inline VALUE
993
1139
  magic_close_internal(void *data)
994
1140
  {
995
1141
  magic_library_close(data);
1142
+
996
1143
  return Qnil;
997
1144
  }
998
1145
 
999
1146
  static inline VALUE
1000
1147
  magic_load_internal(void *data)
1001
1148
  {
1002
- return (VALUE)NOGVL(nogvl_magic_load, data);
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);
1154
+
1155
+ if (MAGIC_STATUS_CHECK(mga->status < 0))
1156
+ magic_setflags_wrapper(cookie, old_flags);
1157
+
1158
+ return (VALUE)NULL;
1003
1159
  }
1004
1160
 
1005
1161
  static inline VALUE
1006
1162
  magic_load_buffers_internal(void *data)
1007
1163
  {
1008
- 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);
1009
1172
 
1010
- ma->status = magic_load_buffers_wrapper(ma->cookie,
1011
- ma->type.buffers.pointers,
1012
- ma->type.buffers.sizes,
1013
- ma->type.buffers.count,
1014
- ma->flags);
1015
1173
  return (VALUE)NULL;
1016
1174
  }
1017
1175
 
1018
1176
  static inline VALUE
1019
1177
  magic_compile_internal(void *data)
1020
1178
  {
1021
- return (VALUE)NOGVL(nogvl_magic_compile, data);
1179
+ rb_mgc_arguments_t *mga = data;
1180
+ magic_t cookie = mga->magic_object->cookie;
1181
+ int old_flags = mga->flags;
1182
+
1183
+ NOGVL(nogvl_magic_compile, mga);
1184
+
1185
+ if (MAGIC_STATUS_CHECK(mga->status < 0))
1186
+ magic_setflags_wrapper(cookie, old_flags);
1187
+
1188
+ return (VALUE)NULL;
1022
1189
  }
1023
1190
 
1024
1191
  static inline VALUE
1025
1192
  magic_check_internal(void *data)
1026
1193
  {
1027
- return (VALUE)NOGVL(nogvl_magic_check, data);
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);
1199
+
1200
+ if (MAGIC_STATUS_CHECK(mga->status < 0))
1201
+ magic_setflags_wrapper(cookie, old_flags);
1202
+
1203
+ return (VALUE)NULL;
1028
1204
  }
1029
1205
 
1030
1206
  static VALUE
1031
1207
  magic_file_internal(void *data)
1032
1208
  {
1033
1209
  int local_errno;
1034
- int old_flags = 0;
1035
1210
  int restore_flags = 0;
1036
- magic_arguments_t *ma = data;
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;
1037
1215
 
1038
- if (ma->stop_on_errors) {
1039
- old_flags = ma->flags;
1040
- ma->flags |= MAGIC_ERROR;
1041
- restore_flags = 1;
1042
- }
1043
- if (ma->flags & MAGIC_CONTINUE) {
1044
- old_flags = ma->flags;
1045
- ma->flags |= MAGIC_RAW;
1216
+ if (mgc->stop_on_errors)
1217
+ mga->flags |= MAGIC_ERROR;
1218
+
1219
+ if (mga->flags & MAGIC_CONTINUE)
1220
+ mga->flags |= MAGIC_RAW;
1221
+
1222
+ if (old_flags != mga->flags)
1046
1223
  restore_flags = 1;
1047
- }
1048
- if (restore_flags && ma->flags)
1049
- magic_setflags_wrapper(ma->cookie, ma->flags);
1050
1224
 
1051
- NOGVL(nogvl_magic_file, ma);
1225
+ if (restore_flags)
1226
+ magic_setflags_wrapper(cookie, mga->flags);
1227
+
1228
+ NOGVL(nogvl_magic_file, mga);
1052
1229
  local_errno = errno;
1053
1230
  /*
1054
1231
  * The Magic library often does not correctly report errors,
@@ -1057,13 +1234,11 @@ magic_file_internal(void *data)
1057
1234
  * Magic library itself, and if that does not work, then from
1058
1235
  * the saved errno value.
1059
1236
  */
1060
- if (magic_errno_wrapper(ma->cookie))
1061
- ma->status = -1;
1062
- else if (local_errno)
1063
- ma->status = -1;
1237
+ if (magic_errno_wrapper(cookie) || local_errno)
1238
+ mga->status = -1;
1064
1239
 
1065
- if (restore_flags && old_flags)
1066
- magic_setflags_wrapper(ma->cookie, old_flags);
1240
+ if (restore_flags)
1241
+ magic_setflags_wrapper(cookie, old_flags);
1067
1242
 
1068
1243
  return (VALUE)NULL;
1069
1244
  }
@@ -1071,24 +1246,29 @@ magic_file_internal(void *data)
1071
1246
  static VALUE
1072
1247
  magic_buffer_internal(void *data)
1073
1248
  {
1074
- int old_flags = 0;
1075
1249
  int restore_flags = 0;
1076
- magic_arguments_t *ma = data;
1250
+ rb_mgc_arguments_t *mga = data;
1251
+ magic_t cookie = mga->magic_object->cookie;
1252
+ int old_flags = mga->flags;
1253
+
1254
+ if (mga->flags & MAGIC_CONTINUE)
1255
+ mga->flags |= MAGIC_RAW;
1077
1256
 
1078
- if (ma->flags & MAGIC_CONTINUE) {
1079
- old_flags = ma->flags;
1080
- ma->flags |= MAGIC_RAW;
1257
+ if (old_flags != mga->flags)
1081
1258
  restore_flags = 1;
1082
- }
1083
- if (restore_flags && ma->flags)
1084
- magic_setflags_wrapper(ma->cookie, ma->flags);
1085
1259
 
1086
- ma->result = magic_buffer_wrapper(ma->cookie,
1087
- (const void *)ma->type.buffers.pointers,
1088
- (size_t)ma->type.buffers.sizes,
1089
- ma->flags);
1090
- if (restore_flags && old_flags)
1091
- magic_setflags_wrapper(ma->cookie, old_flags);
1260
+ if (restore_flags)
1261
+ magic_setflags_wrapper(cookie, mga->flags);
1262
+
1263
+ mga->result = magic_buffer_wrapper(cookie,
1264
+ (const void *)mga->buffers.pointers,
1265
+ (size_t)mga->buffers.sizes,
1266
+ mga->flags);
1267
+
1268
+ mga->status = !mga->result ? -1 : 0;
1269
+
1270
+ if (restore_flags)
1271
+ magic_setflags_wrapper(cookie, old_flags);
1092
1272
 
1093
1273
  return (VALUE)NULL;
1094
1274
  }
@@ -1096,128 +1276,168 @@ magic_buffer_internal(void *data)
1096
1276
  static VALUE
1097
1277
  magic_descriptor_internal(void *data)
1098
1278
  {
1099
- int old_flags = 0;
1100
1279
  int restore_flags = 0;
1101
- magic_arguments_t *ma = data;
1280
+ rb_mgc_arguments_t *mga = data;
1281
+ magic_t cookie = mga->magic_object->cookie;
1282
+ int old_flags = mga->flags;
1102
1283
 
1103
- if (ma->flags & MAGIC_CONTINUE) {
1104
- old_flags = ma->flags;
1105
- ma->flags |= MAGIC_RAW;
1284
+ if (mga->flags & MAGIC_CONTINUE)
1285
+ mga->flags |= MAGIC_RAW;
1286
+
1287
+ if (old_flags != mga->flags)
1106
1288
  restore_flags = 1;
1107
- }
1108
- if (restore_flags && ma->flags)
1109
- magic_setflags_wrapper(ma->cookie, ma->flags);
1110
1289
 
1111
- NOGVL(nogvl_magic_descriptor, ma);
1290
+ if (restore_flags)
1291
+ magic_setflags_wrapper(cookie, mga->flags);
1292
+
1293
+ NOGVL(nogvl_magic_descriptor, mga);
1112
1294
 
1113
- if (restore_flags && old_flags)
1114
- magic_setflags_wrapper(ma->cookie, old_flags);
1295
+ if (restore_flags)
1296
+ magic_setflags_wrapper(cookie, old_flags);
1115
1297
 
1116
1298
  return (VALUE)NULL;
1117
1299
  }
1118
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
+
1119
1329
  static VALUE
1120
1330
  magic_allocate(VALUE klass)
1121
1331
  {
1122
1332
  int local_errno;
1123
- magic_object_t *mo;
1333
+ rb_mgc_object_t *mgc;
1124
1334
 
1125
- mo = (magic_object_t *)ruby_xmalloc(sizeof(magic_object_t));
1335
+ mgc = RB_ALLOC(rb_mgc_object_t);
1126
1336
  local_errno = ENOMEM;
1127
1337
 
1128
- if (!mo) {
1338
+ if (!mgc) {
1129
1339
  errno = local_errno;
1130
1340
  MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError,
1131
1341
  local_errno,
1132
1342
  E_NOT_ENOUGH_MEMORY);
1133
1343
  }
1134
1344
 
1135
- mo->cookie = NULL;
1136
- mo->mutex = Qundef;
1137
- mo->database_loaded = 0;
1138
- mo->stop_on_errors = 0;
1345
+ mgc->cookie = NULL;
1346
+ mgc->mutex = Qundef;
1347
+ mgc->database_loaded = 0;
1348
+ mgc->stop_on_errors = 0;
1139
1349
 
1140
- mo->cookie = magic_open_wrapper(MAGIC_NONE);
1141
- local_errno = ENOMEM;
1350
+ mgc->cookie = magic_library_open();
1351
+ local_errno = errno;
1142
1352
 
1143
- if (!mo->cookie) {
1144
- ruby_xfree(mo);
1145
- mo = NULL;
1353
+ if (!mgc->cookie) {
1354
+ ruby_xfree(mgc);
1355
+ mgc = NULL;
1146
1356
  errno = local_errno;
1147
1357
  MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError,
1148
1358
  local_errno,
1149
1359
  E_MAGIC_LIBRARY_INITIALIZE);
1150
1360
  }
1151
1361
 
1152
- return Data_Wrap_Struct(klass, magic_mark, magic_free, mo);
1362
+ return TypedData_Wrap_Struct(klass, &rb_mgc_type, mgc);
1153
1363
  }
1154
1364
 
1155
1365
  static inline void
1156
- magic_library_close(void *data)
1366
+ magic_mark(void *data)
1157
1367
  {
1158
- magic_object_t *mo = data;
1159
-
1160
- assert(mo != NULL && \
1161
- "Must be a valid pointer to `magic_object_t' type");
1368
+ rb_mgc_object_t *mgc = data;
1162
1369
 
1163
- if (mo->cookie)
1164
- magic_close_wrapper(mo->cookie);
1370
+ assert(mgc != NULL &&
1371
+ "Must be a valid pointer to `rb_mgc_object_t' type");
1165
1372
 
1166
- mo->cookie = NULL;
1373
+ MAGIC_GC_MARK(mgc->mutex);
1167
1374
  }
1168
1375
 
1169
1376
  static inline void
1170
- magic_mark(void *data)
1377
+ magic_free(void *data)
1171
1378
  {
1172
- magic_object_t *mo = data;
1379
+ rb_mgc_object_t *mgc = data;
1173
1380
 
1174
- assert(mo != NULL && \
1175
- "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");
1383
+
1384
+ if (mgc->cookie)
1385
+ magic_library_close(data);
1176
1386
 
1177
- rb_gc_mark(mo->mutex);
1387
+ mgc->cookie = NULL;
1388
+ mgc->mutex = Qundef;
1389
+
1390
+ ruby_xfree(mgc);
1178
1391
  }
1179
1392
 
1180
- static inline void
1181
- magic_free(void *data)
1393
+ static inline size_t
1394
+ magic_size(const void *data)
1182
1395
  {
1183
- magic_object_t *mo = data;
1396
+ const rb_mgc_object_t *mgc = data;
1184
1397
 
1185
- assert(mo != NULL && \
1186
- "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");
1187
1400
 
1188
- if (mo->cookie)
1189
- magic_library_close(data);
1401
+ return sizeof(*mgc);
1402
+ }
1190
1403
 
1191
- mo->cookie = NULL;
1192
- 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;
1193
1409
 
1194
- ruby_xfree(mo);
1410
+ assert(mgc != NULL &&
1411
+ "Must be a valid pointer to `rb_mgc_object_t' type");
1412
+
1413
+ mgc->mutex = rb_gc_location(mgc->mutex);
1195
1414
  }
1415
+ #endif /* HAVE_RUBY_GC_COMPACT */
1196
1416
 
1197
1417
  static inline VALUE
1198
1418
  magic_exception_wrapper(VALUE value)
1199
1419
  {
1200
- magic_exception_t *e = (struct magic_exception *)value;
1420
+ rb_mgc_error_t *mge = (rb_mgc_error_t *)value;
1201
1421
 
1202
- return rb_exc_new2(e->klass, e->magic_error);
1422
+ return rb_exc_new2(mge->klass, mge->magic_error);
1203
1423
  }
1204
1424
 
1205
1425
  static VALUE
1206
1426
  magic_exception(void *data)
1207
1427
  {
1208
- magic_exception_t *e = data;
1209
1428
  int exception = 0;
1429
+ rb_mgc_error_t *mge = data;
1210
1430
  VALUE object = Qundef;
1211
1431
 
1212
- assert(e != NULL && \
1213
- "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");
1214
1434
 
1215
- object = rb_protect(magic_exception_wrapper, (VALUE)e, &exception);
1435
+ object = rb_protect(magic_exception_wrapper, (VALUE)mge, &exception);
1216
1436
 
1217
1437
  if (exception)
1218
1438
  rb_jump_tag(exception);
1219
1439
 
1220
- rb_iv_set(object, "@errno", INT2NUM(e->magic_errno));
1440
+ rb_iv_set(object, "@errno", INT2NUM(mge->magic_errno));
1221
1441
  RB_GC_GUARD(object);
1222
1442
 
1223
1443
  return object;
@@ -1226,49 +1446,56 @@ magic_exception(void *data)
1226
1446
  static inline VALUE
1227
1447
  magic_generic_error(VALUE klass, int magic_errno, const char *magic_error)
1228
1448
  {
1229
- magic_exception_t e;
1449
+ rb_mgc_error_t mge;
1230
1450
 
1231
- e.magic_errno = magic_errno;
1232
- e.magic_error = magic_error;
1233
- e.klass = klass;
1451
+ mge = (rb_mgc_error_t) {
1452
+ .klass = klass,
1453
+ .magic_errno = magic_errno,
1454
+ .magic_error = magic_error,
1455
+ };
1234
1456
 
1235
- return magic_exception(&e);
1457
+ return magic_exception(&mge);
1236
1458
  }
1237
1459
 
1238
1460
  static VALUE
1239
1461
  magic_library_error(VALUE klass, void *data)
1240
1462
  {
1241
- magic_exception_t e;
1463
+ rb_mgc_error_t mge;
1242
1464
  const char *message = NULL;
1243
1465
  const char *empty = "(null)";
1244
1466
  magic_t cookie = data;
1245
1467
 
1246
- assert(cookie != NULL && \
1468
+ UNUSED(empty);
1469
+
1470
+ assert(cookie != NULL &&
1247
1471
  "Must be a valid pointer to `magic_t' type");
1248
1472
 
1249
- e.magic_errno = -1;
1250
- e.magic_error = error(E_UNKNOWN);
1251
- e.klass = klass;
1473
+ mge = (rb_mgc_error_t) {
1474
+ .klass = klass,
1475
+ .magic_errno = -1,
1476
+ .magic_error = MAGIC_ERRORS(E_UNKNOWN),
1477
+ };
1252
1478
 
1253
1479
  message = magic_error_wrapper(cookie);
1254
1480
  if (message) {
1255
- e.magic_errno = magic_errno_wrapper(cookie);
1256
- e.magic_error = message;
1481
+ mge.magic_errno = magic_errno_wrapper(cookie);
1482
+ mge.magic_error = message;
1257
1483
  }
1258
1484
 
1259
- assert(strncmp(e.magic_error, empty, strlen(empty)) != 0 && \
1485
+ assert(strncmp(mge.magic_error, empty, strlen(empty)) != 0 &&
1260
1486
  "Empty or invalid error message");
1261
1487
 
1262
- return magic_exception(&e);
1488
+ return magic_exception(&mge);
1263
1489
  }
1264
1490
 
1265
1491
  VALUE
1266
1492
  magic_lock(VALUE object, VALUE(*function)(ANYARGS), void *data)
1267
1493
  {
1268
- magic_object_t *mo;
1494
+ rb_mgc_object_t *mgc;
1269
1495
 
1270
- MAGIC_OBJECT(mo);
1271
- rb_funcall(mo->mutex, rb_intern("lock"), 0, Qundef);
1496
+ MAGIC_OBJECT(object, mgc);
1497
+
1498
+ rb_funcall(mgc->mutex, rb_intern("lock"), 0);
1272
1499
 
1273
1500
  return rb_ensure(function, (VALUE)data, magic_unlock, object);
1274
1501
  }
@@ -1276,10 +1503,11 @@ magic_lock(VALUE object, VALUE(*function)(ANYARGS), void *data)
1276
1503
  VALUE
1277
1504
  magic_unlock(VALUE object)
1278
1505
  {
1279
- magic_object_t *mo;
1506
+ rb_mgc_object_t *mgc;
1507
+
1508
+ MAGIC_OBJECT(object, mgc);
1280
1509
 
1281
- MAGIC_OBJECT(mo);
1282
- rb_funcall(mo->mutex, rb_intern("unlock"), 0, Qundef);
1510
+ rb_funcall(mgc->mutex, rb_intern("unlock"), 0);
1283
1511
 
1284
1512
  return Qnil;
1285
1513
  }
@@ -1287,13 +1515,12 @@ magic_unlock(VALUE object)
1287
1515
  static VALUE
1288
1516
  magic_return(void *data)
1289
1517
  {
1290
- magic_arguments_t *ma = data;
1518
+ rb_mgc_arguments_t *mga = data;
1291
1519
  const char *unknown = "???";
1292
1520
  VALUE separator = Qundef;
1293
- VALUE array = Qundef;
1294
- VALUE string = Qundef;
1521
+ VALUE array, string;
1295
1522
 
1296
- string = CSTR2RVAL(ma->result);
1523
+ string = CSTR2RVAL(mga->result);
1297
1524
  RB_GC_GUARD(string);
1298
1525
 
1299
1526
  /*
@@ -1301,15 +1528,15 @@ magic_return(void *data)
1301
1528
  * when the CONTINUE flag is set causing all valid matches found by the
1302
1529
  * Magic library to be returned.
1303
1530
  */
1304
- if (ma->flags & MAGIC_CONTINUE)
1531
+ if (mga->flags & MAGIC_CONTINUE)
1305
1532
  separator = CSTR2RVAL(MAGIC_CONTINUE_SEPARATOR);
1306
1533
 
1307
- if (ma->flags & MAGIC_EXTENSION) {
1534
+ if (mga->flags & MAGIC_EXTENSION) {
1308
1535
  /*
1309
1536
  * A possible I/O-related error has occurred, and there is very
1310
1537
  * little sense processing the results, so return string as-is.
1311
1538
  */
1312
- if (ma->status < 0)
1539
+ if (mga->status < 0)
1313
1540
  return string;
1314
1541
  /*
1315
1542
  * A number of Magic flags that support primarily files e.g.,
@@ -1318,31 +1545,37 @@ magic_return(void *data)
1318
1545
  * return an empty string, to indicate lack of results, rather
1319
1546
  * than a confusing string consisting of three questions marks.
1320
1547
  */
1321
- if (strncmp(ma->result, unknown, strlen(unknown)) == 0)
1548
+ if (strncmp(mga->result, unknown, strlen(unknown)) == 0)
1322
1549
  return CSTR2RVAL("");
1323
1550
 
1324
1551
  separator = CSTR2RVAL(MAGIC_EXTENSION_SEPARATOR);
1325
1552
  }
1326
1553
 
1327
- if (ma->flags & (MAGIC_CONTINUE | MAGIC_EXTENSION)) {
1554
+ RB_GC_GUARD(separator);
1555
+
1556
+ if (mga->flags & (MAGIC_CONTINUE | MAGIC_EXTENSION)) {
1328
1557
  array = magic_split(string, separator);
1329
1558
  RB_GC_GUARD(array);
1330
- 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);
1331
1564
  }
1332
1565
 
1333
- return string;
1566
+ return magic_strip(string);
1334
1567
  }
1335
1568
 
1336
1569
  static inline int
1337
- magic_flags(VALUE object)
1570
+ magic_get_flags(VALUE object)
1338
1571
  {
1339
1572
  return NUM2INT(rb_ivar_get(object, id_at_flags));
1340
1573
  }
1341
1574
 
1342
- static inline int
1343
- magic_set_flags(VALUE object, VALUE value)
1575
+ static inline void
1576
+ magic_set_flags(VALUE object, int flags)
1344
1577
  {
1345
- return NUM2INT(rb_ivar_set(object, id_at_flags, value));
1578
+ rb_ivar_set(object, id_at_flags, INT2NUM(flags));
1346
1579
  }
1347
1580
 
1348
1581
  static inline VALUE
@@ -1351,6 +1584,19 @@ magic_set_paths(VALUE object, VALUE value)
1351
1584
  return rb_ivar_set(object, id_at_paths, value);
1352
1585
  }
1353
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
+
1354
1600
  void
1355
1601
  Init_magic(void)
1356
1602
  {