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