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