ruby-magic 0.3.2 → 0.5.3

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