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