]> granicus.if.org Git - imagemagick/blob - MagickCore/locale.c
(no commit message)
[imagemagick] / MagickCore / locale.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                  L       OOO    CCCC   AAA   L      EEEEE                   %
7 %                  L      O   O  C      A   A  L      E                       %
8 %                  L      O   O  C      AAAAA  L      EEE                     %
9 %                  L      O   O  C      A   A  L      E                       %
10 %                  LLLLL   OOO    CCCC  A   A  LLLLL  EEEEE                   %
11 %                                                                             %
12 %                                                                             %
13 %                      MagickCore Image Locale Methods                        %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 2003                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2013 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 \f
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/exception.h"
47 #include "MagickCore/exception-private.h"
48 #include "MagickCore/hashmap.h"
49 #include "MagickCore/locale_.h"
50 #include "MagickCore/locale-private.h"
51 #include "MagickCore/log.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/nt-base-private.h"
54 #include "MagickCore/semaphore.h"
55 #include "MagickCore/splay-tree.h"
56 #include "MagickCore/string_.h"
57 #include "MagickCore/string-private.h"
58 #include "MagickCore/token.h"
59 #include "MagickCore/utility.h"
60 #include "MagickCore/utility-private.h"
61 #include "MagickCore/xml-tree.h"
62 \f
63 /*
64   Define declarations.
65 */
66 #define LocaleFilename  "locale.xml"
67 #define MaxRecursionDepth  200
68 \f
69 /*
70   Typedef declarations.
71 */
72 #if defined(__CYGWIN__)
73 typedef struct _locale_t
74   *locale_t;
75 #endif
76 \f
77 /*
78   Static declarations.
79 */
80 static const char
81   *LocaleMap =
82     "<?xml version=\"1.0\"?>"
83     "<localemap>"
84     "  <locale name=\"C\">"
85     "    <Exception>"
86     "     <Message name=\"\">"
87     "     </Message>"
88     "    </Exception>"
89     "  </locale>"
90     "</localemap>";
91
92 static SemaphoreInfo
93   *locale_semaphore = (SemaphoreInfo *) NULL;
94
95 static SplayTreeInfo
96   *locale_list = (SplayTreeInfo *) NULL;
97
98 #if defined(MAGICKCORE_HAVE_STRTOD_L)
99 static volatile locale_t
100   c_locale = (locale_t) NULL;
101 #endif
102
103 static volatile MagickBooleanType
104   instantiate_locale = MagickFalse;
105 \f
106 /*
107   Forward declarations.
108 */
109 static MagickBooleanType
110   InitializeLocaleList(ExceptionInfo *),
111   LoadLocaleLists(const char *,const char *,ExceptionInfo *);
112 \f
113 #if defined(MAGICKCORE_HAVE_STRTOD_L)
114 /*
115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 %                                                                             %
117 %                                                                             %
118 %                                                                             %
119 +   A c q u i r e C L o c a l e                                               %
120 %                                                                             %
121 %                                                                             %
122 %                                                                             %
123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 %
125 %  AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
126 %  errno set if it cannot be acquired.
127 %
128 %  The format of the AcquireCLocale method is:
129 %
130 %      locale_t AcquireCLocale(void)
131 %
132 */
133 static locale_t AcquireCLocale(void)
134 {
135 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
136   if (c_locale == (locale_t) NULL)
137     c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
138 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
139   if (c_locale == (locale_t) NULL)
140     c_locale=_create_locale(LC_ALL,"C");
141 #endif
142   return(c_locale);
143 }
144 #endif
145 \f
146 #if defined(MAGICKCORE_HAVE_STRTOD_L)
147 /*
148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149 %                                                                             %
150 %                                                                             %
151 %                                                                             %
152 +   D e s t r o y C L o c a l e                                               %
153 %                                                                             %
154 %                                                                             %
155 %                                                                             %
156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 %
158 %  DestroyCLocale() releases the resources allocated for a locale object
159 %  returned by a call to the AcquireCLocale() method.
160 %
161 %  The format of the DestroyCLocale method is:
162 %
163 %      void DestroyCLocale(void)
164 %
165 */
166 static void DestroyCLocale(void)
167 {
168 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
169   if (c_locale != (locale_t) NULL)
170     freelocale(c_locale);
171 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
172   if (c_locale != (locale_t) NULL)
173     _free_locale(c_locale);
174 #endif
175   c_locale=(locale_t) NULL;
176 }
177 #endif
178 \f
179 /*
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
181 %                                                                             %
182 %                                                                             %
183 %                                                                             %
184 %   D e s t r o y L o c a l e O p t i o n s                                   %
185 %                                                                             %
186 %                                                                             %
187 %                                                                             %
188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189 %
190 %  DestroyLocaleOptions() releases memory associated with an locale
191 %  messages.
192 %
193 %  The format of the DestroyProfiles method is:
194 %
195 %      LinkedListInfo *DestroyLocaleOptions(Image *image)
196 %
197 %  A description of each parameter follows:
198 %
199 %    o image: the image.
200 %
201 */
202
203 static void *DestroyOptions(void *message)
204 {
205   return(DestroyStringInfo((StringInfo *) message));
206 }
207
208 MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
209 {
210   assert(messages != (LinkedListInfo *) NULL);
211   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
212   return(DestroyLinkedList(messages,DestroyOptions));
213 }
214 \f
215 /*
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 %                                                                             %
218 %                                                                             %
219 %                                                                             %
220 +  F o r m a t L o c a l e F i l e                                            %
221 %                                                                             %
222 %                                                                             %
223 %                                                                             %
224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225 %
226 %  FormatLocaleFile() prints formatted output of a variable argument list to a
227 %  file in the "C" locale.
228 %
229 %  The format of the FormatLocaleFile method is:
230 %
231 %      ssize_t FormatLocaleFile(FILE *file,const char *format,...)
232 %
233 %  A description of each parameter follows.
234 %
235 %   o file:  the file.
236 %
237 %   o format:  A file describing the format to use to write the remaining
238 %     arguments.
239 %
240 */
241
242 MagickPrivate ssize_t FormatLocaleFileList(FILE *file,
243   const char *restrict format,va_list operands)
244 {
245   ssize_t
246     n;
247
248 #if defined(MAGICKCORE_HAVE_VFPRINTF_L)
249   {
250     locale_t
251       locale;
252
253     locale=AcquireCLocale();
254     if (locale == (locale_t) NULL)
255       n=(ssize_t) vfprintf(file,format,operands);
256     else
257 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
258       n=(ssize_t) vfprintf_l(file,format,locale,operands);
259 #else
260       n=(ssize_t) vfprintf_l(file,locale,format,operands);
261 #endif
262   }
263 #else
264 #if defined(MAGICKCORE_HAVE_USELOCALE)
265   {
266     locale_t
267       locale,
268       previous_locale;
269
270     locale=AcquireCLocale();
271     if (locale == (locale_t) NULL)
272       n=(ssize_t) vfprintf(file,format,operands);
273     else
274       {
275         previous_locale=uselocale(locale);
276         n=(ssize_t) vfprintf(file,format,operands);
277         uselocale(previous_locale);
278       }
279   }
280 #else
281   n=(ssize_t) vfprintf(file,format,operands);
282 #endif
283 #endif
284   return(n);
285 }
286
287 MagickExport ssize_t FormatLocaleFile(FILE *file,const char *restrict format,
288   ...)
289 {
290   ssize_t
291     n;
292
293   va_list
294     operands;
295
296   va_start(operands,format);
297   n=FormatLocaleFileList(file,format,operands);
298   va_end(operands);
299   return(n);
300 }
301 \f
302 /*
303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304 %                                                                             %
305 %                                                                             %
306 %                                                                             %
307 +  F o r m a t L o c a l e S t r i n g                                        %
308 %                                                                             %
309 %                                                                             %
310 %                                                                             %
311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 %
313 %  FormatLocaleString() prints formatted output of a variable argument list to
314 %  a string buffer in the "C" locale.
315 %
316 %  The format of the FormatLocaleString method is:
317 %
318 %      ssize_t FormatLocaleString(char *string,const size_t length,
319 %        const char *format,...)
320 %
321 %  A description of each parameter follows.
322 %
323 %   o string:  FormatLocaleString() returns the formatted string in this
324 %     character buffer.
325 %
326 %   o length: the maximum length of the string.
327 %
328 %   o format:  A string describing the format to use to write the remaining
329 %     arguments.
330 %
331 */
332
333 MagickPrivate ssize_t FormatLocaleStringList(char *restrict string,
334   const size_t length,const char *restrict format,va_list operands)
335 {
336   ssize_t
337     n;
338
339 #if defined(MAGICKCORE_HAVE_VSNPRINTF_L)
340   {
341     locale_t
342       locale;
343
344     locale=AcquireCLocale();
345     if (locale == (locale_t) NULL)
346       n=(ssize_t) vsnprintf(string,length,format,operands);
347     else
348 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
349       n=(ssize_t) vsnprintf_l(string,length,format,locale,operands);
350 #else
351       n=(ssize_t) vsnprintf_l(string,length,locale,format,operands);
352 #endif
353   }
354 #elif defined(MAGICKCORE_HAVE_VSNPRINTF)
355 #if defined(MAGICKCORE_HAVE_USELOCALE)
356   {
357     locale_t
358       locale,
359       previous_locale;
360
361     locale=AcquireCLocale();
362     if (locale == (locale_t) NULL)
363       n=(ssize_t) vsnprintf(string,length,format,operands);
364     else
365       {
366         previous_locale=uselocale(locale);
367         n=(ssize_t) vsnprintf(string,length,format,operands);
368         uselocale(previous_locale);
369       }
370   }
371 #else
372   n=(ssize_t) vsnprintf(string,length,format,operands);
373 #endif
374 #else
375   n=(ssize_t) vsprintf(string,format,operands);
376 #endif
377   if (n < 0)
378     string[length-1]='\0';
379   return(n);
380 }
381
382 MagickExport ssize_t FormatLocaleString(char *restrict string,
383   const size_t length,const char *restrict format,...)
384 {
385   ssize_t
386     n;
387
388   va_list
389     operands;
390
391   va_start(operands,format);
392   n=FormatLocaleStringList(string,length,format,operands);
393   va_end(operands);
394   return(n);
395 }
396 \f
397 /*
398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399 %                                                                             %
400 %                                                                             %
401 %                                                                             %
402 +   G e t L o c a l e I n f o _                                               %
403 %                                                                             %
404 %                                                                             %
405 %                                                                             %
406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 %
408 %  GetLocaleInfo_() searches the locale list for the specified tag and if
409 %  found returns attributes for that element.
410 %
411 %  The format of the GetLocaleInfo method is:
412 %
413 %      const LocaleInfo *GetLocaleInfo_(const char *tag,
414 %        ExceptionInfo *exception)
415 %
416 %  A description of each parameter follows:
417 %
418 %    o tag: the locale tag.
419 %
420 %    o exception: return any errors or warnings in this structure.
421 %
422 */
423 MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
424   ExceptionInfo *exception)
425 {
426   assert(exception != (ExceptionInfo *) NULL);
427   if ((locale_list == (SplayTreeInfo *) NULL) ||
428       (instantiate_locale == MagickFalse))
429     if (InitializeLocaleList(exception) == MagickFalse)
430       return((const LocaleInfo *) NULL);
431   if ((locale_list == (SplayTreeInfo *) NULL) ||
432       (GetNumberOfNodesInSplayTree(locale_list) == 0))
433     return((const LocaleInfo *) NULL);
434   if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
435     {
436       ResetSplayTreeIterator(locale_list);
437       return((const LocaleInfo *) GetNextValueInSplayTree(locale_list));
438     }
439   return((const LocaleInfo *) GetValueFromSplayTree(locale_list,tag));
440 }
441 \f
442 /*
443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444 %                                                                             %
445 %                                                                             %
446 %                                                                             %
447 %   G e t L o c a l e I n f o L i s t                                         %
448 %                                                                             %
449 %                                                                             %
450 %                                                                             %
451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452 %
453 %  GetLocaleInfoList() returns any locale messages that match the
454 %  specified pattern.
455 %
456 %  The format of the GetLocaleInfoList function is:
457 %
458 %      const LocaleInfo **GetLocaleInfoList(const char *pattern,
459 %        size_t *number_messages,ExceptionInfo *exception)
460 %
461 %  A description of each parameter follows:
462 %
463 %    o pattern: Specifies a pointer to a text string containing a pattern.
464 %
465 %    o number_messages:  This integer returns the number of locale messages in
466 %    the list.
467 %
468 %    o exception: return any errors or warnings in this structure.
469 %
470 */
471
472 #if defined(__cplusplus) || defined(c_plusplus)
473 extern "C" {
474 #endif
475
476 static int LocaleInfoCompare(const void *x,const void *y)
477 {
478   const LocaleInfo
479     **p,
480     **q;
481
482   p=(const LocaleInfo **) x,
483   q=(const LocaleInfo **) y;
484   if (LocaleCompare((*p)->path,(*q)->path) == 0)
485     return(LocaleCompare((*p)->tag,(*q)->tag));
486   return(LocaleCompare((*p)->path,(*q)->path));
487 }
488
489 #if defined(__cplusplus) || defined(c_plusplus)
490 }
491 #endif
492
493 MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
494   size_t *number_messages,ExceptionInfo *exception)
495 {
496   const LocaleInfo
497     **messages;
498
499   register const LocaleInfo
500     *p;
501
502   register ssize_t
503     i;
504
505   /*
506     Allocate locale list.
507   */
508   assert(pattern != (char *) NULL);
509   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
510   assert(number_messages != (size_t *) NULL);
511   *number_messages=0;
512   p=GetLocaleInfo_("*",exception);
513   if (p == (const LocaleInfo *) NULL)
514     return((const LocaleInfo **) NULL);
515   messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
516     GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
517   if (messages == (const LocaleInfo **) NULL)
518     return((const LocaleInfo **) NULL);
519   /*
520     Generate locale list.
521   */
522   LockSemaphoreInfo(locale_semaphore);
523   ResetSplayTreeIterator(locale_list);
524   p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
525   for (i=0; p != (const LocaleInfo *) NULL; )
526   {
527     if ((p->stealth == MagickFalse) &&
528         (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
529       messages[i++]=p;
530     p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
531   }
532   UnlockSemaphoreInfo(locale_semaphore);
533   qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
534   messages[i]=(LocaleInfo *) NULL;
535   *number_messages=(size_t) i;
536   return(messages);
537 }
538 \f
539 /*
540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541 %                                                                             %
542 %                                                                             %
543 %                                                                             %
544 %   G e t L o c a l e L i s t                                                 %
545 %                                                                             %
546 %                                                                             %
547 %                                                                             %
548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549 %
550 %  GetLocaleList() returns any locale messages that match the specified
551 %  pattern.
552 %
553 %  The format of the GetLocaleList function is:
554 %
555 %      char **GetLocaleList(const char *pattern,size_t *number_messages,
556 %        Exceptioninfo *exception)
557 %
558 %  A description of each parameter follows:
559 %
560 %    o pattern: Specifies a pointer to a text string containing a pattern.
561 %
562 %    o number_messages:  This integer returns the number of messages in the
563 %      list.
564 %
565 %    o exception: return any errors or warnings in this structure.
566 %
567 */
568
569 #if defined(__cplusplus) || defined(c_plusplus)
570 extern "C" {
571 #endif
572
573 static int LocaleTagCompare(const void *x,const void *y)
574 {
575   register char
576     **p,
577     **q;
578
579   p=(char **) x;
580   q=(char **) y;
581   return(LocaleCompare(*p,*q));
582 }
583
584 #if defined(__cplusplus) || defined(c_plusplus)
585 }
586 #endif
587
588 MagickExport char **GetLocaleList(const char *pattern,
589   size_t *number_messages,ExceptionInfo *exception)
590 {
591   char
592     **messages;
593
594   register const LocaleInfo
595     *p;
596
597   register ssize_t
598     i;
599
600   /*
601     Allocate locale list.
602   */
603   assert(pattern != (char *) NULL);
604   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
605   assert(number_messages != (size_t *) NULL);
606   *number_messages=0;
607   p=GetLocaleInfo_("*",exception);
608   if (p == (const LocaleInfo *) NULL)
609     return((char **) NULL);
610   messages=(char **) AcquireQuantumMemory((size_t)
611     GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
612   if (messages == (char **) NULL)
613     return((char **) NULL);
614   LockSemaphoreInfo(locale_semaphore);
615   p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
616   for (i=0; p != (const LocaleInfo *) NULL; )
617   {
618     if ((p->stealth == MagickFalse) &&
619         (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
620       messages[i++]=ConstantString(p->tag);
621     p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
622   }
623   UnlockSemaphoreInfo(locale_semaphore);
624   qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
625   messages[i]=(char *) NULL;
626   *number_messages=(size_t) i;
627   return(messages);
628 }
629 \f
630 /*
631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632 %                                                                             %
633 %                                                                             %
634 %                                                                             %
635 %   G e t L o c a l e M e s s a g e                                           %
636 %                                                                             %
637 %                                                                             %
638 %                                                                             %
639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
640 %
641 %  GetLocaleMessage() returns a message in the current locale that matches the
642 %  supplied tag.
643 %
644 %  The format of the GetLocaleMessage method is:
645 %
646 %      const char *GetLocaleMessage(const char *tag)
647 %
648 %  A description of each parameter follows:
649 %
650 %    o tag: Return a message that matches this tag in the current locale.
651 %
652 */
653 MagickExport const char *GetLocaleMessage(const char *tag)
654 {
655   char
656     name[MaxTextExtent];
657
658   const LocaleInfo
659     *locale_info;
660
661   ExceptionInfo
662     *exception;
663
664   if ((tag == (const char *) NULL) || (*tag == '\0'))
665     return(tag);
666   exception=AcquireExceptionInfo();
667   (void) FormatLocaleString(name,MaxTextExtent,"%s/",tag);
668   locale_info=GetLocaleInfo_(name,exception);
669   exception=DestroyExceptionInfo(exception);
670   if (locale_info != (const LocaleInfo *) NULL)
671     return(locale_info->message);
672   return(tag);
673 }
674 \f
675 /*
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677 %                                                                             %
678 %                                                                             %
679 %                                                                             %
680 %  G e t L o c a l e O p t i o n s                                            %
681 %                                                                             %
682 %                                                                             %
683 %                                                                             %
684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
685 %
686 %  GetLocaleOptions() returns any Magick configuration messages associated
687 %  with the specified filename.
688 %
689 %  The format of the GetLocaleOptions method is:
690 %
691 %      LinkedListInfo *GetLocaleOptions(const char *filename,
692 %        ExceptionInfo *exception)
693 %
694 %  A description of each parameter follows:
695 %
696 %    o filename: the locale file tag.
697 %
698 %    o exception: return any errors or warnings in this structure.
699 %
700 */
701 MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
702   ExceptionInfo *exception)
703 {
704   char
705     path[MaxTextExtent];
706
707   const char
708     *element;
709
710   LinkedListInfo
711     *messages,
712     *paths;
713
714   StringInfo
715     *xml;
716
717   assert(filename != (const char *) NULL);
718   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
719   assert(exception != (ExceptionInfo *) NULL);
720   (void) CopyMagickString(path,filename,MaxTextExtent);
721   /*
722     Load XML from configuration files to linked-list.
723   */
724   messages=NewLinkedList(0);
725   paths=GetConfigurePaths(filename,exception);
726   if (paths != (LinkedListInfo *) NULL)
727     {
728       ResetLinkedListIterator(paths);
729       element=(const char *) GetNextValueInLinkedList(paths);
730       while (element != (const char *) NULL)
731       {
732         (void) FormatLocaleString(path,MaxTextExtent,"%s%s",element,filename);
733         (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
734           "Searching for locale file: \"%s\"",path);
735         xml=ConfigureFileToStringInfo(path);
736         if (xml != (StringInfo *) NULL)
737           (void) AppendValueToLinkedList(messages,xml);
738         element=(const char *) GetNextValueInLinkedList(paths);
739       }
740       paths=DestroyLinkedList(paths,RelinquishMagickMemory);
741     }
742 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
743   {
744     char
745       *blob;
746
747     blob=(char *) NTResourceToBlob(filename);
748     if (blob != (char *) NULL)
749       {
750         xml=AcquireStringInfo(0);
751         SetStringInfoLength(xml,strlen(blob)+1);
752         SetStringInfoDatum(xml,(unsigned char *) blob);
753         SetStringInfoPath(xml,filename);
754         (void) AppendValueToLinkedList(messages,xml);
755       }
756   }
757 #endif
758   ResetLinkedListIterator(messages);
759   return(messages);
760 }
761 \f
762 /*
763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
764 %                                                                             %
765 %                                                                             %
766 %                                                                             %
767 %   G e t L o c a l e V a l u e                                               %
768 %                                                                             %
769 %                                                                             %
770 %                                                                             %
771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772 %
773 %  GetLocaleValue() returns the message associated with the locale info.
774 %
775 %  The format of the GetLocaleValue method is:
776 %
777 %      const char *GetLocaleValue(const LocaleInfo *locale_info)
778 %
779 %  A description of each parameter follows:
780 %
781 %    o locale_info:  The locale info.
782 %
783 */
784 MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
785 {
786   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
787   assert(locale_info != (LocaleInfo *) NULL);
788   assert(locale_info->signature == MagickSignature);
789   return(locale_info->message);
790 }
791 \f
792 /*
793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
794 %                                                                             %
795 %                                                                             %
796 %                                                                             %
797 +   I n i t i a l i z e L o c a l e L i s t                                   %
798 %                                                                             %
799 %                                                                             %
800 %                                                                             %
801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802 %
803 %  InitializeLocaleList() initializes the locale list.
804 %
805 %  The format of the InitializeLocaleList method is:
806 %
807 %      MagickBooleanType InitializeLocaleList(ExceptionInfo *exception)
808 %
809 %  A description of each parameter follows.
810 %
811 %    o exception: return any errors or warnings in this structure.
812 %
813 */
814 static MagickBooleanType InitializeLocaleList(ExceptionInfo *exception)
815 {
816   if ((locale_list == (SplayTreeInfo *) NULL) &&
817       (instantiate_locale == MagickFalse))
818     {
819       if (locale_semaphore == (SemaphoreInfo *) NULL)
820         AcquireSemaphoreInfo(&locale_semaphore);
821       LockSemaphoreInfo(locale_semaphore);
822       if ((locale_list == (SplayTreeInfo *) NULL) &&
823           (instantiate_locale == MagickFalse))
824         {
825           char
826             *locale;
827
828           register const char
829             *p;
830
831           locale=(char *) NULL;
832           p=setlocale(LC_CTYPE,(const char *) NULL);
833           if (p != (const char *) NULL)
834             locale=ConstantString(p);
835           if (locale == (char *) NULL)
836             locale=GetEnvironmentValue("LC_ALL");
837           if (locale == (char *) NULL)
838             locale=GetEnvironmentValue("LC_MESSAGES");
839           if (locale == (char *) NULL)
840             locale=GetEnvironmentValue("LC_CTYPE");
841           if (locale == (char *) NULL)
842             locale=GetEnvironmentValue("LANG");
843           if (locale == (char *) NULL)
844             locale=ConstantString("C");
845           (void) LoadLocaleLists(LocaleFilename,locale,exception);
846           locale=DestroyString(locale);
847           instantiate_locale=MagickTrue;
848         }
849       UnlockSemaphoreInfo(locale_semaphore);
850     }
851   return(locale_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
852 }
853 \f
854 /*
855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856 %                                                                             %
857 %                                                                             %
858 %                                                                             %
859 +   I n t e r p r e t L o c a l e V a l u e                                   %
860 %                                                                             %
861 %                                                                             %
862 %                                                                             %
863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864 %
865 %  InterpretLocaleValue() interprets the string as a floating point number in
866 %  the "C" locale and returns its value as a double. If sentinal is not a null
867 %  pointer, the method also sets the value pointed by sentinal to point to the
868 %  first character after the number.
869 %
870 %  The format of the InterpretLocaleValue method is:
871 %
872 %      double InterpretLocaleValue(const char *value,char **sentinal)
873 %
874 %  A description of each parameter follows:
875 %
876 %    o value: the string value.
877 %
878 %    o sentinal:  if sentinal is not NULL, a pointer to the character after the
879 %      last character used in the conversion is stored in the location
880 %      referenced by sentinal.
881 %
882 */
883 MagickExport double InterpretLocaleValue(const char *restrict string,
884   char **restrict sentinal)
885 {
886   char
887     *q;
888
889   double
890     value;
891
892   if ((*string == '0') && ((string[1] | 0x20)=='x'))
893     value=(double) strtoul(string,&q,16);
894   else
895     {
896 #if defined(MAGICKCORE_HAVE_STRTOD_L)
897       locale_t
898         locale;
899
900       locale=AcquireCLocale();
901       if (locale == (locale_t) NULL)
902         value=strtod(string,&q);
903       else
904         value=strtod_l(string,&q,locale);
905 #else
906       value=strtod(string,&q);
907 #endif
908     }
909   if (sentinal != (char **) NULL)
910     *sentinal=q;
911   return(value);
912 }
913 \f
914 /*
915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916 %                                                                             %
917 %                                                                             %
918 %                                                                             %
919 %  L i s t L o c a l e I n f o                                                %
920 %                                                                             %
921 %                                                                             %
922 %                                                                             %
923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924 %
925 %  ListLocaleInfo() lists the locale info to a file.
926 %
927 %  The format of the ListLocaleInfo method is:
928 %
929 %      MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
930 %
931 %  A description of each parameter follows.
932 %
933 %    o file:  An pointer to a FILE.
934 %
935 %    o exception: return any errors or warnings in this structure.
936 %
937 */
938 MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
939   ExceptionInfo *exception)
940 {
941   const char
942     *path;
943
944   const LocaleInfo
945     **locale_info;
946
947   register ssize_t
948     i;
949
950   size_t
951     number_messages;
952
953   if (file == (const FILE *) NULL)
954     file=stdout;
955   number_messages=0;
956   locale_info=GetLocaleInfoList("*",&number_messages,exception);
957   if (locale_info == (const LocaleInfo **) NULL)
958     return(MagickFalse);
959   path=(const char *) NULL;
960   for (i=0; i < (ssize_t) number_messages; i++)
961   {
962     if (locale_info[i]->stealth != MagickFalse)
963       continue;
964     if ((path == (const char *) NULL) ||
965         (LocaleCompare(path,locale_info[i]->path) != 0))
966       {
967         if (locale_info[i]->path != (char *) NULL)
968           (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
969         (void) FormatLocaleFile(file,"Tag/Message\n");
970         (void) FormatLocaleFile(file,
971           "-------------------------------------------------"
972           "------------------------------\n");
973       }
974     path=locale_info[i]->path;
975     (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
976     if (locale_info[i]->message != (char *) NULL)
977       (void) FormatLocaleFile(file,"  %s",locale_info[i]->message);
978     (void) FormatLocaleFile(file,"\n");
979   }
980   (void) fflush(file);
981   locale_info=(const LocaleInfo **)
982     RelinquishMagickMemory((void *) locale_info);
983   return(MagickTrue);
984 }
985 \f
986 /*
987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 %                                                                             %
989 %                                                                             %
990 %                                                                             %
991 +   L o a d L o c a l e L i s t                                               %
992 %                                                                             %
993 %                                                                             %
994 %                                                                             %
995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
996 %
997 %  LoadLocaleList() loads the locale configuration file which provides a mapping
998 %  between locale attributes and a locale name.
999 %
1000 %  The format of the LoadLocaleList method is:
1001 %
1002 %      MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
1003 %        const size_t depth,ExceptionInfo *exception)
1004 %
1005 %  A description of each parameter follows:
1006 %
1007 %    o xml:  The locale list in XML format.
1008 %
1009 %    o filename:  The locale list filename.
1010 %
1011 %    o depth: depth of <include /> statements.
1012 %
1013 %    o exception: return any errors or warnings in this structure.
1014 %
1015 */
1016
1017 static void ChopLocaleComponents(char *path,const size_t components)
1018 {
1019   register char
1020     *p;
1021
1022   ssize_t
1023     count;
1024
1025   if (*path == '\0')
1026     return;
1027   p=path+strlen(path)-1;
1028   if (*p == '/')
1029     *p='\0';
1030   for (count=0; (count < (ssize_t) components) && (p > path); p--)
1031     if (*p == '/')
1032       {
1033         *p='\0';
1034         count++;
1035       }
1036   if (count < (ssize_t) components)
1037     *path='\0';
1038 }
1039
1040 static void *DestroyLocaleNode(void *locale_info)
1041 {
1042   register LocaleInfo
1043     *p;
1044
1045   p=(LocaleInfo *) locale_info;
1046   if (p->path != (char *) NULL)
1047     p->path=DestroyString(p->path);
1048   if (p->tag != (char *) NULL)
1049     p->tag=DestroyString(p->tag);
1050   if (p->message != (char *) NULL)
1051     p->message=DestroyString(p->message);
1052   return(RelinquishMagickMemory(p));
1053 }
1054
1055 static void LocaleFatalErrorHandler(
1056   const ExceptionType magick_unused(severity),
1057   const char *reason,const char *description)
1058 {
1059   if (reason == (char *) NULL)
1060     return;
1061   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
1062   if (description != (char *) NULL)
1063     (void) FormatLocaleFile(stderr," (%s)",description);
1064   (void) FormatLocaleFile(stderr,".\n");
1065   (void) fflush(stderr);
1066   exit(1);
1067 }
1068
1069
1070 static MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
1071   const char *locale,const size_t depth,ExceptionInfo *exception)
1072 {
1073   char
1074     keyword[MaxTextExtent],
1075     message[MaxTextExtent],
1076     tag[MaxTextExtent],
1077     *token;
1078
1079   const char
1080     *q;
1081
1082   FatalErrorHandler
1083     fatal_handler;
1084
1085   LocaleInfo
1086     *locale_info;
1087
1088   MagickBooleanType
1089     status;
1090
1091   register char
1092     *p;
1093
1094   /*
1095     Read the locale configure file.
1096   */
1097   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1098     "Loading locale configure file \"%s\" ...",filename);
1099   if (xml == (const char *) NULL)
1100     return(MagickFalse);
1101   if (locale_list == (SplayTreeInfo *) NULL)
1102     {
1103       locale_list=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
1104         DestroyLocaleNode);
1105       if (locale_list == (SplayTreeInfo *) NULL)
1106         return(MagickFalse);
1107     }
1108   status=MagickTrue;
1109   locale_info=(LocaleInfo *) NULL;
1110   *tag='\0';
1111   *message='\0';
1112   *keyword='\0';
1113   fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
1114   token=AcquireString(xml);
1115   for (q=(char *) xml; *q != '\0'; )
1116   {
1117     /*
1118       Interpret XML.
1119     */
1120     GetMagickToken(q,&q,token);
1121     if (*token == '\0')
1122       break;
1123     (void) CopyMagickString(keyword,token,MaxTextExtent);
1124     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1125       {
1126         /*
1127           Doctype element.
1128         */
1129         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1130         {
1131           GetMagickToken(q,&q,token);
1132           while (isspace((int) ((unsigned char) *q)) != 0)
1133             q++;
1134         }
1135         continue;
1136       }
1137     if (LocaleNCompare(keyword,"<!--",4) == 0)
1138       {
1139         /*
1140           Comment element.
1141         */
1142         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1143         {
1144           GetMagickToken(q,&q,token);
1145           while (isspace((int) ((unsigned char) *q)) != 0)
1146             q++;
1147         }
1148         continue;
1149       }
1150     if (LocaleCompare(keyword,"<include") == 0)
1151       {
1152         /*
1153           Include element.
1154         */
1155         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1156         {
1157           (void) CopyMagickString(keyword,token,MaxTextExtent);
1158           GetMagickToken(q,&q,token);
1159           if (*token != '=')
1160             continue;
1161           GetMagickToken(q,&q,token);
1162           if (LocaleCompare(keyword,"locale") == 0)
1163             {
1164               if (LocaleCompare(locale,token) != 0)
1165                 break;
1166               continue;
1167             }
1168           if (LocaleCompare(keyword,"file") == 0)
1169             {
1170               if (depth > 200)
1171                 (void) ThrowMagickException(exception,GetMagickModule(),
1172                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1173               else
1174                 {
1175                   char
1176                     path[MaxTextExtent],
1177                     *xml;
1178
1179                   *path='\0';
1180                   GetPathComponent(filename,HeadPath,path);
1181                   if (*path != '\0')
1182                     (void) ConcatenateMagickString(path,DirectorySeparator,
1183                       MaxTextExtent);
1184                   if (*token == *DirectorySeparator)
1185                     (void) CopyMagickString(path,token,MaxTextExtent);
1186                   else
1187                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
1188                   xml=FileToString(path,~0,exception);
1189                   if (xml != (char *) NULL)
1190                     {
1191                       status=LoadLocaleList(xml,path,locale,depth+1,exception);
1192                       xml=(char *) RelinquishMagickMemory(xml);
1193                     }
1194                 }
1195             }
1196         }
1197         continue;
1198       }
1199     if (LocaleCompare(keyword,"<locale") == 0)
1200       {
1201         /*
1202           Locale element.
1203         */
1204         while ((*token != '>') && (*q != '\0'))
1205         {
1206           (void) CopyMagickString(keyword,token,MaxTextExtent);
1207           GetMagickToken(q,&q,token);
1208           if (*token != '=')
1209             continue;
1210           GetMagickToken(q,&q,token);
1211         }
1212         continue;
1213       }
1214     if (LocaleCompare(keyword,"</locale>") == 0)
1215       {
1216         ChopLocaleComponents(tag,1);
1217         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1218         continue;
1219       }
1220     if (LocaleCompare(keyword,"<localemap>") == 0)
1221       continue;
1222     if (LocaleCompare(keyword,"</localemap>") == 0)
1223       continue;
1224     if (LocaleCompare(keyword,"<message") == 0)
1225       {
1226         /*
1227           Message element.
1228         */
1229         while ((*token != '>') && (*q != '\0'))
1230         {
1231           (void) CopyMagickString(keyword,token,MaxTextExtent);
1232           GetMagickToken(q,&q,token);
1233           if (*token != '=')
1234             continue;
1235           GetMagickToken(q,&q,token);
1236           if (LocaleCompare(keyword,"name") == 0)
1237             {
1238               (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1239               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1240             }
1241         }
1242         for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1243         while (isspace((int) ((unsigned char) *p)) != 0)
1244           p++;
1245         q--;
1246         while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1247           q--;
1248         (void) CopyMagickString(message,p,(size_t) (q-p+2));
1249         locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
1250         if (locale_info == (LocaleInfo *) NULL)
1251           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1252         (void) ResetMagickMemory(locale_info,0,sizeof(*locale_info));
1253         locale_info->path=ConstantString(filename);
1254         locale_info->tag=ConstantString(tag);
1255         locale_info->message=ConstantString(message);
1256         locale_info->signature=MagickSignature;
1257         status=AddValueToSplayTree(locale_list,locale_info->tag,locale_info);
1258         if (status == MagickFalse)
1259           (void) ThrowMagickException(exception,GetMagickModule(),
1260             ResourceLimitError,"MemoryAllocationFailed","`%s'",
1261             locale_info->tag);
1262         (void) ConcatenateMagickString(tag,message,MaxTextExtent);
1263         (void) ConcatenateMagickString(tag,"\n",MaxTextExtent);
1264         q++;
1265         continue;
1266       }
1267     if (LocaleCompare(keyword,"</message>") == 0)
1268       {
1269         ChopLocaleComponents(tag,2);
1270         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1271         continue;
1272       }
1273     if (*keyword == '<')
1274       {
1275         /*
1276           Subpath element.
1277         */
1278         if (*(keyword+1) == '?')
1279           continue;
1280         if (*(keyword+1) == '/')
1281           {
1282             ChopLocaleComponents(tag,1);
1283             if (*tag != '\0')
1284               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1285             continue;
1286           }
1287         token[strlen(token)-1]='\0';
1288         (void) CopyMagickString(token,token+1,MaxTextExtent);
1289         (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1290         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1291         continue;
1292       }
1293     GetMagickToken(q,(const char **) NULL,token);
1294     if (*token != '=')
1295       continue;
1296   }
1297   token=(char *) RelinquishMagickMemory(token);
1298   (void) SetFatalErrorHandler(fatal_handler);
1299   return(status);
1300 }
1301 \f
1302 /*
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304 %                                                                             %
1305 %                                                                             %
1306 %                                                                             %
1307 %  L o a d L o c a l e L i s t s                                              %
1308 %                                                                             %
1309 %                                                                             %
1310 %                                                                             %
1311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312 %
1313 %  LoadLocaleList() loads one or more locale configuration file which
1314 %  provides a mapping between locale attributes and a locale tag.
1315 %
1316 %  The format of the LoadLocaleLists method is:
1317 %
1318 %      MagickBooleanType LoadLocaleLists(const char *filename,
1319 %        ExceptionInfo *exception)
1320 %
1321 %  A description of each parameter follows:
1322 %
1323 %    o filename: the font file tag.
1324 %
1325 %    o locale: the actual locale.
1326 %
1327 %    o exception: return any errors or warnings in this structure.
1328 %
1329 */
1330 static MagickBooleanType LoadLocaleLists(const char *filename,
1331   const char *locale,ExceptionInfo *exception)
1332 {
1333 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
1334   return(LoadLocaleList(LocaleMap,"built-in",locale,0,exception));
1335 #else
1336   const StringInfo
1337     *option;
1338
1339   LinkedListInfo
1340     *options;
1341
1342   MagickStatusType
1343     status;
1344
1345   status=MagickFalse;
1346   options=GetLocaleOptions(filename,exception);
1347   option=(const StringInfo *) GetNextValueInLinkedList(options);
1348   while (option != (const StringInfo *) NULL)
1349   {
1350     status|=LoadLocaleList((const char *) GetStringInfoDatum(option),
1351       GetStringInfoPath(option),locale,0,exception);
1352     option=(const StringInfo *) GetNextValueInLinkedList(options);
1353   }
1354   options=DestroyLocaleOptions(options);
1355   if ((locale_list == (SplayTreeInfo *) NULL) ||
1356       (GetNumberOfNodesInSplayTree(locale_list) == 0))
1357     {
1358       options=GetLocaleOptions("english.xml",exception);
1359       option=(const StringInfo *) GetNextValueInLinkedList(options);
1360       while (option != (const StringInfo *) NULL)
1361       {
1362         status|=LoadLocaleList((const char *) GetStringInfoDatum(option),
1363           GetStringInfoPath(option),locale,0,exception);
1364         option=(const StringInfo *) GetNextValueInLinkedList(options);
1365       }
1366       options=DestroyLocaleOptions(options);
1367     }
1368   if ((locale_list == (SplayTreeInfo *) NULL) ||
1369       (GetNumberOfNodesInSplayTree(locale_list) == 0))
1370     status|=LoadLocaleList(LocaleMap,"built-in",locale,0,exception);
1371   return(status != 0 ? MagickTrue : MagickFalse);
1372 #endif
1373 }
1374 \f
1375 /*
1376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 %                                                                             %
1378 %                                                                             %
1379 %                                                                             %
1380 +   L o c a l e C o m p o n e n t G e n e s i s                               %
1381 %                                                                             %
1382 %                                                                             %
1383 %                                                                             %
1384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385 %
1386 %  LocaleComponentGenesis() instantiates the locale component.
1387 %
1388 %  The format of the LocaleComponentGenesis method is:
1389 %
1390 %      MagickBooleanType LocaleComponentGenesis(void)
1391 %
1392 */
1393 MagickPrivate MagickBooleanType LocaleComponentGenesis(void)
1394 {
1395   AcquireSemaphoreInfo(&locale_semaphore);
1396   return(MagickTrue);
1397 }
1398 \f
1399 /*
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401 %                                                                             %
1402 %                                                                             %
1403 %                                                                             %
1404 +   L o c a l e C o m p o n e n t T e r m i n u s                             %
1405 %                                                                             %
1406 %                                                                             %
1407 %                                                                             %
1408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409 %
1410 %  LocaleComponentTerminus() destroys the locale component.
1411 %
1412 %  The format of the LocaleComponentTerminus method is:
1413 %
1414 %      LocaleComponentTerminus(void)
1415 %
1416 */
1417 MagickPrivate void LocaleComponentTerminus(void)
1418 {
1419   if (locale_semaphore == (SemaphoreInfo *) NULL)
1420     AcquireSemaphoreInfo(&locale_semaphore);
1421   LockSemaphoreInfo(locale_semaphore);
1422   if (locale_list != (SplayTreeInfo *) NULL)
1423     locale_list=DestroySplayTree(locale_list);
1424 #if defined(MAGICKCORE_HAVE_STRTOD_L)
1425   DestroyCLocale();
1426 #endif
1427   instantiate_locale=MagickFalse;
1428   UnlockSemaphoreInfo(locale_semaphore);
1429   DestroySemaphoreInfo(&locale_semaphore);
1430 }