MagickCore  7.1.1-43
Convert, Edit, Or Compose Bitmap Images
magick.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % M M AAA GGGG IIIII CCCC K K %
7 % MM MM A A G I C K K %
8 % M M M AAAAA G GGG I C KKK %
9 % M M A A G G I C K K %
10 % M M A A GGGG IIIII CCCC K K %
11 % %
12 % %
13 % Methods to Read or List ImageMagick Image formats %
14 % %
15 % Software Design %
16 % Bob Friesenhahn %
17 % Cristy %
18 % November 1998 %
19 % %
20 % %
21 % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
23 % %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
26 % %
27 % https://imagemagick.org/script/license.php %
28 % %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
34 % %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %
37 %
38 */
39 
40 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/annotate-private.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/blob-private.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/cache-private.h"
49 #include "MagickCore/coder-private.h"
50 #include "MagickCore/client.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/configure-private.h"
53 #include "MagickCore/constitute-private.h"
54 #include "MagickCore/delegate-private.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/exception.h"
57 #include "MagickCore/exception-private.h"
58 #include "MagickCore/locale-private.h"
59 #include "MagickCore/log-private.h"
60 #include "MagickCore/magic-private.h"
61 #include "MagickCore/magick.h"
62 #include "MagickCore/magick-private.h"
63 #include "MagickCore/memory_.h"
64 #include "MagickCore/mime-private.h"
65 #include "MagickCore/monitor-private.h"
66 #include "MagickCore/module.h"
67 #include "MagickCore/module-private.h"
68 #include "MagickCore/mutex.h"
69 #include "MagickCore/nt-base-private.h"
70 #include "MagickCore/nt-feature.h"
71 #include "MagickCore/opencl-private.h"
72 #include "MagickCore/option-private.h"
73 #include "MagickCore/random-private.h"
74 #include "MagickCore/registry.h"
75 #include "MagickCore/registry-private.h"
76 #include "MagickCore/resource_.h"
77 #include "MagickCore/resource-private.h"
78 #include "MagickCore/policy.h"
79 #include "MagickCore/policy-private.h"
80 #include "MagickCore/mutex.h"
81 #include "MagickCore/semaphore.h"
82 #include "MagickCore/semaphore-private.h"
83 #include "MagickCore/signature-private.h"
84 #include "MagickCore/splay-tree.h"
85 #include "MagickCore/static.h"
86 #include "MagickCore/string_.h"
87 #include "MagickCore/string-private.h"
88 #include "MagickCore/thread_.h"
89 #include "MagickCore/thread-private.h"
90 #include "MagickCore/timer-private.h"
91 #include "MagickCore/type-private.h"
92 #include "MagickCore/token.h"
93 #include "MagickCore/utility.h"
94 #include "MagickCore/utility-private.h"
95 #include "MagickCore/xwindow-private.h"
96 
97 /*
98  Define declarations.
99 */
100 #if !defined(SIG_DFL)
101 # define SIG_DFL ((SignalHandler *) 0)
102 #endif
103 #if !defined(SIG_ERR)
104 # define SIG_ERR ((SignalHandler *) -1)
105 #endif
106 #if !defined(SIGMAX)
107 #define SIGMAX 64
108 #endif
109 
110 /*
111  Typedef declarations.
112 */
113 typedef void SignalHandler(int);
114 
115 /*
116  Global declarations.
117 */
118 static SemaphoreInfo
119  *magick_semaphore = (SemaphoreInfo *) NULL;
120 
121 static SignalHandler
122  *signal_handlers[SIGMAX] = { (SignalHandler *) NULL };
123 
124 static SplayTreeInfo
125  *magick_list = (SplayTreeInfo *) NULL;
126 
127 static volatile MagickBooleanType
128  magickcore_instantiated = MagickFalse,
129  magickcore_signal_in_progress = MagickFalse,
130  magick_list_initialized = MagickFalse;
131 
132 static int
133  magick_precision = 0;
134 
135 /*
136  Forward declarations.
137 */
138 static MagickBooleanType
139  IsMagickTreeInstantiated(ExceptionInfo *);
140 
141 /*
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 % %
144 % %
145 % %
146 % A c q u i r e M a g i c k I n f o %
147 % %
148 % %
149 % %
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151 %
152 % AcquireMagickInfo() allocates a MagickInfo structure and initializes the
153 % members to default values.
154 %
155 % The format of the AcquireMagickInfo method is:
156 %
157 % MagickInfo *AcquireMagickInfo(const char *magick_module,
158 % const char *name,const char *description)
159 %
160 % A description of each parameter follows:
161 %
162 % o magick_module: a character string that represents the module associated
163 % with the MagickInfo structure.
164 %
165 % o name: a character string that represents the image format associated
166 % with the MagickInfo structure.
167 %
168 % o description: a character string that represents the image format
169 % associated with the MagickInfo structure.
170 %
171 */
172 MagickExport MagickInfo *AcquireMagickInfo(const char *magick_module,
173  const char *name,const char *description)
174 {
175  MagickInfo
176  *magick_info;
177 
178  assert(magick_module != (const char *) NULL);
179  assert(name != (const char *) NULL);
180  assert(description != (const char *) NULL);
181  if (IsEventLogging() != MagickFalse)
182  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
183  magick_info=(MagickInfo *) AcquireCriticalMemory(sizeof(*magick_info));
184  (void) memset(magick_info,0,sizeof(*magick_info));
185  magick_info->magick_module=ConstantString(magick_module);
186  magick_info->name=ConstantString(name);
187  magick_info->description=ConstantString(description);
188  magick_info->flags=CoderAdjoinFlag | CoderBlobSupportFlag |
189  CoderDecoderThreadSupportFlag | CoderEncoderThreadSupportFlag |
190  CoderUseExtensionFlag;
191  magick_info->signature=MagickCoreSignature;
192  return(magick_info);
193 }
194 
195 /*
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197 % %
198 % %
199 % %
200 + G e t I m a g e D e c o d e r %
201 % %
202 % %
203 % %
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 %
206 % GetImageDecoder() returns the image decoder.
207 %
208 % The format of the GetImageDecoder method is:
209 %
210 % DecodeImageHandler *GetImageDecoder(const MagickInfo *magick_info)
211 %
212 % A description of each parameter follows:
213 %
214 % o magick_info: The magick info.
215 %
216 */
217 MagickExport DecodeImageHandler *GetImageDecoder(const MagickInfo *magick_info)
218 {
219  if (magick_info == (MagickInfo *) NULL)
220  return((DecodeImageHandler *) NULL);
221  assert(magick_info->signature == MagickCoreSignature);
222  return(magick_info->decoder);
223 }
224 
225 /*
226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 % %
228 % %
229 % %
230 + G e t I m a g e E n c o d e r %
231 % %
232 % %
233 % %
234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235 %
236 % GetImageEncoder() returns the image encoder.
237 %
238 % The format of the GetImageEncoder method is:
239 %
240 % EncodeImageHandler *GetImageEncoder(const MagickInfo *magick_info)
241 %
242 % A description of each parameter follows:
243 %
244 % o magick_info: The magick info.
245 %
246 */
247 MagickExport EncodeImageHandler *GetImageEncoder(const MagickInfo *magick_info)
248 {
249  if (magick_info == (MagickInfo *) NULL)
250  return((EncodeImageHandler *) NULL);
251  assert(magick_info->signature == MagickCoreSignature);
252  return(magick_info->encoder);
253 }
254 
255 /*
256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257 % %
258 % %
259 % %
260 + G e t I m a g e M a g i c k %
261 % %
262 % %
263 % %
264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265 %
266 % GetImageMagick() searches for an image format that matches the specified
267 % magick string. If one is found, MagickTrue is returned otherwise
268 % MagickFalse.
269 %
270 % The format of the GetImageMagick method is:
271 %
272 % MagickBooleanType GetImageMagick(const unsigned char *magick,
273 % const size_t length,char *format)
274 %
275 % A description of each parameter follows:
276 %
277 % o magick: the image format we are searching for.
278 %
279 % o length: the length of the binary string.
280 %
281 % o format: the image format as determined by the magick bytes.
282 %
283 */
284 MagickExport MagickBooleanType GetImageMagick(const unsigned char *magick,
285  const size_t length,char *format)
286 {
288  *exception;
289 
290  MagickBooleanType
291  status;
292 
293  const MagickInfo
294  *p;
295 
296  assert(magick != (const unsigned char *) NULL);
297  if (IsEventLogging() != MagickFalse)
298  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
299  exception=AcquireExceptionInfo();
300  p=GetMagickInfo("*",exception);
301  exception=DestroyExceptionInfo(exception);
302  if (p == (const MagickInfo *) NULL)
303  return(MagickFalse);
304  status=MagickFalse;
305  LockSemaphoreInfo(magick_semaphore);
306  ResetSplayTreeIterator(magick_list);
307  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
308  while (p != (const MagickInfo *) NULL)
309  {
310  if ((p->magick != (IsImageFormatHandler *) NULL) &&
311  (p->magick(magick,length) != 0))
312  {
313  status=MagickTrue;
314  (void) CopyMagickString(format,p->name,MagickPathExtent);
315  break;
316  }
317  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
318  }
319  UnlockSemaphoreInfo(magick_semaphore);
320  return(status);
321 }
322 
323 /*
324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 % %
326 % %
327 % %
328 + G e t M a g i c k A d j o i n %
329 % %
330 % %
331 % %
332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333 %
334 % GetMagickAdjoin() returns MagickTrue if the magick adjoin is MagickTrue.
335 %
336 % The format of the GetMagickAdjoin method is:
337 %
338 % MagickBooleanType GetMagickAdjoin(const MagickInfo *magick_info)
339 %
340 % A description of each parameter follows:
341 %
342 % o magick_info: The magick info.
343 %
344 */
345 MagickExport MagickBooleanType GetMagickAdjoin(const MagickInfo *magick_info)
346 {
347  assert(magick_info != (MagickInfo *) NULL);
348  assert(magick_info->signature == MagickCoreSignature);
349  return(((magick_info->flags & CoderAdjoinFlag) == 0) ? MagickFalse :
350  MagickTrue);
351 }
352 
353 /*
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355 % %
356 % %
357 % %
358 + G e t M a g i c k B l o b S u p p o r t %
359 % %
360 % %
361 % %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363 %
364 % GetMagickBlobSupport() returns MagickTrue if the magick supports blobs.
365 %
366 % The format of the GetMagickBlobSupport method is:
367 %
368 % MagickBooleanType GetMagickBlobSupport(const MagickInfo *magick_info)
369 %
370 % A description of each parameter follows:
371 %
372 % o magick_info: The magick info.
373 %
374 */
375 MagickExport MagickBooleanType GetMagickBlobSupport(
376  const MagickInfo *magick_info)
377 {
378  assert(magick_info != (MagickInfo *) NULL);
379  assert(magick_info->signature == MagickCoreSignature);
380  return(((magick_info->flags & CoderBlobSupportFlag) == 0) ? MagickFalse :
381  MagickTrue);
382 }
383 
384 /*
385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 % %
387 % %
388 % %
389 + G e t M a g i c k D e c o d e r S e e k a b l e S t r e a m %
390 % %
391 % %
392 % %
393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394 %
395 % GetMagickDecoderSeekableStream() returns MagickTrue if the magick supports a
396 % seekable stream in the decoder.
397 %
398 % The format of the GetMagickDecoderSeekableStream method is:
399 %
400 % MagickBooleanType GetMagickDecoderSeekableStream(
401 % const MagickInfo *magick_info)
402 %
403 % A description of each parameter follows:
404 %
405 % o magick_info: The magick info.
406 %
407 */
408 MagickExport MagickBooleanType GetMagickDecoderSeekableStream(
409  const MagickInfo *magick_info)
410 {
411  assert(magick_info != (MagickInfo *) NULL);
412  assert(magick_info->signature == MagickCoreSignature);
413  if ((magick_info->flags & CoderDecoderSeekableStreamFlag) == 0)
414  return(MagickFalse);
415  return(MagickTrue);
416 }
417 
418 /*
419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420 % %
421 % %
422 % %
423 + G e t M a g i c k D e c o d e r T h r e a d S u p p o r t %
424 % %
425 % %
426 % %
427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428 %
429 % GetMagickDecoderThreadSupport() returns MagickTrue if the decoder supports
430 % threads.
431 %
432 % The format of the GetMagickDecoderThreadSupport method is:
433 %
434 % MagickStatusType GetMagickDecoderThreadSupport(
435 % const MagickInfo *magick_info)
436 %
437 % A description of each parameter follows:
438 %
439 % o magick_info: The magick info.
440 %
441 */
442 MagickExport MagickBooleanType GetMagickDecoderThreadSupport(
443  const MagickInfo *magick_info)
444 {
445  assert(magick_info != (MagickInfo *) NULL);
446  assert(magick_info->signature == MagickCoreSignature);
447  return(((magick_info->flags & CoderDecoderThreadSupportFlag) == 0) ?
448  MagickFalse : MagickTrue);
449 }
450 
451 /*
452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453 % %
454 % %
455 % %
456 + G e t M a g i c k D e s c r i p t i o n %
457 % %
458 % %
459 % %
460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461 %
462 % GetMagickDescription() returns the magick description.
463 %
464 % The format of the GetMagickDescription method is:
465 %
466 % const char *GetMagickDescription(const MagickInfo *magick_info)
467 %
468 % A description of each parameter follows:
469 %
470 % o magick_info: The magick info.
471 %
472 */
473 MagickExport const char *GetMagickDescription(const MagickInfo *magick_info)
474 {
475  assert(magick_info != (MagickInfo *) NULL);
476  assert(magick_info->signature == MagickCoreSignature);
477  return(magick_info->description);
478 }
479 
480 /*
481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482 % %
483 % %
484 % %
485 + G e t M a g i c k E n c o d e r S e e k a b l e S t r e a m %
486 % %
487 % %
488 % %
489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 %
491 % GetMagickEncoderSeekableStream() returns MagickTrue if the magick supports a
492 % seekable stream in the encoder.
493 %
494 % The format of the GetMagickEncoderSeekableStream method is:
495 %
496 % MagickBooleanType GetMagickEncoderSeekableStream(
497 % const MagickInfo *magick_info)
498 %
499 % A description of each parameter follows:
500 %
501 % o magick_info: The magick info.
502 %
503 */
504 MagickExport MagickBooleanType GetMagickEncoderSeekableStream(
505  const MagickInfo *magick_info)
506 {
507  assert(magick_info != (MagickInfo *) NULL);
508  assert(magick_info->signature == MagickCoreSignature);
509  if ((magick_info->flags & CoderEncoderSeekableStreamFlag) == 0)
510  return(MagickFalse);
511  return(MagickTrue);
512 }
513 
514 /*
515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
516 % %
517 % %
518 % %
519 + G e t M a g i c k E n c o d e r T h r e a d S u p p o r t %
520 % %
521 % %
522 % %
523 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524 %
525 % GetMagickEncoderThreadSupport() returns MagickTrue if the encoder supports
526 % threads.
527 %
528 % The format of the GetMagickEncoderThreadSupport method is:
529 %
530 % MagickStatusType GetMagickEncoderThreadSupport(
531 % const MagickInfo *magick_info)
532 %
533 % A description of each parameter follows:
534 %
535 % o magick_info: The magick info.
536 %
537 */
538 MagickExport MagickBooleanType GetMagickEncoderThreadSupport(
539  const MagickInfo *magick_info)
540 {
541  assert(magick_info != (MagickInfo *) NULL);
542  assert(magick_info->signature == MagickCoreSignature);
543  return(((magick_info->flags & CoderDecoderThreadSupportFlag) == 0) ?
544  MagickFalse : MagickTrue);
545 }
546 
547 /*
548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549 % %
550 % %
551 % %
552 + G e t M a g i c k E n d i a n S u p p o r t %
553 % %
554 % %
555 % %
556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557 %
558 % GetMagickEndianSupport() returns the MagickTrue if the coder respects
559 % endianness other than MSBEndian.
560 %
561 % The format of the GetMagickEndianSupport method is:
562 %
563 % MagickBooleanType GetMagickEndianSupport(const MagickInfo *magick_info)
564 %
565 % A description of each parameter follows:
566 %
567 % o magick_info: The magick info.
568 %
569 */
570 MagickExport MagickBooleanType GetMagickEndianSupport(
571  const MagickInfo *magick_info)
572 {
573  assert(magick_info != (MagickInfo *) NULL);
574  assert(magick_info->signature == MagickCoreSignature);
575  return(((magick_info->flags & CoderEndianSupportFlag) == 0) ? MagickFalse :
576  MagickTrue);
577 }
578 
579 /*
580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
581 % %
582 % %
583 % %
584 + G e t M a g i c k I n f o %
585 % %
586 % %
587 % %
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589 %
590 % GetMagickInfo() returns a pointer MagickInfo structure that matches
591 % the specified name. If name is NULL, the head of the image format list
592 % is returned.
593 %
594 % The format of the GetMagickInfo method is:
595 %
596 % const MagickInfo *GetMagickInfo(const char *name,Exception *exception)
597 %
598 % A description of each parameter follows:
599 %
600 % o name: the image format we are looking for.
601 %
602 % o exception: return any errors or warnings in this structure.
603 %
604 */
605 MagickExport const MagickInfo *GetMagickInfo(const char *name,
606  ExceptionInfo *exception)
607 {
608  const MagickInfo
609  *magick_info;
610 
611  /*
612  Find named module attributes.
613  */
614  assert(exception != (ExceptionInfo *) NULL);
615  if (IsMagickTreeInstantiated(exception) == MagickFalse)
616  return((const MagickInfo *) NULL);
617  magick_info=(const MagickInfo *) NULL;
618  if ((name != (const char *) NULL) && (*name != '\0'))
619  {
620  LockSemaphoreInfo(magick_semaphore);
621  if (LocaleCompare(name,"*") == 0)
622 #if defined(MAGICKCORE_BUILD_MODULES)
623  (void) OpenModules(exception);
624 #else
625  RegisterStaticModules();
626 #endif
627  else
628  {
629  magick_info=(const MagickInfo *) GetValueFromSplayTree(magick_list,
630  name);
631  if (magick_info == (const MagickInfo *) NULL)
632 #if defined(MAGICKCORE_BUILD_MODULES)
633  (void) OpenModule(name,exception);
634 #else
635  (void) RegisterStaticModule(name,exception);
636 #endif
637  }
638  UnlockSemaphoreInfo(magick_semaphore);
639  }
640  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
641  return((const MagickInfo *) GetRootValueFromSplayTree(magick_list));
642  if (magick_info == (const MagickInfo *) NULL)
643  magick_info=(const MagickInfo *) GetValueFromSplayTree(magick_list,name);
644  return(magick_info);
645 }
646 
647 /*
648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649 % %
650 % %
651 % %
652 + G e t M a g i c k I n f o L i s t %
653 % %
654 % %
655 % %
656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
657 %
658 % GetMagickInfoList() returns any image formats that match the specified
659 % pattern.
660 %
661 % The format of the GetMagickInfoList function is:
662 %
663 % const MagickInfo **GetMagickInfoList(const char *pattern,
664 % size_t *number_formats,ExceptionInfo *exception)
665 %
666 % A description of each parameter follows:
667 %
668 % o pattern: Specifies a pointer to a text string containing a pattern.
669 %
670 % o number_formats: This integer returns the number of formats in the list.
671 %
672 % o exception: return any errors or warnings in this structure.
673 %
674 */
675 
676 #if defined(__cplusplus) || defined(c_plusplus)
677 extern "C" {
678 #endif
679 
680 static int MagickInfoCompare(const void *x,const void *y)
681 {
682  const MagickInfo
683  **p,
684  **q;
685 
686  p=(const MagickInfo **) x,
687  q=(const MagickInfo **) y;
688  return(LocaleCompare((*p)->name,(*q)->name));
689 }
690 
691 #if defined(__cplusplus) || defined(c_plusplus)
692 }
693 #endif
694 
695 MagickExport const MagickInfo **GetMagickInfoList(const char *pattern,
696  size_t *number_formats,ExceptionInfo *exception)
697 {
698  const MagickInfo
699  **formats;
700 
701  const MagickInfo
702  *p;
703 
704  ssize_t
705  i;
706 
707  /*
708  Allocate magick list.
709  */
710  assert(pattern != (char *) NULL);
711  assert(number_formats != (size_t *) NULL);
712  if (IsEventLogging() != MagickFalse)
713  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
714  *number_formats=0;
715  p=GetMagickInfo("*",exception);
716  if (p == (const MagickInfo *) NULL)
717  return((const MagickInfo **) NULL);
718  formats=(const MagickInfo **) AcquireQuantumMemory((size_t)
719  GetNumberOfNodesInSplayTree(magick_list)+1UL,sizeof(*formats));
720  if (formats == (const MagickInfo **) NULL)
721  return((const MagickInfo **) NULL);
722  /*
723  Generate magick list.
724  */
725  LockSemaphoreInfo(magick_semaphore);
726  ResetSplayTreeIterator(magick_list);
727  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
728  for (i=0; p != (const MagickInfo *) NULL; )
729  {
730  if ((GetMagickStealth(p) == MagickFalse) &&
731  (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
732  formats[i++]=p;
733  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
734  }
735  UnlockSemaphoreInfo(magick_semaphore);
736  qsort((void *) formats,(size_t) i,sizeof(*formats),MagickInfoCompare);
737  formats[i]=(MagickInfo *) NULL;
738  *number_formats=(size_t) i;
739  return(formats);
740 }
741 
742 /*
743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
744 % %
745 % %
746 % %
747 + G e t M a g i c k L i s t %
748 % %
749 % %
750 % %
751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
752 %
753 % GetMagickList() returns any image formats that match the specified pattern.
754 %
755 % The format of the GetMagickList function is:
756 %
757 % char **GetMagickList(const char *pattern,size_t *number_formats,
758 % ExceptionInfo *exception)
759 %
760 % A description of each parameter follows:
761 %
762 % o pattern: Specifies a pointer to a text string containing a pattern.
763 %
764 % o number_formats: This integer returns the number of formats in the list.
765 %
766 % o exception: return any errors or warnings in this structure.
767 %
768 */
769 
770 #if defined(__cplusplus) || defined(c_plusplus)
771 extern "C" {
772 #endif
773 
774 static int MagickCompare(const void *x,const void *y)
775 {
776  const char
777  **p,
778  **q;
779 
780  p=(const char **) x;
781  q=(const char **) y;
782  return(LocaleCompare(*p,*q));
783 }
784 
785 #if defined(__cplusplus) || defined(c_plusplus)
786 }
787 #endif
788 
789 MagickExport char **GetMagickList(const char *pattern,
790  size_t *number_formats,ExceptionInfo *exception)
791 {
792  char
793  **formats;
794 
795  const MagickInfo
796  *p;
797 
798  ssize_t
799  i;
800 
801  /*
802  Allocate magick list.
803  */
804  assert(pattern != (char *) NULL);
805  assert(number_formats != (size_t *) NULL);
806  if (IsEventLogging() != MagickFalse)
807  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
808  *number_formats=0;
809  p=GetMagickInfo("*",exception);
810  if (p == (const MagickInfo *) NULL)
811  return((char **) NULL);
812  formats=(char **) AcquireQuantumMemory((size_t)
813  GetNumberOfNodesInSplayTree(magick_list)+1UL,sizeof(*formats));
814  if (formats == (char **) NULL)
815  return((char **) NULL);
816  LockSemaphoreInfo(magick_semaphore);
817  ResetSplayTreeIterator(magick_list);
818  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
819  for (i=0; p != (const MagickInfo *) NULL; )
820  {
821  if ((GetMagickStealth(p) == MagickFalse) &&
822  (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
823  formats[i++]=ConstantString(p->name);
824  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
825  }
826  UnlockSemaphoreInfo(magick_semaphore);
827  qsort((void *) formats,(size_t) i,sizeof(*formats),MagickCompare);
828  formats[i]=(char *) NULL;
829  *number_formats=(size_t) i;
830  return(formats);
831 }
832 
833 /*
834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835 % %
836 % %
837 % %
838 + G e t M a g i c k M i m e T y p e %
839 % %
840 % %
841 % %
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
843 %
844 % GetMagickMimeType() returns the magick mime type.
845 %
846 % The format of the GetMagickMimeType method is:
847 %
848 % const char *GetMagickMimeType(const MagickInfo *magick_info)
849 %
850 % A description of each parameter follows:
851 %
852 % o magick_info: The magick info.
853 %
854 */
855 MagickExport const char *GetMagickMimeType(const MagickInfo *magick_info)
856 {
857  assert(magick_info != (MagickInfo *) NULL);
858  assert(magick_info->signature == MagickCoreSignature);
859  return(magick_info->mime_type);
860 }
861 
862 /*
863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864 % %
865 % %
866 % %
867 + G e t M a g i c k M o d u l e N a m e %
868 % %
869 % %
870 % %
871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
872 %
873 % GetMagickModuleName() returns the magick module name.
874 %
875 % The format of the GetMagickModuleName method is:
876 %
877 % const char *GetMagickModuleName(const MagickInfo *magick_info)
878 %
879 % A description of each parameter follows:
880 %
881 % o magick_info: The magick info.
882 %
883 */
884 MagickExport const char *GetMagickModuleName(const MagickInfo *magick_info)
885 {
886  assert(magick_info != (MagickInfo *) NULL);
887  assert(magick_info->signature == MagickCoreSignature);
888  return(magick_info->magick_module);
889 }
890 
891 /*
892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
893 % %
894 % %
895 % %
896 + G e t M a g i c k N a m e %
897 % %
898 % %
899 % %
900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901 %
902 % GetMagickName() returns the magick name.
903 %
904 % The format of the GetMagickName method is:
905 %
906 % const char *GetMagickName(const MagickInfo *magick_info)
907 %
908 % A description of each parameter follows:
909 %
910 % o magick_info: The magick info.
911 %
912 */
913 MagickExport const char *GetMagickName(const MagickInfo *magick_info)
914 {
915  assert(magick_info != (MagickInfo *) NULL);
916  assert(magick_info->signature == MagickCoreSignature);
917  return(magick_info->name);
918 }
919 
920 /*
921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922 % %
923 % %
924 % %
925 % G e t M a g i c k P r e c i s i o n %
926 % %
927 % %
928 % %
929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
930 %
931 % GetMagickPrecision() returns the maximum number of significant digits to be
932 % printed.
933 %
934 % The format of the GetMagickPrecision method is:
935 %
936 % int GetMagickPrecision(void)
937 %
938 */
939 MagickExport int GetMagickPrecision(void)
940 {
941  if (IsEventLogging() != MagickFalse)
942  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
943  return(SetMagickPrecision(0));
944 }
945 
946 /*
947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
948 % %
949 % %
950 % %
951 + G e t M a g i c k R a w S u p p o r t %
952 % %
953 % %
954 % %
955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
956 %
957 % GetMagickRawSupport() returns the MagickTrue if the coder is a raw format.
958 %
959 % The format of the GetMagickRawSupport method is:
960 %
961 % MagickBooleanType GetMagickRawSupport(const MagickInfo *magick_info)
962 %
963 % A description of each parameter follows:
964 %
965 % o magick_info: The magick info.
966 %
967 */
968 MagickExport MagickBooleanType GetMagickRawSupport(
969  const MagickInfo *magick_info)
970 {
971  assert(magick_info != (MagickInfo *) NULL);
972  assert(magick_info->signature == MagickCoreSignature);
973  return(((magick_info->flags & CoderRawSupportFlag) == 0) ? MagickFalse :
974  MagickTrue);
975 }
976 
977 /*
978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
979 % %
980 % %
981 % %
982 + G e t M a g i c k S t e a l t h %
983 % %
984 % %
985 % %
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 %
988 % GetMagickStealth() returns MagickTrue if the magick is a stealth coder.
989 %
990 % The format of the GetMagickStealth method is:
991 %
992 % MagickBooleanType GetMagickStealth(const MagickInfo *magick_info)
993 %
994 % A description of each parameter follows:
995 %
996 % o magick_info: The magick info.
997 %
998 */
999 MagickExport MagickBooleanType GetMagickStealth(const MagickInfo *magick_info)
1000 {
1001  assert(magick_info != (MagickInfo *) NULL);
1002  assert(magick_info->signature == MagickCoreSignature);
1003  return(((magick_info->flags & CoderStealthFlag) == 0) ? MagickFalse :
1004  MagickTrue);
1005 }
1006 
1007 /*
1008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009 % %
1010 % %
1011 % %
1012 + G e t M a g i c k U s e E x t e n s i o n %
1013 % %
1014 % %
1015 % %
1016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1017 %
1018 % GetMagickUseExtension() returns MagickTrue if the magick can use the
1019 % extension of the format if the format return by IsImageFormatHandler uses
1020 % the same coder.
1021 %
1022 % The format of the GetMagickUseExtension method is:
1023 %
1024 % MagickBooleanType GetMagickUseExtension(const MagickInfo *magick_info)
1025 %
1026 % A description of each parameter follows:
1027 %
1028 % o magick_info: The magick info.
1029 %
1030 */
1031 MagickExport MagickBooleanType GetMagickUseExtension(
1032  const MagickInfo *magick_info)
1033 {
1034  assert(magick_info != (MagickInfo *) NULL);
1035  assert(magick_info->signature == MagickCoreSignature);
1036  return(((magick_info->flags & CoderUseExtensionFlag) == 0) ? MagickFalse :
1037  MagickTrue);
1038 }
1039 
1040 /*
1041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042 % %
1043 % %
1044 % %
1045 + I s M a g i c k T r e e I n s t a n t i a t e d %
1046 % %
1047 % %
1048 % %
1049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050 %
1051 % IsMagickTreeInstantiated() determines if the magick tree is instantiated.
1052 % If not, it instantiates the tree and returns it.
1053 %
1054 % The format of the IsMagickTreeInstantiated() method is:
1055 %
1056 % IsMagickTreeInstantiated(Exceptioninfo *exception)
1057 %
1058 % A description of each parameter follows.
1059 %
1060 % o exception: return any errors or warnings in this structure.
1061 %
1062 */
1063 
1064 static void *DestroyMagickNode(void *magick_info)
1065 {
1066  MagickInfo
1067  *p;
1068 
1069  p=(MagickInfo *) magick_info;
1070  if (p->magick_module != (char *) NULL)
1071  p->magick_module=DestroyString(p->magick_module);
1072  if (p->note != (char *) NULL)
1073  p->note=DestroyString(p->note);
1074  if (p->mime_type != (char *) NULL)
1075  p->mime_type=DestroyString(p->mime_type);
1076  if (p->version != (char *) NULL)
1077  p->version=DestroyString(p->version);
1078  if (p->description != (char *) NULL)
1079  p->description=DestroyString(p->description);
1080  if (p->name != (char *) NULL)
1081  p->name=DestroyString(p->name);
1082  if (p->semaphore != (SemaphoreInfo *) NULL)
1083  RelinquishSemaphoreInfo(&p->semaphore);
1084  return(RelinquishMagickMemory(p));
1085 }
1086 
1087 static MagickBooleanType IsMagickTreeInstantiated(ExceptionInfo *exception)
1088 {
1089  (void) exception;
1090  if (magick_list_initialized == MagickFalse)
1091  {
1092  if (magick_semaphore == (SemaphoreInfo *) NULL)
1093  ActivateSemaphoreInfo(&magick_semaphore);
1094  LockSemaphoreInfo(magick_semaphore);
1095  if (magick_list_initialized == MagickFalse)
1096  {
1097  magick_list=NewSplayTree(CompareSplayTreeString,(void *(*)(void *))
1098  NULL,DestroyMagickNode);
1099 #if defined(MAGICKCORE_MODULES_SUPPORT)
1100  (void) GetModuleInfo((char *) NULL,exception);
1101 #endif
1102  magick_list_initialized=MagickTrue;
1103  }
1104  UnlockSemaphoreInfo(magick_semaphore);
1105  }
1106  return(magick_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
1107 }
1108 
1109 /*
1110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1111 % %
1112 % %
1113 % %
1114 + I s M a g i c k C o n f l i c t %
1115 % %
1116 % %
1117 % %
1118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 %
1120 % IsMagickConflict() returns MagickTrue if the image format conflicts with a
1121 % logical drive (.e.g. X:).
1122 %
1123 % The format of the IsMagickConflict method is:
1124 %
1125 % MagickBooleanType IsMagickConflict(const char *magick)
1126 %
1127 % A description of each parameter follows:
1128 %
1129 % o magick: Specifies the image format.
1130 %
1131 */
1132 MagickPrivate MagickBooleanType IsMagickConflict(const char *magick)
1133 {
1134  assert(magick != (char *) NULL);
1135 #if defined(vms)
1136  return(VMSIsMagickConflict(magick));
1137 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1138  return(NTIsMagickConflict(magick));
1139 #else
1140  return(MagickFalse);
1141 #endif
1142 }
1143 
1144 /*
1145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1146 % %
1147 % %
1148 % %
1149 + L i s t M a g i c k I n f o %
1150 % %
1151 % %
1152 % %
1153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1154 %
1155 % ListMagickInfo() lists the image formats to a file.
1156 %
1157 % The format of the ListMagickInfo method is:
1158 %
1159 % MagickBooleanType ListMagickInfo(FILE *file,ExceptionInfo *exception)
1160 %
1161 % A description of each parameter follows.
1162 %
1163 % o file: A file handle.
1164 %
1165 % o exception: return any errors or warnings in this structure.
1166 %
1167 */
1168 MagickExport MagickBooleanType ListMagickInfo(FILE *file,
1169  ExceptionInfo *exception)
1170 {
1171  const MagickInfo
1172  **magick_info;
1173 
1174  ssize_t
1175  i;
1176 
1177  size_t
1178  number_formats;
1179 
1180  ssize_t
1181  j;
1182 
1183  if (file == (FILE *) NULL)
1184  file=stdout;
1185  magick_info=GetMagickInfoList("*",&number_formats,exception);
1186  if (magick_info == (const MagickInfo **) NULL)
1187  return(MagickFalse);
1188  ClearMagickException(exception);
1189 #if !defined(MAGICKCORE_MODULES_SUPPORT)
1190  (void) FormatLocaleFile(file," Format Mode Description\n");
1191 #else
1192  (void) FormatLocaleFile(file," Format Module Mode Description\n");
1193 #endif
1194  (void) FormatLocaleFile(file,
1195  "--------------------------------------------------------"
1196  "-----------------------\n");
1197  for (i=0; i < (ssize_t) number_formats; i++)
1198  {
1199  if (GetMagickStealth(magick_info[i]) != MagickFalse)
1200  continue;
1201  (void) FormatLocaleFile(file,"%9s%c ",
1202  magick_info[i]->name != (char *) NULL ? magick_info[i]->name : "",
1203  GetMagickBlobSupport(magick_info[i]) != MagickFalse ? '*' : ' ');
1204 #if defined(MAGICKCORE_MODULES_SUPPORT)
1205  {
1206  char
1207  magick_module[MagickPathExtent];
1208 
1209  *magick_module='\0';
1210  if (magick_info[i]->magick_module != (char *) NULL)
1211  (void) CopyMagickString(magick_module,magick_info[i]->magick_module,
1212  MagickPathExtent);
1213  (void) ConcatenateMagickString(magick_module," ",
1214  MagickPathExtent);
1215  magick_module[9]='\0';
1216  (void) FormatLocaleFile(file,"%9s ",magick_module);
1217  }
1218 #endif
1219  (void) FormatLocaleFile(file,"%c%c%c ",magick_info[i]->decoder ? 'r' : '-',
1220  magick_info[i]->encoder ? 'w' : '-',magick_info[i]->encoder != NULL &&
1221  GetMagickAdjoin(magick_info[i]) != MagickFalse ? '+' : '-');
1222  if (magick_info[i]->description != (char *) NULL)
1223  (void) FormatLocaleFile(file," %s",magick_info[i]->description);
1224  if (magick_info[i]->version != (char *) NULL)
1225  (void) FormatLocaleFile(file," (%s)",magick_info[i]->version);
1226  (void) FormatLocaleFile(file,"\n");
1227  if (magick_info[i]->note != (char *) NULL)
1228  {
1229  char
1230  **text;
1231 
1232  text=StringToList(magick_info[i]->note);
1233  if (text != (char **) NULL)
1234  {
1235  for (j=0; text[j] != (char *) NULL; j++)
1236  {
1237  (void) FormatLocaleFile(file," %s\n",text[j]);
1238  text[j]=DestroyString(text[j]);
1239  }
1240  text=(char **) RelinquishMagickMemory(text);
1241  }
1242  }
1243  }
1244  (void) FormatLocaleFile(file,"\n* native blob support\n");
1245  (void) FormatLocaleFile(file,"r read support\n");
1246  (void) FormatLocaleFile(file,"w write support\n");
1247  (void) FormatLocaleFile(file,"+ support for multiple images\n");
1248  (void) fflush(file);
1249  magick_info=(const MagickInfo **) RelinquishMagickMemory((void *)
1250  magick_info);
1251  return(MagickTrue);
1252 }
1253 
1254 /*
1255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256 % %
1257 % %
1258 % %
1259 % I s M a g i c k C o r e I n s t a n t i a t e d %
1260 % %
1261 % %
1262 % %
1263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264 %
1265 % IsMagickCoreInstantiated() returns MagickFalse if the ImageMagick
1266 % environment has not been instantiated; the ImageMagick environment
1267 % has been instantiated when MagickCoreGenesis() has been called but
1268 % MagickDestroy() has not been called.
1269 %
1270 % The format of the IsMagickCoreInstantiated method is:
1271 %
1272 % MagickBooleanType IsMagickCoreInstantiated(void)
1273 %
1274 */
1275 MagickExport MagickBooleanType IsMagickCoreInstantiated(void)
1276 {
1277  return(magickcore_instantiated);
1278 }
1279 
1280 /*
1281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282 % %
1283 % %
1284 % %
1285 + M a g i c k C o m p o n e n t G e n e s i s %
1286 % %
1287 % %
1288 % %
1289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290 %
1291 % MagickComponentGenesis() instantiates the magick component.
1292 %
1293 % The format of the MagickComponentGenesis method is:
1294 %
1295 % MagickBooleanType MagickComponentGenesis(void)
1296 %
1297 */
1298 MagickPrivate MagickBooleanType MagickComponentGenesis(void)
1299 {
1300  if (magick_semaphore == (SemaphoreInfo *) NULL)
1301  magick_semaphore=AcquireSemaphoreInfo();
1302  return(MagickTrue);
1303 }
1304 
1305 /*
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 % %
1308 % %
1309 % %
1310 + M a g i c k C o m p o n e n t T e r m i n u s %
1311 % %
1312 % %
1313 % %
1314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315 %
1316 % MagickComponentTerminus() destroys the magick component.
1317 %
1318 % The format of the MagickComponentTerminus method is:
1319 %
1320 % void MagickComponentTerminus(void)
1321 %
1322 */
1323 MagickPrivate void MagickComponentTerminus(void)
1324 {
1325  if (magick_semaphore == (SemaphoreInfo *) NULL)
1326  ActivateSemaphoreInfo(&magick_semaphore);
1327  LockSemaphoreInfo(magick_semaphore);
1328  if (magick_list != (SplayTreeInfo *) NULL)
1329  {
1330  magick_list=DestroySplayTree(magick_list);
1331  magick_list_initialized=MagickFalse;
1332  }
1333  UnlockSemaphoreInfo(magick_semaphore);
1334  RelinquishSemaphoreInfo(&magick_semaphore);
1335 }
1336 
1337 /*
1338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339 % %
1340 % %
1341 % %
1342 % M a g i c k C o r e G e n e s i s %
1343 % %
1344 % %
1345 % %
1346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347 %
1348 % MagickCoreGenesis() initializes the MagickCore environment.
1349 %
1350 % The format of the MagickCoreGenesis function is:
1351 %
1352 % MagickCoreGenesis(const char *path,
1353 % const MagickBooleanType establish_signal_handlers)
1354 %
1355 % A description of each parameter follows:
1356 %
1357 % o path: the execution path of the current ImageMagick client.
1358 %
1359 % o establish_signal_handlers: set to MagickTrue to use MagickCore's own
1360 % signal handlers for common signals.
1361 %
1362 */
1363 
1364 static SignalHandler *SetMagickSignalHandler(int signal_number,
1365  SignalHandler *handler)
1366 {
1367 #if defined(MAGICKCORE_HAVE_SIGACTION) && defined(MAGICKCORE_HAVE_SIGEMPTYSET)
1368  int
1369  status;
1370 
1371  sigset_t
1372  mask;
1373 
1374  struct sigaction
1375  action,
1376  previous_action;
1377 
1378  sigemptyset(&mask);
1379  sigaddset(&mask,signal_number);
1380  sigprocmask(SIG_BLOCK,&mask,NULL);
1381  action.sa_mask=mask;
1382  action.sa_handler=handler;
1383  action.sa_flags=0;
1384 #if defined(SA_INTERRUPT)
1385  action.sa_flags|=SA_INTERRUPT;
1386 #endif
1387 #if defined(SA_ONSTACK)
1388  action.sa_flags|=SA_ONSTACK;
1389 #endif
1390  previous_action.sa_handler=SIG_DFL;
1391  status=sigaction(signal_number,&action,&previous_action);
1392  if (status < 0)
1393  return(SIG_ERR);
1394  sigprocmask(SIG_UNBLOCK,&mask,NULL);
1395  return(previous_action.sa_handler);
1396 #else
1397  return(signal(signal_number,handler));
1398 #endif
1399 }
1400 
1401 static void MagickSignalHandler(int signal_number)
1402 {
1403  if (magickcore_signal_in_progress != MagickFalse)
1404  (void) SetMagickSignalHandler(signal_number,signal_handlers[signal_number]);
1405  magickcore_signal_in_progress=MagickTrue;
1406  AsynchronousResourceComponentTerminus();
1407 #if defined(SIGQUIT)
1408  if (signal_number == SIGQUIT)
1409  abort();
1410 #endif
1411 #if defined(SIGABRT)
1412  if (signal_number == SIGABRT)
1413  abort();
1414 #endif
1415 #if defined(SIGBUS)
1416  if (signal_number == SIGBUS)
1417  abort();
1418 #endif
1419 #if defined(SIGFPE)
1420  if (signal_number == SIGFPE)
1421  abort();
1422 #endif
1423 #if defined(SIGSEGV)
1424  if (signal_number == SIGSEGV)
1425  abort();
1426 #endif
1427 #if !defined(MAGICKCORE_HAVE__EXIT)
1428  exit(signal_number);
1429 #else
1430 #if defined(SIGHUP)
1431  if (signal_number == SIGHUP)
1432  _exit(signal_number);
1433 #endif
1434 #if defined(SIGINT)
1435  if (signal_number == SIGINT)
1436  _exit(signal_number);
1437 #endif
1438 #if defined(MAGICKCORE_HAVE_RAISE)
1439  if (signal_handlers[signal_number] != MagickSignalHandler)
1440  raise(signal_number);
1441 #endif
1442  _exit(signal_number); /* do not invoke registered atexit() methods */
1443 #endif
1444 }
1445 
1446 static SignalHandler *RegisterMagickSignalHandler(int signal_number)
1447 {
1448  SignalHandler
1449  *handler;
1450 
1451  handler=SetMagickSignalHandler(signal_number,MagickSignalHandler);
1452  if (handler == SIG_ERR)
1453  return(handler);
1454  if (handler != SIG_DFL)
1455  handler=SetMagickSignalHandler(signal_number,handler);
1456  else
1457  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1458  "Register handler for signal: %d",signal_number);
1459  return(handler);
1460 }
1461 
1462 static void SetClientNameAndPath(const char *path)
1463 {
1464  char
1465  execution_path[MagickPathExtent],
1466  filename[MagickPathExtent];
1467 
1468 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1469  if ((path != (const char *) NULL) && (IsPathAccessible(path) != MagickFalse))
1470 #else
1471  if ((path != (const char *) NULL) && (*path == *DirectorySeparator) &&
1472  (IsPathAccessible(path) != MagickFalse))
1473 #endif
1474  (void) CopyMagickString(execution_path,path,MagickPathExtent);
1475  else
1476  (void) GetExecutionPath(execution_path,MagickPathExtent);
1477  GetPathComponent(execution_path,TailPath,filename);
1478  (void) SetClientName(filename);
1479  GetPathComponent(execution_path,HeadPath,execution_path);
1480  (void) SetClientPath(execution_path);
1481 }
1482 
1483 MagickExport void MagickCoreGenesis(const char *path,
1484  const MagickBooleanType establish_signal_handlers)
1485 {
1486  char
1487  *events;
1488 
1489  /*
1490  Initialize the Magick environment.
1491  */
1492 #if defined(__has_feature)
1493 #if __has_feature(address_sanitizer)
1494  (void) putenv("MAGICK_THREAD_LIMIT=1");
1495 #endif
1496 #endif
1497  InitializeMagickMutex();
1498  LockMagickMutex();
1499  if (magickcore_instantiated != MagickFalse)
1500  {
1501  UnlockMagickMutex();
1502  return;
1503  }
1504  (void) SemaphoreComponentGenesis();
1505  (void) ExceptionComponentGenesis();
1506  SetClientNameAndPath(path);
1507  (void) LogComponentGenesis();
1508  (void) LocaleComponentGenesis();
1509  (void) RandomComponentGenesis();
1510  events=GetEnvironmentValue("MAGICK_DEBUG");
1511  if (events != (char *) NULL)
1512  {
1513  (void) SetLogEventMask(events);
1514  events=DestroyString(events);
1515  }
1516 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1517  NTWindowsGenesis();
1518 #endif
1519  if (establish_signal_handlers != MagickFalse)
1520  {
1521  /*
1522  Set signal handlers.
1523  */
1524 #if defined(SIGABRT)
1525  if (signal_handlers[SIGABRT] == (SignalHandler *) NULL)
1526  signal_handlers[SIGABRT]=RegisterMagickSignalHandler(SIGABRT);
1527 #endif
1528 #if defined(SIGBUS)
1529  if (signal_handlers[SIGBUS] == (SignalHandler *) NULL)
1530  signal_handlers[SIGBUS]=RegisterMagickSignalHandler(SIGBUS);
1531 #endif
1532 #if defined(SIGSEGV)
1533  if (signal_handlers[SIGSEGV] == (SignalHandler *) NULL)
1534  signal_handlers[SIGSEGV]=RegisterMagickSignalHandler(SIGSEGV);
1535 #endif
1536 #if defined(SIGFPE)
1537  if (signal_handlers[SIGFPE] == (SignalHandler *) NULL)
1538  signal_handlers[SIGFPE]=RegisterMagickSignalHandler(SIGFPE);
1539 #endif
1540 #if defined(SIGHUP)
1541  if (signal_handlers[SIGHUP] == (SignalHandler *) NULL)
1542  signal_handlers[SIGHUP]=RegisterMagickSignalHandler(SIGHUP);
1543 #endif
1544 #if defined(SIGINT)
1545  if (signal_handlers[SIGINT] == (SignalHandler *) NULL)
1546  signal_handlers[SIGINT]=RegisterMagickSignalHandler(SIGINT);
1547 #endif
1548 #if defined(SIGQUIT)
1549  if (signal_handlers[SIGQUIT] == (SignalHandler *) NULL)
1550  signal_handlers[SIGQUIT]=RegisterMagickSignalHandler(SIGQUIT);
1551 #endif
1552 #if defined(SIGTERM)
1553  if (signal_handlers[SIGTERM] == (SignalHandler *) NULL)
1554  signal_handlers[SIGTERM]=RegisterMagickSignalHandler(SIGTERM);
1555 #endif
1556 #if defined(SIGXCPU)
1557  if (signal_handlers[SIGXCPU] == (SignalHandler *) NULL)
1558  signal_handlers[SIGXCPU]=RegisterMagickSignalHandler(SIGXCPU);
1559 #endif
1560 #if defined(SIGXFSZ)
1561  if (signal_handlers[SIGXFSZ] == (SignalHandler *) NULL)
1562  signal_handlers[SIGXFSZ]=RegisterMagickSignalHandler(SIGXFSZ);
1563 #endif
1564  }
1565  /*
1566  Instantiate magick resources.
1567  */
1568  (void) ConfigureComponentGenesis();
1569  (void) PolicyComponentGenesis();
1570 #if MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1571  (void) ZeroConfigurationPolicy;
1572 #endif
1573  (void) CacheComponentGenesis();
1574  (void) ResourceComponentGenesis();
1575  (void) CoderComponentGenesis();
1576  (void) MagickComponentGenesis();
1577 #if defined(MAGICKCORE_MODULES_SUPPORT)
1578  (void) ModuleComponentGenesis();
1579 #endif
1580  (void) DelegateComponentGenesis();
1581  (void) MagicComponentGenesis();
1582  (void) ColorComponentGenesis();
1583  (void) TypeComponentGenesis();
1584  (void) MimeComponentGenesis();
1585  (void) AnnotateComponentGenesis();
1586 #if defined(MAGICKCORE_X11_DELEGATE)
1587  (void) XComponentGenesis();
1588 #endif
1589  (void) RegistryComponentGenesis();
1590  (void) MonitorComponentGenesis();
1591  magickcore_instantiated=MagickTrue;
1592  UnlockMagickMutex();
1593 }
1594 
1595 /*
1596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597 % %
1598 % %
1599 % %
1600 % M a g i c k C o r e T e r m i n u s %
1601 % %
1602 % %
1603 % %
1604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1605 %
1606 % MagickCoreTerminus() is a function in the ImageMagick library that is
1607 % used to clean up and release resources when shutting down an application
1608 % that uses ImageMagick. This function should be called in the primary thread
1609 % of the application's process during the shutdown process. It's crucial that
1610 % this function is invoked only after any threads that are using ImageMagick
1611 % functions have terminated.
1612 %
1613 % ImageMagick might internally use threads via OpenMP (a method for parallel
1614 % programming). As a result, it's important to ensure that any function calls
1615 % into ImageMagick have completed before calling MagickCoreTerminus(). This
1616 % prevents issues with OpenMP worker threads accessing resources that are
1617 % destroyed by this termination function.
1618 %
1619 % If OpenMP is being used (starting from version 5.0), the OpenMP
1620 % implementation itself handles starting and stopping worker threads and
1621 % allocating and freeing resources using its own methods. This means that
1622 % after calling MagickCoreTerminus(), some OpenMP resources and worker
1623 % threads might still remain allocated. To address this, the function
1624 % omp_pause_resource_all(omp_pause_hard) can be invoked. This function,
1625 % introduced in OpenMP version 5.0, ensures that any resources allocated by
1626 % OpenMP (such as threads and thread-specific memory) are freed. It's
1627 % recommended to call this function after MagickCoreTerminus() has completed
1628 % its execution.
1629 %
1630 % The format of the MagickCoreTerminus function is:
1631 %
1632 % MagickCoreTerminus(void)
1633 %
1634 */
1635 MagickExport void MagickCoreTerminus(void)
1636 {
1637  InitializeMagickMutex();
1638  LockMagickMutex();
1639  if (magickcore_instantiated == MagickFalse)
1640  {
1641  UnlockMagickMutex();
1642  return;
1643  }
1644  MonitorComponentTerminus();
1645  RegistryComponentTerminus();
1646  AnnotateComponentTerminus();
1647  MimeComponentTerminus();
1648  TypeComponentTerminus();
1649 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1650  OpenCLTerminus();
1651 #endif
1652  ColorComponentTerminus();
1653 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1654  NTWindowsTerminus();
1655 #endif
1656  MagicComponentTerminus();
1657  DelegateComponentTerminus();
1658  MagickComponentTerminus();
1659 #if !defined(MAGICKCORE_BUILD_MODULES)
1660  UnregisterStaticModules();
1661 #endif
1662 #if defined(MAGICKCORE_MODULES_SUPPORT)
1663  ModuleComponentTerminus();
1664 #endif
1665 #if defined(MAGICKCORE_X11_DELEGATE)
1666  XComponentTerminus();
1667 #endif
1668  CoderComponentTerminus();
1669  ResourceComponentTerminus();
1670  CacheComponentTerminus();
1671  PolicyComponentTerminus();
1672  ConfigureComponentTerminus();
1673  RandomComponentTerminus();
1674  LocaleComponentTerminus();
1675  LogComponentTerminus();
1676  ExceptionComponentTerminus();
1677  magickcore_instantiated=MagickFalse;
1678  UnlockMagickMutex();
1679  SemaphoreComponentTerminus();
1680 }
1681 
1682 /*
1683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684 % %
1685 % %
1686 % %
1687 + R e g i s t e r M a g i c k I n f o %
1688 % %
1689 % %
1690 % %
1691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1692 %
1693 % RegisterMagickInfo() adds attributes for a particular image format to the
1694 % list of supported formats. The attributes include the image format name,
1695 % a method to read and/or write the format, whether the format supports the
1696 % saving of more than one frame to the same file or blob, whether the format
1697 % supports native in-memory I/O, and a brief description of the format.
1698 %
1699 % The format of the RegisterMagickInfo method is:
1700 %
1701 % MagickInfo *RegisterMagickInfo(MagickInfo *magick_info)
1702 %
1703 % A description of each parameter follows:
1704 %
1705 % o magick_info: the magick info.
1706 %
1707 */
1708 MagickExport MagickBooleanType RegisterMagickInfo(MagickInfo *magick_info)
1709 {
1710  MagickBooleanType
1711  status;
1712 
1713  /*
1714  Register a new image format.
1715  */
1716  assert(magick_info != (MagickInfo *) NULL);
1717  assert(magick_info->signature == MagickCoreSignature);
1718  if (IsEventLogging() != MagickFalse)
1719  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",magick_info->name);
1720  if (magick_list == (SplayTreeInfo *) NULL)
1721  return(MagickFalse);
1722  if ((GetMagickDecoderThreadSupport(magick_info) == MagickFalse) ||
1723  (GetMagickEncoderThreadSupport(magick_info) == MagickFalse))
1724  magick_info->semaphore=AcquireSemaphoreInfo();
1725  status=AddValueToSplayTree(magick_list,magick_info->name,magick_info);
1726  return(status);
1727 }
1728 
1729 /*
1730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731 % %
1732 % %
1733 % %
1734 + R e s e t M a g i c k P r e c i s i o n %
1735 % %
1736 % %
1737 % %
1738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739 %
1740 % ResetMagickPrecision() resets the magick_precision value.
1741 %
1742 % The format of the ResetMagickPrecision method is:
1743 %
1744 % void ResetMagickPrecision(void)
1745 %
1746 */
1747 MagickPrivate void ResetMagickPrecision(void)
1748 {
1749  magick_precision=0;
1750 }
1751 
1752 /*
1753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754 % %
1755 % %
1756 % %
1757 % S e t M a g i c k P r e c i s i o n %
1758 % %
1759 % %
1760 % %
1761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762 %
1763 % SetMagickPrecision() sets the maximum number of significant digits to be
1764 % printed.
1765 %
1766 % An input argument of 0 returns the current precision setting.
1767 %
1768 % A negative value forces the precision to reset to a default value according
1769 % to the environment variable "MAGICK_PRECISION", the current 'policy'
1770 % configuration setting, or the default value of '6', in that order.
1771 %
1772 % The format of the SetMagickPrecision method is:
1773 %
1774 % int SetMagickPrecision(const int precision)
1775 %
1776 % A description of each parameter follows:
1777 %
1778 % o precision: set the maximum number of significant digits to be printed.
1779 %
1780 */
1781 MagickExport int SetMagickPrecision(const int precision)
1782 {
1783 #define MagickPrecision (MAGICKCORE_QUANTUM_DEPTH/8+4)
1784 
1785  if (IsEventLogging() != MagickFalse)
1786  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1787  if (precision > 0)
1788  magick_precision=precision;
1789  if ((precision < 0) || (magick_precision == 0))
1790  {
1791  char
1792  *limit;
1793 
1795  *exception = AcquireExceptionInfo();
1796 
1797  magick_precision=MagickPrecision;
1798  limit=(char *) GetImageRegistry(StringRegistryType,"precision",exception);
1799  exception=DestroyExceptionInfo(exception);
1800  if (limit == (char *) NULL)
1801  limit=GetEnvironmentValue("MAGICK_PRECISION");
1802  if (limit == (char *) NULL)
1803  limit=GetPolicyValue("system:precision"); /* deprecated */
1804  if (limit != (char *) NULL)
1805  {
1806  magick_precision=StringToInteger(limit);
1807  limit=DestroyString(limit);
1808  }
1809  }
1810  return(magick_precision);
1811 }
1812 
1813 /*
1814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815 % %
1816 % %
1817 % %
1818 + U n r e g i s t e r M a g i c k I n f o %
1819 % %
1820 % %
1821 % %
1822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1823 %
1824 % UnregisterMagickInfo() removes a name from the magick info list. It returns
1825 % MagickFalse if the name does not exist in the list otherwise MagickTrue.
1826 %
1827 % The format of the UnregisterMagickInfo method is:
1828 %
1829 % MagickBooleanType UnregisterMagickInfo(const char *name)
1830 %
1831 % A description of each parameter follows:
1832 %
1833 % o name: a character string that represents the image format we are
1834 % looking for.
1835 %
1836 */
1837 MagickExport MagickBooleanType UnregisterMagickInfo(const char *name)
1838 {
1839  const MagickInfo
1840  *p;
1841 
1842  MagickBooleanType
1843  status;
1844 
1845  assert(name != (const char *) NULL);
1846  if (magick_list == (SplayTreeInfo *) NULL)
1847  return(MagickFalse);
1848  if (GetNumberOfNodesInSplayTree(magick_list) == 0)
1849  return(MagickFalse);
1850  LockSemaphoreInfo(magick_semaphore);
1851  ResetSplayTreeIterator(magick_list);
1852  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
1853  while (p != (const MagickInfo *) NULL)
1854  {
1855  if (LocaleCompare(p->name,name) == 0)
1856  break;
1857  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
1858  }
1859  status=DeleteNodeByValueFromSplayTree(magick_list,p);
1860  UnlockSemaphoreInfo(magick_semaphore);
1861  return(status);
1862 }
_SplayTreeInfo
Definition: splay-tree.c:83
_MagickInfo
Definition: magick.h:66
SemaphoreInfo
Definition: semaphore.c:60
_ExceptionInfo
Definition: exception.h:101