configure.c revision 7c9770650f31145e0fe8811d10b2e0ecd47697c8
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%          CCCC   OOO   N   N  FFFFF  IIIII   GGGG  U   U  RRRR   EEEEE       %
7%         C      O   O  NN  N  F        I    G      U   U  R   R  E           %
8%         C      O   O  N N N  FFF      I    G GG   U   U  RRRR   EEE         %
9%         C      O   O  N  NN  F        I    G   G  U   U  R R    E           %
10%          CCCC   OOO   N   N  F      IIIII   GGG    UUU   R  R   EEEEE       %
11%                                                                             %
12%                                                                             %
13%                      MagickCore Image Configure Methods                     %
14%                                                                             %
15%                              Software Design                                %
16%                                   Cristy                                    %
17%                                 July 2003                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/client.h"
45#include "MagickCore/configure.h"
46#include "MagickCore/configure-private.h"
47#include "MagickCore/exception.h"
48#include "MagickCore/exception-private.h"
49#include "MagickCore/hashmap.h"
50#include "MagickCore/log.h"
51#include "MagickCore/memory_.h"
52#include "MagickCore/semaphore.h"
53#include "MagickCore/string_.h"
54#include "MagickCore/string-private.h"
55#include "MagickCore/token.h"
56#include "MagickCore/utility.h"
57#include "MagickCore/utility-private.h"
58#include "MagickCore/xml-tree.h"
59#include "MagickCore/xml-tree-private.h"
60
61/*
62  Define declarations.
63*/
64#define ConfigureFilename  "configure.xml"
65
66#ifdef _OPENMP
67#define MAGICKCORE_FEATURE_OPENMP_STR "OpenMP "
68#else
69#define MAGICKCORE_FEATURE_OPENMP_STR ""
70#endif
71#ifdef _OPENCL
72#define MAGICKCORE_FEATURE_OPENCL_STR "OpenCL "
73#else
74#define MAGICKCORE_FEATURE_OPENCL_STR ""
75#endif
76#ifdef MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
77#define MAGICKCORE_FEATURE_ZERO_CONFIGURATION_STR "Zero-Configuration "
78#else
79#define MAGICKCORE_FEATURE_ZERO_CONFIGURATION_STR ""
80#endif
81#ifdef HDRI_SUPPORT
82#define MAGICKCORE_FEATURE_HDRI_STR "HDRI"
83#else
84#define MAGICKCORE_FEATURE_HDRI_STR ""
85#endif
86
87#define MAGICKCORE_FEATURES_STR MAGICKCORE_FEATURE_OPENMP_STR MAGICKCORE_FEATURE_OPENCL_STR MAGICKCORE_FEATURE_ZERO_CONFIGURATION_STR MAGICKCORE_FEATURE_HDRI_STR
88
89/*
90  Typedef declarations.
91*/
92typedef struct _ConfigureMapInfo
93{
94  const char
95    *name,
96    *value;
97} ConfigureMapInfo;
98
99/*
100  Static declarations.
101*/
102static const ConfigureMapInfo
103  ConfigureMap[] =
104  {
105    { "NAME", "ImageMagick" },
106    { "QuantumDepth", MAGICKCORE_STRING_XQUOTE(MAGICKCORE_QUANTUM_DEPTH) } ,
107    { "FEATURES", MAGICKCORE_FEATURES_STR }
108  };
109
110static LinkedListInfo
111  *configure_cache = (LinkedListInfo *) NULL;
112
113static SemaphoreInfo
114  *configure_semaphore = (SemaphoreInfo *) NULL;
115
116/*
117  Forward declarations.
118*/
119static MagickBooleanType
120  IsConfigureCacheInstantiated(ExceptionInfo *),
121  LoadConfigureCache(LinkedListInfo *,const char *,const char *,const size_t,
122    ExceptionInfo *);
123
124/*
125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126%                                                                             %
127%                                                                             %
128%                                                                             %
129%  A c q u i r e C o n f i g u r e C a c h e                                  %
130%                                                                             %
131%                                                                             %
132%                                                                             %
133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134%
135%  AcquireConfigureCache() caches one or more configure configurations which
136%  provides a mapping between configure attributes and a configure name.
137%
138%  The format of the AcquireConfigureCache method is:
139%
140%      LinkedListInfo *AcquireConfigureCache(const char *filename,
141%        ExceptionInfo *exception)
142%
143%  A description of each parameter follows:
144%
145%    o filename: the font file name.
146%
147%    o exception: return any errors or warnings in this structure.
148%
149*/
150static LinkedListInfo *AcquireConfigureCache(const char *filename,
151  ExceptionInfo *exception)
152{
153  const StringInfo
154    *option;
155
156  LinkedListInfo
157    *configure_cache,
158    *options;
159
160  MagickStatusType
161    status;
162
163  register ssize_t
164    i;
165
166  /*
167    Load external configure map.
168  */
169  configure_cache=NewLinkedList(0);
170  if (configure_cache == (LinkedListInfo *) NULL)
171    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
172  status=MagickTrue;
173  options=GetConfigureOptions(filename,exception);
174  option=(const StringInfo *) GetNextValueInLinkedList(options);
175  while (option != (const StringInfo *) NULL)
176  {
177    status&=LoadConfigureCache(configure_cache,(const char *)
178      GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
179    option=(const StringInfo *) GetNextValueInLinkedList(options);
180  }
181  options=DestroyConfigureOptions(options);
182  /*
183    Load built-in configure map.
184  */
185  for (i=0; i < (ssize_t) (sizeof(ConfigureMap)/sizeof(*ConfigureMap)); i++)
186  {
187    ConfigureInfo
188      *configure_info;
189
190    register const ConfigureMapInfo
191      *p;
192
193    p=ConfigureMap+i;
194    configure_info=(ConfigureInfo *) AcquireMagickMemory(
195      sizeof(*configure_info));
196    if (configure_info == (ConfigureInfo *) NULL)
197      {
198        (void) ThrowMagickException(exception,GetMagickModule(),
199          ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
200        continue;
201      }
202    (void) ResetMagickMemory(configure_info,0,sizeof(*configure_info));
203    configure_info->path=(char *) "[built-in]";
204    configure_info->name=(char *) p->name;
205    configure_info->value=(char *) p->value;
206    configure_info->exempt=MagickTrue;
207    configure_info->signature=MagickSignature;
208    status&=AppendValueToLinkedList(configure_cache,configure_info);
209    if (status == MagickFalse)
210      (void) ThrowMagickException(exception,GetMagickModule(),
211        ResourceLimitError,"MemoryAllocationFailed","`%s'",
212        configure_info->name);
213  }
214  return(configure_cache);
215}
216
217/*
218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219%                                                                             %
220%                                                                             %
221%                                                                             %
222+   C o n f i g u r e C o m p o n e n t G e n e s i s                         %
223%                                                                             %
224%                                                                             %
225%                                                                             %
226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227%
228%  ConfigureComponentGenesis() instantiates the configure component.
229%
230%  The format of the ConfigureComponentGenesis method is:
231%
232%      MagickBooleanType ConfigureComponentGenesis(void)
233%
234*/
235MagickPrivate MagickBooleanType ConfigureComponentGenesis(void)
236{
237  if (configure_semaphore == (SemaphoreInfo *) NULL)
238    configure_semaphore=AcquireSemaphoreInfo();
239  return(MagickTrue);
240}
241
242/*
243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244%                                                                             %
245%                                                                             %
246%                                                                             %
247+   C o n f i g u r e C o m p o n e n t T e r m i n u s                       %
248%                                                                             %
249%                                                                             %
250%                                                                             %
251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252%
253%  ConfigureComponentTerminus() destroys the configure component.
254%
255%  The format of the ConfigureComponentTerminus method is:
256%
257%      ConfigureComponentTerminus(void)
258%
259*/
260
261static void *DestroyConfigureElement(void *configure_info)
262{
263  register ConfigureInfo
264    *p;
265
266  p=(ConfigureInfo *) configure_info;
267  if (p->exempt == MagickFalse)
268    {
269      if (p->value != (char *) NULL)
270        p->value=DestroyString(p->value);
271      if (p->name != (char *) NULL)
272        p->name=DestroyString(p->name);
273      if (p->path != (char *) NULL)
274        p->path=DestroyString(p->path);
275    }
276  p=(ConfigureInfo *) RelinquishMagickMemory(p);
277  return((void *) NULL);
278}
279
280MagickPrivate void ConfigureComponentTerminus(void)
281{
282  if (configure_semaphore == (SemaphoreInfo *) NULL)
283    ActivateSemaphoreInfo(&configure_semaphore);
284  LockSemaphoreInfo(configure_semaphore);
285  if (configure_cache != (LinkedListInfo *) NULL)
286    configure_cache=DestroyLinkedList(configure_cache,DestroyConfigureElement);
287  configure_cache=(LinkedListInfo *) NULL;
288  UnlockSemaphoreInfo(configure_semaphore);
289  RelinquishSemaphoreInfo(&configure_semaphore);
290}
291
292/*
293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294%                                                                             %
295%                                                                             %
296%                                                                             %
297%   D e s t r o y C o n f i g u r e O p t i o n s                             %
298%                                                                             %
299%                                                                             %
300%                                                                             %
301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302%
303%  DestroyConfigureOptions() releases memory associated with an configure
304%  options.
305%
306%  The format of the DestroyProfiles method is:
307%
308%      LinkedListInfo *DestroyConfigureOptions(Image *image)
309%
310%  A description of each parameter follows:
311%
312%    o image: the image.
313%
314*/
315
316static void *DestroyOptions(void *option)
317{
318  return(DestroyStringInfo((StringInfo *) option));
319}
320
321MagickExport LinkedListInfo *DestroyConfigureOptions(LinkedListInfo *options)
322{
323  assert(options != (LinkedListInfo *) NULL);
324  return(DestroyLinkedList(options,DestroyOptions));
325}
326
327/*
328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329%                                                                             %
330%                                                                             %
331%                                                                             %
332+   G e t C o n f i g u r e I n f o                                           %
333%                                                                             %
334%                                                                             %
335%                                                                             %
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337%
338%  GetConfigureInfo() searches the configure list for the specified name and if
339%  found returns attributes for that element.
340%
341%  The format of the GetConfigureInfo method is:
342%
343%      const ConfigureInfo *GetConfigureInfo(const char *name,
344%        ExceptionInfo *exception)
345%
346%  A description of each parameter follows:
347%
348%    o configure_info: GetConfigureInfo() searches the configure list for the
349%      specified name and if found returns attributes for that element.
350%
351%    o name: the configure name.
352%
353%    o exception: return any errors or warnings in this structure.
354%
355*/
356MagickExport const ConfigureInfo *GetConfigureInfo(const char *name,
357  ExceptionInfo *exception)
358{
359  register const ConfigureInfo
360    *p;
361
362  assert(exception != (ExceptionInfo *) NULL);
363  if (IsConfigureCacheInstantiated(exception) == MagickFalse)
364    return((const ConfigureInfo *) NULL);
365  /*
366    Search for configure tag.
367  */
368  LockSemaphoreInfo(configure_semaphore);
369  ResetLinkedListIterator(configure_cache);
370  p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_cache);
371  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
372    {
373      UnlockSemaphoreInfo(configure_semaphore);
374      return(p);
375    }
376  while (p != (const ConfigureInfo *) NULL)
377  {
378    if (LocaleCompare(name,p->name) == 0)
379      break;
380    p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_cache);
381  }
382  if (p != (ConfigureInfo *) NULL)
383    (void) InsertValueInLinkedList(configure_cache,0,
384      RemoveElementByValueFromLinkedList(configure_cache,p));
385  UnlockSemaphoreInfo(configure_semaphore);
386  return(p);
387}
388
389/*
390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
391%                                                                             %
392%                                                                             %
393%                                                                             %
394%   G e t C o n f i g u r e I n f o L i s t                                   %
395%                                                                             %
396%                                                                             %
397%                                                                             %
398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399%
400%  GetConfigureInfoList() returns any configure options that match the
401%  specified pattern.
402%
403%  The format of the GetConfigureInfoList function is:
404%
405%      const ConfigureInfo **GetConfigureInfoList(const char *pattern,
406%        size_t *number_options,ExceptionInfo *exception)
407%
408%  A description of each parameter follows:
409%
410%    o pattern: Specifies a pointer to a text string containing a pattern.
411%
412%    o number_options:  This integer returns the number of configure options in
413%    the list.
414%
415%    o exception: return any errors or warnings in this structure.
416%
417*/
418
419#if defined(__cplusplus) || defined(c_plusplus)
420extern "C" {
421#endif
422
423static int ConfigureInfoCompare(const void *x,const void *y)
424{
425  const ConfigureInfo
426    **p,
427    **q;
428
429  p=(const ConfigureInfo **) x,
430  q=(const ConfigureInfo **) y;
431  if (LocaleCompare((*p)->path,(*q)->path) == 0)
432    return(LocaleCompare((*p)->name,(*q)->name));
433  return(LocaleCompare((*p)->path,(*q)->path));
434}
435
436#if defined(__cplusplus) || defined(c_plusplus)
437}
438#endif
439
440MagickExport const ConfigureInfo **GetConfigureInfoList(const char *pattern,
441  size_t *number_options,ExceptionInfo *exception)
442{
443  const ConfigureInfo
444    **options;
445
446  register const ConfigureInfo
447    *p;
448
449  register ssize_t
450    i;
451
452  /*
453    Allocate configure list.
454  */
455  assert(pattern != (char *) NULL);
456  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
457  assert(number_options != (size_t *) NULL);
458  *number_options=0;
459  p=GetConfigureInfo("*",exception);
460  if (p == (const ConfigureInfo *) NULL)
461    return((const ConfigureInfo **) NULL);
462  options=(const ConfigureInfo **) AcquireQuantumMemory((size_t)
463    GetNumberOfElementsInLinkedList(configure_cache)+1UL,sizeof(*options));
464  if (options == (const ConfigureInfo **) NULL)
465    return((const ConfigureInfo **) NULL);
466  /*
467    Generate configure list.
468  */
469  LockSemaphoreInfo(configure_semaphore);
470  ResetLinkedListIterator(configure_cache);
471  p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_cache);
472  for (i=0; p != (const ConfigureInfo *) NULL; )
473  {
474    if ((p->stealth == MagickFalse) &&
475        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
476      options[i++]=p;
477    p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_cache);
478  }
479  UnlockSemaphoreInfo(configure_semaphore);
480  qsort((void *) options,(size_t) i,sizeof(*options),ConfigureInfoCompare);
481  options[i]=(ConfigureInfo *) NULL;
482  *number_options=(size_t) i;
483  return(options);
484}
485
486/*
487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
488%                                                                             %
489%                                                                             %
490%                                                                             %
491%   G e t C o n f i g u r e L i s t                                           %
492%                                                                             %
493%                                                                             %
494%                                                                             %
495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
496%
497%  GetConfigureList() returns any configure options that match the specified
498%  pattern.
499%
500%  The format of the GetConfigureList function is:
501%
502%      char **GetConfigureList(const char *pattern,
503%        size_t *number_options,ExceptionInfo *exception)
504%
505%  A description of each parameter follows:
506%
507%    o pattern: Specifies a pointer to a text string containing a pattern.
508%
509%    o number_options:  This integer returns the number of options in the list.
510%
511%    o exception: return any errors or warnings in this structure.
512%
513*/
514
515#if defined(__cplusplus) || defined(c_plusplus)
516extern "C" {
517#endif
518
519static int ConfigureCompare(const void *x,const void *y)
520{
521  register char
522    **p,
523    **q;
524
525  p=(char **) x;
526  q=(char **) y;
527  return(LocaleCompare(*p,*q));
528}
529
530#if defined(__cplusplus) || defined(c_plusplus)
531}
532#endif
533
534MagickExport char **GetConfigureList(const char *pattern,
535  size_t *number_options,ExceptionInfo *exception)
536{
537  char
538    **options;
539
540  register const ConfigureInfo
541    *p;
542
543  register ssize_t
544    i;
545
546  /*
547    Allocate configure list.
548  */
549  assert(pattern != (char *) NULL);
550  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
551  assert(number_options != (size_t *) NULL);
552  *number_options=0;
553  p=GetConfigureInfo("*",exception);
554  if (p == (const ConfigureInfo *) NULL)
555    return((char **) NULL);
556  options=(char **) AcquireQuantumMemory((size_t)
557    GetNumberOfElementsInLinkedList(configure_cache)+1UL,sizeof(*options));
558  if (options == (char **) NULL)
559    return((char **) NULL);
560  LockSemaphoreInfo(configure_semaphore);
561  ResetLinkedListIterator(configure_cache);
562  p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_cache);
563  for (i=0; p != (const ConfigureInfo *) NULL; )
564  {
565    if ((p->stealth == MagickFalse) &&
566        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
567      options[i++]=ConstantString(p->name);
568    p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_cache);
569  }
570  UnlockSemaphoreInfo(configure_semaphore);
571  qsort((void *) options,(size_t) i,sizeof(*options),ConfigureCompare);
572  options[i]=(char *) NULL;
573  *number_options=(size_t) i;
574  return(options);
575}
576
577/*
578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
579%                                                                             %
580%                                                                             %
581%                                                                             %
582%   G e t C o n f i g u r e O p t i o n                                       %
583%                                                                             %
584%                                                                             %
585%                                                                             %
586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
587%
588%  GetConfigureOption() returns the value associated with the configure option.
589%
590%  The format of the GetConfigureOption method is:
591%
592%      char *GetConfigureOption(const char *option)
593%
594%  A description of each parameter follows:
595%
596%    o configure_info:  The configure info.
597%
598*/
599MagickExport char *GetConfigureOption(const char *option)
600{
601  const char
602    *value;
603
604  const ConfigureInfo
605    *configure_info;
606
607  ExceptionInfo
608    *exception;
609
610  assert(option != (const char *) NULL);
611  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",option);
612  exception=AcquireExceptionInfo();
613  configure_info=GetConfigureInfo(option,exception);
614  exception=DestroyExceptionInfo(exception);
615  if (configure_info == (ConfigureInfo *) NULL)
616    return((char *) NULL);
617  value=GetConfigureValue(configure_info);
618  if ((value == (const char *) NULL) || (*value == '\0'))
619    return((char *) NULL);
620  return(ConstantString(value));
621}
622
623/*
624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625%                                                                             %
626%                                                                             %
627%                                                                             %
628%  G e t C o n f i g u r e O p t i o n s                                      %
629%                                                                             %
630%                                                                             %
631%                                                                             %
632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
633%
634%  GetConfigureOptions() returns any Magick configuration options associated
635%  with the specified filename.
636%
637%  The format of the GetConfigureOptions method is:
638%
639%      LinkedListInfo *GetConfigureOptions(const char *filename,
640%        ExceptionInfo *exception)
641%
642%  A description of each parameter follows:
643%
644%    o filename: the configure file name.
645%
646%    o exception: return any errors or warnings in this structure.
647%
648*/
649MagickExport LinkedListInfo *GetConfigureOptions(const char *filename,
650  ExceptionInfo *exception)
651{
652  char
653    path[MaxTextExtent];
654
655  const char
656    *element;
657
658  LinkedListInfo
659    *options,
660    *paths;
661
662  StringInfo
663    *xml;
664
665  assert(filename != (const char *) NULL);
666  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
667  assert(exception != (ExceptionInfo *) NULL);
668  (void) CopyMagickString(path,filename,MaxTextExtent);
669  /*
670    Load XML from configuration files to linked-list.
671  */
672  options=NewLinkedList(0);
673  paths=GetConfigurePaths(filename,exception);
674  if (paths != (LinkedListInfo *) NULL)
675    {
676      ResetLinkedListIterator(paths);
677      element=(const char *) GetNextValueInLinkedList(paths);
678      while (element != (const char *) NULL)
679      {
680        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",element,filename);
681        (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
682          "Searching for configure file: \"%s\"",path);
683        xml=ConfigureFileToStringInfo(path);
684        if (xml != (StringInfo *) NULL)
685          (void) AppendValueToLinkedList(options,xml);
686        element=(const char *) GetNextValueInLinkedList(paths);
687      }
688      paths=DestroyLinkedList(paths,RelinquishMagickMemory);
689    }
690#if defined(MAGICKCORE_WINDOWS_SUPPORT)
691  if (GetNumberOfElementsInLinkedList(options) == 0)
692    {
693      char
694        *blob;
695
696      blob=(char *) NTResourceToBlob(filename);
697      if (blob != (char *) NULL)
698        {
699          xml=AcquireStringInfo(0);
700          SetStringInfoLength(xml,strlen(blob)+1);
701          SetStringInfoDatum(xml,(unsigned char *) blob);
702          SetStringInfoPath(xml,filename);
703          (void) AppendValueToLinkedList(options,xml);
704        }
705    }
706#endif
707  if (GetNumberOfElementsInLinkedList(options) == 0)
708    (void) ThrowMagickException(exception,GetMagickModule(),ConfigureWarning,
709      "UnableToOpenConfigureFile","`%s'",filename);
710  ResetLinkedListIterator(options);
711  return(options);
712}
713
714/*
715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716%                                                                             %
717%                                                                             %
718%                                                                             %
719%  G e t C o n f i g u r e P a t h s                                          %
720%                                                                             %
721%                                                                             %
722%                                                                             %
723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
724%
725%  GetConfigurePaths() returns any Magick configuration paths associated
726%  with the specified filename.
727%
728%  The format of the GetConfigurePaths method is:
729%
730%      LinkedListInfo *GetConfigurePaths(const char *filename,
731%        ExceptionInfo *exception)
732%
733%  A description of each parameter follows:
734%
735%    o filename: the configure file name.
736%
737%    o exception: return any errors or warnings in this structure.
738%
739*/
740MagickExport LinkedListInfo *GetConfigurePaths(const char *filename,
741  ExceptionInfo *exception)
742{
743#define RegistryKey  "ConfigurePath"
744#define MagickCoreDLL  "CORE_RL_MagickCore_.dll"
745#define MagickCoreDebugDLL  "CORE_DB_MagickCore_.dll"
746
747  char
748    path[MaxTextExtent];
749
750  LinkedListInfo
751    *paths;
752
753  assert(filename != (const char *) NULL);
754  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
755  assert(exception != (ExceptionInfo *) NULL);
756  (void) CopyMagickString(path,filename,MaxTextExtent);
757  paths=NewLinkedList(0);
758  {
759    char
760      *configure_path;
761
762    /*
763      Search $MAGICK_CONFIGURE_PATH.
764    */
765    configure_path=GetEnvironmentValue("MAGICK_CONFIGURE_PATH");
766    if (configure_path != (char *) NULL)
767      {
768        register char
769          *p,
770          *q;
771
772        for (p=configure_path-1; p != (char *) NULL; )
773        {
774          (void) CopyMagickString(path,p+1,MaxTextExtent);
775          q=strchr(path,DirectoryListSeparator);
776          if (q != (char *) NULL)
777            *q='\0';
778          q=path+strlen(path)-1;
779          if ((q >= path) && (*q != *DirectorySeparator))
780            (void) ConcatenateMagickString(path,DirectorySeparator,
781              MaxTextExtent);
782          (void) AppendValueToLinkedList(paths,ConstantString(path));
783          p=strchr(p+1,DirectoryListSeparator);
784        }
785        configure_path=DestroyString(configure_path);
786      }
787  }
788#if defined(MAGICKCORE_INSTALLED_SUPPORT)
789#if defined(MAGICKCORE_SHARE_PATH)
790  (void) AppendValueToLinkedList(paths,ConstantString(MAGICKCORE_SHARE_PATH));
791#endif
792#if defined(MAGICKCORE_SHAREARCH_PATH)
793  (void) AppendValueToLinkedList(paths,ConstantString(
794    MAGICKCORE_SHAREARCH_PATH));
795#endif
796#if defined(MAGICKCORE_CONFIGURE_PATH)
797  (void) AppendValueToLinkedList(paths,ConstantString(
798    MAGICKCORE_CONFIGURE_PATH));
799#endif
800#if defined(MAGICKCORE_DOCUMENTATION_PATH)
801  (void) AppendValueToLinkedList(paths,ConstantString(
802    MAGICKCORE_DOCUMENTATION_PATH));
803#endif
804#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !(defined(MAGICKCORE_CONFIGURE_PATH) || defined(MAGICKCORE_SHARE_PATH))
805  {
806    unsigned char
807      *key_value;
808
809    /*
810      Locate file via registry key.
811    */
812    key_value=NTRegistryKeyLookup(RegistryKey);
813    if (key_value != (unsigned char *) NULL)
814      {
815        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",(char *) key_value,
816          DirectorySeparator);
817        (void) AppendValueToLinkedList(paths,ConstantString(path));
818        key_value=(unsigned char *) RelinquishMagickMemory(key_value);
819      }
820  }
821#endif
822#else
823  {
824    char
825      *home;
826
827    /*
828      Search under MAGICK_HOME.
829    */
830    home=GetEnvironmentValue("MAGICK_HOME");
831    if (home != (char *) NULL)
832      {
833#if !defined(MAGICKCORE_POSIX_SUPPORT)
834        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",home,
835          DirectorySeparator);
836        (void) AppendValueToLinkedList(paths,ConstantString(path));
837#else
838        (void) FormatLocaleString(path,MaxTextExtent,"%s/etc/%s/",home,
839          MAGICKCORE_CONFIGURE_RELATIVE_PATH);
840        (void) AppendValueToLinkedList(paths,ConstantString(path));
841        (void) FormatLocaleString(path,MaxTextExtent,"%s/share/%s/",home,
842          MAGICKCORE_SHARE_RELATIVE_PATH);
843        (void) AppendValueToLinkedList(paths,ConstantString(path));
844        (void) FormatLocaleString(path,MaxTextExtent,"%s",
845          MAGICKCORE_SHAREARCH_PATH);
846        (void) AppendValueToLinkedList(paths,ConstantString(path));
847#endif
848        home=DestroyString(home);
849      }
850    }
851  if (*GetClientPath() != '\0')
852    {
853#if !defined(MAGICKCORE_POSIX_SUPPORT)
854      (void) FormatLocaleString(path,MaxTextExtent,"%s%s",GetClientPath(),
855        DirectorySeparator);
856      (void) AppendValueToLinkedList(paths,ConstantString(path));
857#else
858      char
859        prefix[MaxTextExtent];
860
861      /*
862        Search based on executable directory if directory is known.
863      */
864      (void) CopyMagickString(prefix,GetClientPath(),MaxTextExtent);
865      ChopPathComponents(prefix,1);
866      (void) FormatLocaleString(path,MaxTextExtent,"%s/etc/%s/",prefix,
867        MAGICKCORE_CONFIGURE_RELATIVE_PATH);
868      (void) AppendValueToLinkedList(paths,ConstantString(path));
869      (void) FormatLocaleString(path,MaxTextExtent,"%s/share/%s/",prefix,
870        MAGICKCORE_SHARE_RELATIVE_PATH);
871      (void) AppendValueToLinkedList(paths,ConstantString(path));
872      (void) FormatLocaleString(path,MaxTextExtent,"%s",
873        MAGICKCORE_SHAREARCH_PATH);
874      (void) AppendValueToLinkedList(paths,ConstantString(path));
875#endif
876    }
877  /*
878    Search current directory.
879  */
880  (void) AppendValueToLinkedList(paths,ConstantString(""));
881#endif
882  {
883    char
884      *home;
885
886    home=GetEnvironmentValue("HOME");
887    if (home == (char *) NULL)
888      home=GetEnvironmentValue("USERPROFILE");
889    if (home != (char *) NULL)
890      {
891        /*
892          Search $HOME/.config/ImageMagick.
893        */
894        (void) FormatLocaleString(path,MaxTextExtent,
895          "%s%s.config%sImageMagick%s",home,DirectorySeparator,
896          DirectorySeparator,DirectorySeparator);
897        (void) AppendValueToLinkedList(paths,ConstantString(path));
898        home=DestroyString(home);
899      }
900  }
901#if defined(MAGICKCORE_WINDOWS_SUPPORT)
902  {
903    char
904      module_path[MaxTextExtent];
905
906    if ((NTGetModulePath(MagickCoreDLL,module_path) != MagickFalse) ||
907        (NTGetModulePath(MagickCoreDebugDLL,module_path) != MagickFalse))
908      {
909        unsigned char
910          *key_value;
911
912        /*
913          Search module path.
914        */
915        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",module_path,
916          DirectorySeparator);
917        key_value=NTRegistryKeyLookup(RegistryKey);
918        if (key_value == (unsigned char *) NULL)
919          (void) AppendValueToLinkedList(paths,ConstantString(path));
920        else
921          key_value=(unsigned char *) RelinquishMagickMemory(key_value);
922      }
923    if (NTGetModulePath("Magick.dll",module_path) != MagickFalse)
924      {
925        /*
926          Search PerlMagick module path.
927        */
928        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",module_path,
929          DirectorySeparator);
930        (void) AppendValueToLinkedList(paths,ConstantString(path));
931        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",module_path,
932          "\\inc\\lib\\auto\\Image\\Magick\\");
933        (void) AppendValueToLinkedList(paths,ConstantString(path));
934      }
935  }
936#endif
937  return(paths);
938}
939
940/*
941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
942%                                                                             %
943%                                                                             %
944%                                                                             %
945%   G e t C o n f i g u r e V a l u e                                         %
946%                                                                             %
947%                                                                             %
948%                                                                             %
949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
950%
951%  GetConfigureValue() returns the value associated with the configure info.
952%
953%  The format of the GetConfigureValue method is:
954%
955%      const char *GetConfigureValue(const ConfigureInfo *configure_info)
956%
957%  A description of each parameter follows:
958%
959%    o configure_info:  The configure info.
960%
961*/
962MagickExport const char *GetConfigureValue(const ConfigureInfo *configure_info)
963{
964  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
965  assert(configure_info != (ConfigureInfo *) NULL);
966  assert(configure_info->signature == MagickSignature);
967  return(configure_info->value);
968}
969
970/*
971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
972%                                                                             %
973%                                                                             %
974%                                                                             %
975+   I s C o n f i g u r e C a c h e I n s t a n t i a t e d                   %
976%                                                                             %
977%                                                                             %
978%                                                                             %
979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980%
981%  IsConfigureCacheInstantiated() determines if the configure list is
982%  instantiated.  If not, it instantiates the list and returns it.
983%
984%  The format of the IsConfigureInstantiated method is:
985%
986%      MagickBooleanType IsConfigureCacheInstantiated(ExceptionInfo *exception)
987%
988%  A description of each parameter follows.
989%
990%    o exception: return any errors or warnings in this structure.
991%
992*/
993static MagickBooleanType IsConfigureCacheInstantiated(ExceptionInfo *exception)
994{
995  if (configure_cache == (LinkedListInfo *) NULL)
996    {
997      if (configure_semaphore == (SemaphoreInfo *) NULL)
998        ActivateSemaphoreInfo(&configure_semaphore);
999      LockSemaphoreInfo(configure_semaphore);
1000      if (configure_cache == (LinkedListInfo *) NULL)
1001        configure_cache=AcquireConfigureCache(ConfigureFilename,exception);
1002      UnlockSemaphoreInfo(configure_semaphore);
1003    }
1004  return(configure_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
1005}
1006
1007/*
1008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009%                                                                             %
1010%                                                                             %
1011%                                                                             %
1012%  L i s t C o n f i g u r e I n f o                                          %
1013%                                                                             %
1014%                                                                             %
1015%                                                                             %
1016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1017%
1018%  ListConfigureInfo() lists the configure info to a file.
1019%
1020%  The format of the ListConfigureInfo method is:
1021%
1022%      MagickBooleanType ListConfigureInfo(FILE *file,ExceptionInfo *exception)
1023%
1024%  A description of each parameter follows.
1025%
1026%    o file:  An pointer to a FILE.
1027%
1028%    o exception: return any errors or warnings in this structure.
1029%
1030*/
1031MagickExport MagickBooleanType ListConfigureInfo(FILE *file,
1032  ExceptionInfo *exception)
1033{
1034  const char
1035    *name,
1036    *path,
1037    *value;
1038
1039  const ConfigureInfo
1040    **configure_info;
1041
1042  register ssize_t
1043    i;
1044
1045  size_t
1046    number_options;
1047
1048  ssize_t
1049    j;
1050
1051  if (file == (const FILE *) NULL)
1052    file=stdout;
1053  configure_info=GetConfigureInfoList("*",&number_options,exception);
1054  if (configure_info == (const ConfigureInfo **) NULL)
1055    return(MagickFalse);
1056  path=(const char *) NULL;
1057  for (i=0; i < (ssize_t) number_options; i++)
1058  {
1059    if (configure_info[i]->stealth != MagickFalse)
1060      continue;
1061    if ((path == (const char *) NULL) ||
1062        (LocaleCompare(path,configure_info[i]->path) != 0))
1063      {
1064        if (configure_info[i]->path != (char *) NULL)
1065          (void) FormatLocaleFile(file,"\nPath: %s\n\n",
1066            configure_info[i]->path);
1067        (void) FormatLocaleFile(file,"Name           Value\n");
1068        (void) FormatLocaleFile(file,
1069          "-------------------------------------------------"
1070          "------------------------------\n");
1071      }
1072    path=configure_info[i]->path;
1073    name="unknown";
1074    if (configure_info[i]->name != (char *) NULL)
1075      name=configure_info[i]->name;
1076    (void) FormatLocaleFile(file,"%s",name);
1077    for (j=(ssize_t) strlen(name); j <= 13; j++)
1078      (void) FormatLocaleFile(file," ");
1079    (void) FormatLocaleFile(file," ");
1080    value="unknown";
1081    if (configure_info[i]->value != (char *) NULL)
1082      value=configure_info[i]->value;
1083    (void) FormatLocaleFile(file,"%s",value);
1084    (void) FormatLocaleFile(file,"\n");
1085  }
1086  (void) fflush(file);
1087  configure_info=(const ConfigureInfo **) RelinquishMagickMemory((void *)
1088    configure_info);
1089  return(MagickTrue);
1090}
1091
1092/*
1093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094%                                                                             %
1095%                                                                             %
1096%                                                                             %
1097+   L o a d C o n f i g u r e L i s t                                         %
1098%                                                                             %
1099%                                                                             %
1100%                                                                             %
1101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102%
1103%  LoadConfigureCache() loads the configure configurations which provides a
1104%  mapping between configure attributes and a configure name.
1105%
1106%  The format of the LoadConfigureCache method is:
1107%
1108%      MagickBooleanType LoadConfigureCache(LinkedListInfo *configure_cache,
1109%        const char *xml,const char *filename,const size_t depth,ExceptionInfo *exception)
1110%
1111%  A description of each parameter follows:
1112%
1113%    o xml:  The configure list in XML format.
1114%
1115%    o filename:  The configure list filename.
1116%
1117%    o depth: depth of <include /> statements.
1118%
1119%    o exception: return any errors or warnings in this structure.
1120%
1121*/
1122static MagickBooleanType LoadConfigureCache(LinkedListInfo *configure_cache,
1123  const char *xml,const char *filename,const size_t depth,
1124  ExceptionInfo *exception)
1125{
1126  char
1127    keyword[MaxTextExtent],
1128    *token;
1129
1130  ConfigureInfo
1131    *configure_info;
1132
1133  const char
1134    *q;
1135
1136  MagickBooleanType
1137    status;
1138
1139  /*
1140    Load the configure map file.
1141  */
1142  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1143    "Loading configure file \"%s\" ...",filename);
1144  status=MagickTrue;
1145  configure_info=(ConfigureInfo *) NULL;
1146  token=AcquireString((char *) xml);
1147  for (q=(char *) xml; *q != '\0'; )
1148  {
1149    /*
1150      Interpret XML.
1151    */
1152    GetMagickToken(q,&q,token);
1153    if (*token == '\0')
1154      break;
1155    (void) CopyMagickString(keyword,token,MaxTextExtent);
1156    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1157      {
1158        /*
1159          Doctype element.
1160        */
1161        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1162          GetMagickToken(q,&q,token);
1163        continue;
1164      }
1165    if (LocaleNCompare(keyword,"<!--",4) == 0)
1166      {
1167        /*
1168          Comment element.
1169        */
1170        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1171          GetMagickToken(q,&q,token);
1172        continue;
1173      }
1174    if (LocaleCompare(keyword,"<include") == 0)
1175      {
1176        /*
1177          Include element.
1178        */
1179        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1180        {
1181          (void) CopyMagickString(keyword,token,MaxTextExtent);
1182          GetMagickToken(q,&q,token);
1183          if (*token != '=')
1184            continue;
1185          GetMagickToken(q,&q,token);
1186          if (LocaleCompare(keyword,"file") == 0)
1187            {
1188              if (depth > 200)
1189                (void) ThrowMagickException(exception,GetMagickModule(),
1190                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1191              else
1192                {
1193                  char
1194                    path[MaxTextExtent],
1195                    *xml;
1196
1197                  GetPathComponent(filename,HeadPath,path);
1198                  if (*path != '\0')
1199                    (void) ConcatenateMagickString(path,DirectorySeparator,
1200                      MaxTextExtent);
1201                  if (*token == *DirectorySeparator)
1202                    (void) CopyMagickString(path,token,MaxTextExtent);
1203                  else
1204                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
1205                  xml=FileToXML(path,~0UL);
1206                  if (xml != (char *) NULL)
1207                    {
1208                      status&=LoadConfigureCache(configure_cache,xml,path,
1209                        depth+1,exception);
1210                      xml=(char *) RelinquishMagickMemory(xml);
1211                    }
1212                }
1213            }
1214        }
1215        continue;
1216      }
1217    if (LocaleCompare(keyword,"<configure") == 0)
1218      {
1219        /*
1220          Configure element.
1221        */
1222        configure_info=(ConfigureInfo *) AcquireMagickMemory(
1223          sizeof(*configure_info));
1224        if (configure_info == (ConfigureInfo *) NULL)
1225          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1226        (void) ResetMagickMemory(configure_info,0,sizeof(*configure_info));
1227        configure_info->path=ConstantString(filename);
1228        configure_info->exempt=MagickFalse;
1229        configure_info->signature=MagickSignature;
1230        continue;
1231      }
1232    if (configure_info == (ConfigureInfo *) NULL)
1233      continue;
1234    if (LocaleCompare(keyword,"/>") == 0)
1235      {
1236        status=AppendValueToLinkedList(configure_cache,configure_info);
1237        if (status == MagickFalse)
1238          (void) ThrowMagickException(exception,GetMagickModule(),
1239            ResourceLimitError,"MemoryAllocationFailed","`%s'",
1240            configure_info->name);
1241        configure_info=(ConfigureInfo *) NULL;
1242        continue;
1243      }
1244    /*
1245      Parse configure element.
1246    */
1247    GetMagickToken(q,(const char **) NULL,token);
1248    if (*token != '=')
1249      continue;
1250    GetMagickToken(q,&q,token);
1251    GetMagickToken(q,&q,token);
1252    switch (*keyword)
1253    {
1254      case 'N':
1255      case 'n':
1256      {
1257        if (LocaleCompare((char *) keyword,"name") == 0)
1258          {
1259            configure_info->name=ConstantString(token);
1260            break;
1261          }
1262        break;
1263      }
1264      case 'S':
1265      case 's':
1266      {
1267        if (LocaleCompare((char *) keyword,"stealth") == 0)
1268          {
1269            configure_info->stealth=IsStringTrue(token);
1270            break;
1271          }
1272        break;
1273      }
1274      case 'V':
1275      case 'v':
1276      {
1277        if (LocaleCompare((char *) keyword,"value") == 0)
1278          {
1279            configure_info->value=ConstantString(token);
1280            break;
1281          }
1282        break;
1283      }
1284      default:
1285        break;
1286    }
1287  }
1288  token=(char *) RelinquishMagickMemory(token);
1289  return(status);
1290}
1291