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