]> 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 %                                   Cristy                                    %
17 %                                 July 2003                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \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         ActivateSemaphoreInfo(&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 static inline size_t MagickMin(const size_t x,const size_t y)
1070 {
1071   if (x < y)
1072     return(x);
1073   return(y);
1074 }
1075
1076 static MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
1077   const char *locale,const size_t depth,ExceptionInfo *exception)
1078 {
1079   char
1080     keyword[MaxTextExtent],
1081     message[MaxTextExtent],
1082     tag[MaxTextExtent],
1083     *token;
1084
1085   const char
1086     *q;
1087
1088   FatalErrorHandler
1089     fatal_handler;
1090
1091   LocaleInfo
1092     *locale_info;
1093
1094   MagickBooleanType
1095     status;
1096
1097   register char
1098     *p;
1099
1100   /*
1101     Read the locale configure file.
1102   */
1103   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1104     "Loading locale configure file \"%s\" ...",filename);
1105   if (xml == (const char *) NULL)
1106     return(MagickFalse);
1107   if (locale_list == (SplayTreeInfo *) NULL)
1108     {
1109       locale_list=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
1110         DestroyLocaleNode);
1111       if (locale_list == (SplayTreeInfo *) NULL)
1112         return(MagickFalse);
1113     }
1114   status=MagickTrue;
1115   locale_info=(LocaleInfo *) NULL;
1116   *tag='\0';
1117   *message='\0';
1118   *keyword='\0';
1119   fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
1120   token=AcquireString(xml);
1121   for (q=(char *) xml; *q != '\0'; )
1122   {
1123     /*
1124       Interpret XML.
1125     */
1126     GetMagickToken(q,&q,token);
1127     if (*token == '\0')
1128       break;
1129     (void) CopyMagickString(keyword,token,MaxTextExtent);
1130     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1131       {
1132         /*
1133           Doctype element.
1134         */
1135         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1136         {
1137           GetMagickToken(q,&q,token);
1138           while (isspace((int) ((unsigned char) *q)) != 0)
1139             q++;
1140         }
1141         continue;
1142       }
1143     if (LocaleNCompare(keyword,"<!--",4) == 0)
1144       {
1145         /*
1146           Comment element.
1147         */
1148         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1149         {
1150           GetMagickToken(q,&q,token);
1151           while (isspace((int) ((unsigned char) *q)) != 0)
1152             q++;
1153         }
1154         continue;
1155       }
1156     if (LocaleCompare(keyword,"<include") == 0)
1157       {
1158         /*
1159           Include element.
1160         */
1161         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1162         {
1163           (void) CopyMagickString(keyword,token,MaxTextExtent);
1164           GetMagickToken(q,&q,token);
1165           if (*token != '=')
1166             continue;
1167           GetMagickToken(q,&q,token);
1168           if (LocaleCompare(keyword,"locale") == 0)
1169             {
1170               if (LocaleCompare(locale,token) != 0)
1171                 break;
1172               continue;
1173             }
1174           if (LocaleCompare(keyword,"file") == 0)
1175             {
1176               if (depth > 200)
1177                 (void) ThrowMagickException(exception,GetMagickModule(),
1178                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1179               else
1180                 {
1181                   char
1182                     path[MaxTextExtent],
1183                     *xml;
1184
1185                   *path='\0';
1186                   GetPathComponent(filename,HeadPath,path);
1187                   if (*path != '\0')
1188                     (void) ConcatenateMagickString(path,DirectorySeparator,
1189                       MaxTextExtent);
1190                   if (*token == *DirectorySeparator)
1191                     (void) CopyMagickString(path,token,MaxTextExtent);
1192                   else
1193                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
1194                   xml=FileToString(path,~0UL,exception);
1195                   if (xml != (char *) NULL)
1196                     {
1197                       status=LoadLocaleList(xml,path,locale,depth+1,exception);
1198                       xml=(char *) RelinquishMagickMemory(xml);
1199                     }
1200                 }
1201             }
1202         }
1203         continue;
1204       }
1205     if (LocaleCompare(keyword,"<locale") == 0)
1206       {
1207         /*
1208           Locale element.
1209         */
1210         while ((*token != '>') && (*q != '\0'))
1211         {
1212           (void) CopyMagickString(keyword,token,MaxTextExtent);
1213           GetMagickToken(q,&q,token);
1214           if (*token != '=')
1215             continue;
1216           GetMagickToken(q,&q,token);
1217         }
1218         continue;
1219       }
1220     if (LocaleCompare(keyword,"</locale>") == 0)
1221       {
1222         ChopLocaleComponents(tag,1);
1223         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1224         continue;
1225       }
1226     if (LocaleCompare(keyword,"<localemap>") == 0)
1227       continue;
1228     if (LocaleCompare(keyword,"</localemap>") == 0)
1229       continue;
1230     if (LocaleCompare(keyword,"<message") == 0)
1231       {
1232         /*
1233           Message element.
1234         */
1235         while ((*token != '>') && (*q != '\0'))
1236         {
1237           (void) CopyMagickString(keyword,token,MaxTextExtent);
1238           GetMagickToken(q,&q,token);
1239           if (*token != '=')
1240             continue;
1241           GetMagickToken(q,&q,token);
1242           if (LocaleCompare(keyword,"name") == 0)
1243             {
1244               (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1245               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1246             }
1247         }
1248         for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1249         while (isspace((int) ((unsigned char) *p)) != 0)
1250           p++;
1251         q--;
1252         while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1253           q--;
1254         (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2),
1255           MaxTextExtent));
1256         locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
1257         if (locale_info == (LocaleInfo *) NULL)
1258           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1259         (void) ResetMagickMemory(locale_info,0,sizeof(*locale_info));
1260         locale_info->path=ConstantString(filename);
1261         locale_info->tag=ConstantString(tag);
1262         locale_info->message=ConstantString(message);
1263         locale_info->signature=MagickSignature;
1264         status=AddValueToSplayTree(locale_list,locale_info->tag,locale_info);
1265         if (status == MagickFalse)
1266           (void) ThrowMagickException(exception,GetMagickModule(),
1267             ResourceLimitError,"MemoryAllocationFailed","`%s'",
1268             locale_info->tag);
1269         (void) ConcatenateMagickString(tag,message,MaxTextExtent);
1270         (void) ConcatenateMagickString(tag,"\n",MaxTextExtent);
1271         q++;
1272         continue;
1273       }
1274     if (LocaleCompare(keyword,"</message>") == 0)
1275       {
1276         ChopLocaleComponents(tag,2);
1277         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1278         continue;
1279       }
1280     if (*keyword == '<')
1281       {
1282         /*
1283           Subpath element.
1284         */
1285         if (*(keyword+1) == '?')
1286           continue;
1287         if (*(keyword+1) == '/')
1288           {
1289             ChopLocaleComponents(tag,1);
1290             if (*tag != '\0')
1291               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1292             continue;
1293           }
1294         token[strlen(token)-1]='\0';
1295         (void) CopyMagickString(token,token+1,MaxTextExtent);
1296         (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1297         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1298         continue;
1299       }
1300     GetMagickToken(q,(const char **) NULL,token);
1301     if (*token != '=')
1302       continue;
1303   }
1304   token=(char *) RelinquishMagickMemory(token);
1305   (void) SetFatalErrorHandler(fatal_handler);
1306   return(status);
1307 }
1308 \f
1309 /*
1310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311 %                                                                             %
1312 %                                                                             %
1313 %                                                                             %
1314 %  L o a d L o c a l e L i s t s                                              %
1315 %                                                                             %
1316 %                                                                             %
1317 %                                                                             %
1318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1319 %
1320 %  LoadLocaleList() loads one or more locale configuration file which
1321 %  provides a mapping between locale attributes and a locale tag.
1322 %
1323 %  The format of the LoadLocaleLists method is:
1324 %
1325 %      MagickBooleanType LoadLocaleLists(const char *filename,
1326 %        ExceptionInfo *exception)
1327 %
1328 %  A description of each parameter follows:
1329 %
1330 %    o filename: the font file tag.
1331 %
1332 %    o locale: the actual locale.
1333 %
1334 %    o exception: return any errors or warnings in this structure.
1335 %
1336 */
1337 static MagickBooleanType LoadLocaleLists(const char *filename,
1338   const char *locale,ExceptionInfo *exception)
1339 {
1340 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
1341   return(LoadLocaleList(LocaleMap,"built-in",locale,0,exception));
1342 #else
1343   const StringInfo
1344     *option;
1345
1346   LinkedListInfo
1347     *options;
1348
1349   MagickStatusType
1350     status;
1351
1352   status=MagickFalse;
1353   options=GetLocaleOptions(filename,exception);
1354   option=(const StringInfo *) GetNextValueInLinkedList(options);
1355   while (option != (const StringInfo *) NULL)
1356   {
1357     status&=LoadLocaleList((const char *) GetStringInfoDatum(option),
1358       GetStringInfoPath(option),locale,0,exception);
1359     option=(const StringInfo *) GetNextValueInLinkedList(options);
1360   }
1361   options=DestroyLocaleOptions(options);
1362   if ((locale_list == (SplayTreeInfo *) NULL) ||
1363       (GetNumberOfNodesInSplayTree(locale_list) == 0))
1364     {
1365       options=GetLocaleOptions("english.xml",exception);
1366       option=(const StringInfo *) GetNextValueInLinkedList(options);
1367       while (option != (const StringInfo *) NULL)
1368       {
1369         status&=LoadLocaleList((const char *) GetStringInfoDatum(option),
1370           GetStringInfoPath(option),locale,0,exception);
1371         option=(const StringInfo *) GetNextValueInLinkedList(options);
1372       }
1373       options=DestroyLocaleOptions(options);
1374     }
1375   if ((locale_list == (SplayTreeInfo *) NULL) ||
1376       (GetNumberOfNodesInSplayTree(locale_list) == 0))
1377     status&=LoadLocaleList(LocaleMap,"built-in",locale,0,exception);
1378   return(status != 0 ? MagickTrue : MagickFalse);
1379 #endif
1380 }
1381 \f
1382 /*
1383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1384 %                                                                             %
1385 %                                                                             %
1386 %                                                                             %
1387 +   L o c a l e C o m p o n e n t G e n e s i s                               %
1388 %                                                                             %
1389 %                                                                             %
1390 %                                                                             %
1391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 %
1393 %  LocaleComponentGenesis() instantiates the locale component.
1394 %
1395 %  The format of the LocaleComponentGenesis method is:
1396 %
1397 %      MagickBooleanType LocaleComponentGenesis(void)
1398 %
1399 */
1400 MagickPrivate MagickBooleanType LocaleComponentGenesis(void)
1401 {
1402   locale_semaphore=AcquireSemaphoreInfo();
1403   return(MagickTrue);
1404 }
1405 \f
1406 /*
1407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408 %                                                                             %
1409 %                                                                             %
1410 %                                                                             %
1411 +   L o c a l e C o m p o n e n t T e r m i n u s                             %
1412 %                                                                             %
1413 %                                                                             %
1414 %                                                                             %
1415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416 %
1417 %  LocaleComponentTerminus() destroys the locale component.
1418 %
1419 %  The format of the LocaleComponentTerminus method is:
1420 %
1421 %      LocaleComponentTerminus(void)
1422 %
1423 */
1424 MagickPrivate void LocaleComponentTerminus(void)
1425 {
1426   if (locale_semaphore == (SemaphoreInfo *) NULL)
1427     ActivateSemaphoreInfo(&locale_semaphore);
1428   LockSemaphoreInfo(locale_semaphore);
1429   if (locale_list != (SplayTreeInfo *) NULL)
1430     locale_list=DestroySplayTree(locale_list);
1431 #if defined(MAGICKCORE_HAVE_STRTOD_L)
1432   DestroyCLocale();
1433 #endif
1434   instantiate_locale=MagickFalse;
1435   UnlockSemaphoreInfo(locale_semaphore);
1436   RelinquishSemaphoreInfo(&locale_semaphore);
1437 }