ruby-magic 0.3.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  {