]> 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 \f
103 /*
104   Forward declarations.
105 */
106 static MagickBooleanType
107   IsLocaleTreeInstantiated(ExceptionInfo *),
108   LoadLocaleLists(const char *,const char *,ExceptionInfo *);
109 \f
110 #if defined(MAGICKCORE_HAVE_STRTOD_L)
111 /*
112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113 %                                                                             %
114 %                                                                             %
115 %                                                                             %
116 +   A c q u i r e C L o c a l e                                               %
117 %                                                                             %
118 %                                                                             %
119 %                                                                             %
120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 %
122 %  AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
123 %  errno set if it cannot be acquired.
124 %
125 %  The format of the AcquireCLocale method is:
126 %
127 %      locale_t AcquireCLocale(void)
128 %
129 */
130 static locale_t AcquireCLocale(void)
131 {
132 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
133   if (c_locale == (locale_t) NULL)
134     c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
135 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
136   if (c_locale == (locale_t) NULL)
137     c_locale=_create_locale(LC_ALL,"C");
138 #endif
139   return(c_locale);
140 }
141 #endif
142 \f
143 #if defined(MAGICKCORE_HAVE_STRTOD_L)
144 /*
145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 %                                                                             %
147 %                                                                             %
148 %                                                                             %
149 +   D e s t r o y C L o c a l e                                               %
150 %                                                                             %
151 %                                                                             %
152 %                                                                             %
153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 %
155 %  DestroyCLocale() releases the resources allocated for a locale object
156 %  returned by a call to the AcquireCLocale() method.
157 %
158 %  The format of the DestroyCLocale method is:
159 %
160 %      void DestroyCLocale(void)
161 %
162 */
163 static void DestroyCLocale(void)
164 {
165 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
166   if (c_locale != (locale_t) NULL)
167     freelocale(c_locale);
168 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
169   if (c_locale != (locale_t) NULL)
170     _free_locale(c_locale);
171 #endif
172   c_locale=(locale_t) NULL;
173 }
174 #endif
175 \f
176 /*
177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178 %                                                                             %
179 %                                                                             %
180 %                                                                             %
181 %   D e s t r o y L o c a l e O p t i o n s                                   %
182 %                                                                             %
183 %                                                                             %
184 %                                                                             %
185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 %
187 %  DestroyLocaleOptions() releases memory associated with an locale
188 %  messages.
189 %
190 %  The format of the DestroyProfiles method is:
191 %
192 %      LinkedListInfo *DestroyLocaleOptions(Image *image)
193 %
194 %  A description of each parameter follows:
195 %
196 %    o image: the image.
197 %
198 */
199
200 static void *DestroyOptions(void *message)
201 {
202   return(DestroyStringInfo((StringInfo *) message));
203 }
204
205 MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
206 {
207   assert(messages != (LinkedListInfo *) NULL);
208   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
209   return(DestroyLinkedList(messages,DestroyOptions));
210 }
211 \f
212 /*
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 %                                                                             %
215 %                                                                             %
216 %                                                                             %
217 +  F o r m a t L o c a l e F i l e                                            %
218 %                                                                             %
219 %                                                                             %
220 %                                                                             %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222 %
223 %  FormatLocaleFile() prints formatted output of a variable argument list to a
224 %  file in the "C" locale.
225 %
226 %  The format of the FormatLocaleFile method is:
227 %
228 %      ssize_t FormatLocaleFile(FILE *file,const char *format,...)
229 %
230 %  A description of each parameter follows.
231 %
232 %   o file:  the file.
233 %
234 %   o format:  A file describing the format to use to write the remaining
235 %     arguments.
236 %
237 */
238
239 MagickPrivate ssize_t FormatLocaleFileList(FILE *file,
240   const char *restrict format,va_list operands)
241 {
242   ssize_t
243     n;
244
245 #if defined(MAGICKCORE_HAVE_VFPRINTF_L)
246   {
247     locale_t
248       locale;
249
250     locale=AcquireCLocale();
251     if (locale == (locale_t) NULL)
252       n=(ssize_t) vfprintf(file,format,operands);
253     else
254 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
255       n=(ssize_t) vfprintf_l(file,format,locale,operands);
256 #else
257       n=(ssize_t) vfprintf_l(file,locale,format,operands);
258 #endif
259   }
260 #else
261 #if defined(MAGICKCORE_HAVE_USELOCALE)
262   {
263     locale_t
264       locale,
265       previous_locale;
266
267     locale=AcquireCLocale();
268     if (locale == (locale_t) NULL)
269       n=(ssize_t) vfprintf(file,format,operands);
270     else
271       {
272         previous_locale=uselocale(locale);
273         n=(ssize_t) vfprintf(file,format,operands);
274         uselocale(previous_locale);
275       }
276   }
277 #else
278   n=(ssize_t) vfprintf(file,format,operands);
279 #endif
280 #endif
281   return(n);
282 }
283
284 MagickExport ssize_t FormatLocaleFile(FILE *file,const char *restrict format,
285   ...)
286 {
287   ssize_t
288     n;
289
290   va_list
291     operands;
292
293   va_start(operands,format);
294   n=FormatLocaleFileList(file,format,operands);
295   va_end(operands);
296   return(n);
297 }
298 \f
299 /*
300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301 %                                                                             %
302 %                                                                             %
303 %                                                                             %
304 +  F o r m a t L o c a l e S t r i n g                                        %
305 %                                                                             %
306 %                                                                             %
307 %                                                                             %
308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309 %
310 %  FormatLocaleString() prints formatted output of a variable argument list to
311 %  a string buffer in the "C" locale.
312 %
313 %  The format of the FormatLocaleString method is:
314 %
315 %      ssize_t FormatLocaleString(char *string,const size_t length,
316 %        const char *format,...)
317 %
318 %  A description of each parameter follows.
319 %
320 %   o string:  FormatLocaleString() returns the formatted string in this
321 %     character buffer.
322 %
323 %   o length: the maximum length of the string.
324 %
325 %   o format:  A string describing the format to use to write the remaining
326 %     arguments.
327 %
328 */
329
330 MagickPrivate ssize_t FormatLocaleStringList(char *restrict string,
331   const size_t length,const char *restrict format,va_list operands)
332 {
333   ssize_t
334     n;
335
336 #if defined(MAGICKCORE_HAVE_VSNPRINTF_L)
337   {
338     locale_t
339       locale;
340
341     locale=AcquireCLocale();
342     if (locale == (locale_t) NULL)
343       n=(ssize_t) vsnprintf(string,length,format,operands);
344     else
345 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
346       n=(ssize_t) vsnprintf_l(string,length,format,locale,operands);
347 #else
348       n=(ssize_t) vsnprintf_l(string,length,locale,format,operands);
349 #endif
350   }
351 #elif defined(MAGICKCORE_HAVE_VSNPRINTF)
352 #if defined(MAGICKCORE_HAVE_USELOCALE)
353   {
354     locale_t
355       locale,
356       previous_locale;
357
358     locale=AcquireCLocale();
359     if (locale == (locale_t) NULL)
360       n=(ssize_t) vsnprintf(string,length,format,operands);
361     else
362       {
363         previous_locale=uselocale(locale);
364         n=(ssize_t) vsnprintf(string,length,format,operands);
365         uselocale(previous_locale);
366       }
367   }
368 #else
369   n=(ssize_t) vsnprintf(string,length,format,operands);
370 #endif
371 #else
372   n=(ssize_t) vsprintf(string,format,operands);
373 #endif
374   if (n < 0)
375     string[length-1]='\0';
376   return(n);
377 }
378
379 MagickExport ssize_t FormatLocaleString(char *restrict string,
380   const size_t length,const char *restrict format,...)
381 {
382   ssize_t
383     n;
384
385   va_list
386     operands;
387
388   va_start(operands,format);
389   n=FormatLocaleStringList(string,length,format,operands);
390   va_end(operands);
391   return(n);
392 }
393 \f
394 /*
395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396 %                                                                             %
397 %                                                                             %
398 %                                                                             %
399 +   G e t L o c a l e I n f o _                                               %
400 %                                                                             %
401 %                                                                             %
402 %                                                                             %
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 %
405 %  GetLocaleInfo_() searches the locale list for the specified tag and if
406 %  found returns attributes for that element.
407 %
408 %  The format of the GetLocaleInfo method is:
409 %
410 %      const LocaleInfo *GetLocaleInfo_(const char *tag,
411 %        ExceptionInfo *exception)
412 %
413 %  A description of each parameter follows:
414 %
415 %    o tag: the locale tag.
416 %
417 %    o exception: return any errors or warnings in this structure.
418 %
419 */
420 MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
421   ExceptionInfo *exception)
422 {
423   const LocaleInfo
424     *locale_info;
425
426   assert(exception != (ExceptionInfo *) NULL);
427   if (IsLocaleTreeInstantiated(exception) == MagickFalse)
428     return((const LocaleInfo *) NULL);
429   LockSemaphoreInfo(locale_semaphore);
430   if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
431     {
432       ResetSplayTreeIterator(locale_list);
433       locale_info=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
434       UnlockSemaphoreInfo(locale_semaphore);
435       return(locale_info);
436     }
437   locale_info=(const LocaleInfo *) GetValueFromSplayTree(locale_list,tag);
438   UnlockSemaphoreInfo(locale_semaphore);
439   return(locale_info);
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 s L o c a l e T r e e I n s t a n t i a t e d                           %
798 %                                                                             %
799 %                                                                             %
800 %                                                                             %
801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802 %
803 %  IsLocaleTreeInstantiated() determines if the locale tree is instantiated.
804 %  If not, it instantiates the tree and returns it.
805 %
806 %  The format of the IsLocaleInstantiated method is:
807 %
808 %      MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
809 %
810 %  A description of each parameter follows.
811 %
812 %    o exception: return any errors or warnings in this structure.
813 %
814 */
815 static MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
816 {
817   if (locale_semaphore == (SemaphoreInfo *) NULL)
818     ActivateSemaphoreInfo(&locale_semaphore);
819   LockSemaphoreInfo(locale_semaphore);
820   if (locale_list == (SplayTreeInfo *) NULL)
821     {
822       char
823         *locale;
824
825       register const char
826         *p;
827
828       locale=(char *) NULL;
829       p=setlocale(LC_CTYPE,(const char *) NULL);
830       if (p != (const char *) NULL)
831         locale=ConstantString(p);
832       if (locale == (char *) NULL)
833         locale=GetEnvironmentValue("LC_ALL");
834       if (locale == (char *) NULL)
835         locale=GetEnvironmentValue("LC_MESSAGES");
836       if (locale == (char *) NULL)
837         locale=GetEnvironmentValue("LC_CTYPE");
838       if (locale == (char *) NULL)
839         locale=GetEnvironmentValue("LANG");
840       if (locale == (char *) NULL)
841         locale=ConstantString("C");
842       (void) LoadLocaleLists(LocaleFilename,locale,exception);
843       locale=DestroyString(locale);
844     }
845   UnlockSemaphoreInfo(locale_semaphore);
846   return(locale_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
847 }
848 \f
849 /*
850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
851 %                                                                             %
852 %                                                                             %
853 %                                                                             %
854 +   I n t e r p r e t L o c a l e V a l u e                                   %
855 %                                                                             %
856 %                                                                             %
857 %                                                                             %
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 %
860 %  InterpretLocaleValue() interprets the string as a floating point number in
861 %  the "C" locale and returns its value as a double. If sentinal is not a null
862 %  pointer, the method also sets the value pointed by sentinal to point to the
863 %  first character after the number.
864 %
865 %  The format of the InterpretLocaleValue method is:
866 %
867 %      double InterpretLocaleValue(const char *value,char **sentinal)
868 %
869 %  A description of each parameter follows:
870 %
871 %    o value: the string value.
872 %
873 %    o sentinal:  if sentinal is not NULL, a pointer to the character after the
874 %      last character used in the conversion is stored in the location
875 %      referenced by sentinal.
876 %
877 */
878 MagickExport double InterpretLocaleValue(const char *restrict string,
879   char **restrict sentinal)
880 {
881   char
882     *q;
883
884   double
885     value;
886
887   if ((*string == '0') && ((string[1] | 0x20)=='x'))
888     value=(double) strtoul(string,&q,16);
889   else
890     {
891 #if defined(MAGICKCORE_HAVE_STRTOD_L)
892       locale_t
893         locale;
894
895       locale=AcquireCLocale();
896       if (locale == (locale_t) NULL)
897         value=strtod(string,&q);
898       else
899         value=strtod_l(string,&q,locale);
900 #else
901       value=strtod(string,&q);
902 #endif
903     }
904   if (sentinal != (char **) NULL)
905     *sentinal=q;
906   return(value);
907 }
908 \f
909 /*
910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911 %                                                                             %
912 %                                                                             %
913 %                                                                             %
914 %  L i s t L o c a l e I n f o                                                %
915 %                                                                             %
916 %                                                                             %
917 %                                                                             %
918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
919 %
920 %  ListLocaleInfo() lists the locale info to a file.
921 %
922 %  The format of the ListLocaleInfo method is:
923 %
924 %      MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
925 %
926 %  A description of each parameter follows.
927 %
928 %    o file:  An pointer to a FILE.
929 %
930 %    o exception: return any errors or warnings in this structure.
931 %
932 */
933 MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
934   ExceptionInfo *exception)
935 {
936   const char
937     *path;
938
939   const LocaleInfo
940     **locale_info;
941
942   register ssize_t
943     i;
944
945   size_t
946     number_messages;
947
948   if (file == (const FILE *) NULL)
949     file=stdout;
950   number_messages=0;
951   locale_info=GetLocaleInfoList("*",&number_messages,exception);
952   if (locale_info == (const LocaleInfo **) NULL)
953     return(MagickFalse);
954   path=(const char *) NULL;
955   for (i=0; i < (ssize_t) number_messages; i++)
956   {
957     if (locale_info[i]->stealth != MagickFalse)
958       continue;
959     if ((path == (const char *) NULL) ||
960         (LocaleCompare(path,locale_info[i]->path) != 0))
961       {
962         if (locale_info[i]->path != (char *) NULL)
963           (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
964         (void) FormatLocaleFile(file,"Tag/Message\n");
965         (void) FormatLocaleFile(file,
966           "-------------------------------------------------"
967           "------------------------------\n");
968       }
969     path=locale_info[i]->path;
970     (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
971     if (locale_info[i]->message != (char *) NULL)
972       (void) FormatLocaleFile(file,"  %s",locale_info[i]->message);
973     (void) FormatLocaleFile(file,"\n");
974   }
975   (void) fflush(file);
976   locale_info=(const LocaleInfo **)
977     RelinquishMagickMemory((void *) locale_info);
978   return(MagickTrue);
979 }
980 \f
981 /*
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
983 %                                                                             %
984 %                                                                             %
985 %                                                                             %
986 +   L o a d L o c a l e L i s t                                               %
987 %                                                                             %
988 %                                                                             %
989 %                                                                             %
990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
991 %
992 %  LoadLocaleList() loads the locale configuration file which provides a mapping
993 %  between locale attributes and a locale name.
994 %
995 %  The format of the LoadLocaleList method is:
996 %
997 %      MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
998 %        const size_t depth,ExceptionInfo *exception)
999 %
1000 %  A description of each parameter follows:
1001 %
1002 %    o xml:  The locale list in XML format.
1003 %
1004 %    o filename:  The locale list filename.
1005 %
1006 %    o depth: depth of <include /> statements.
1007 %
1008 %    o exception: return any errors or warnings in this structure.
1009 %
1010 */
1011
1012 static void ChopLocaleComponents(char *path,const size_t components)
1013 {
1014   register char
1015     *p;
1016
1017   ssize_t
1018     count;
1019
1020   if (*path == '\0')
1021     return;
1022   p=path+strlen(path)-1;
1023   if (*p == '/')
1024     *p='\0';
1025   for (count=0; (count < (ssize_t) components) && (p > path); p--)
1026     if (*p == '/')
1027       {
1028         *p='\0';
1029         count++;
1030       }
1031   if (count < (ssize_t) components)
1032     *path='\0';
1033 }
1034
1035 static void *DestroyLocaleNode(void *locale_info)
1036 {
1037   register LocaleInfo
1038     *p;
1039
1040   p=(LocaleInfo *) locale_info;
1041   if (p->path != (char *) NULL)
1042     p->path=DestroyString(p->path);
1043   if (p->tag != (char *) NULL)
1044     p->tag=DestroyString(p->tag);
1045   if (p->message != (char *) NULL)
1046     p->message=DestroyString(p->message);
1047   return(RelinquishMagickMemory(p));
1048 }
1049
1050 static void LocaleFatalErrorHandler(
1051   const ExceptionType magick_unused(severity),
1052   const char *reason,const char *description)
1053 {
1054   if (reason == (char *) NULL)
1055     return;
1056   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
1057   if (description != (char *) NULL)
1058     (void) FormatLocaleFile(stderr," (%s)",description);
1059   (void) FormatLocaleFile(stderr,".\n");
1060   (void) fflush(stderr);
1061   exit(1);
1062 }
1063
1064 static inline size_t MagickMin(const size_t x,const size_t y)
1065 {
1066   if (x < y)
1067     return(x);
1068   return(y);
1069 }
1070
1071 static MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
1072   const char *locale,const size_t depth,ExceptionInfo *exception)
1073 {
1074   char
1075     keyword[MaxTextExtent],
1076     message[MaxTextExtent],
1077     tag[MaxTextExtent],
1078     *token;
1079
1080   const char
1081     *q;
1082
1083   FatalErrorHandler
1084     fatal_handler;
1085
1086   LocaleInfo
1087     *locale_info;
1088
1089   MagickBooleanType
1090     status;
1091
1092   register char
1093     *p;
1094
1095   /*
1096     Read the locale configure file.
1097   */
1098   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1099     "Loading locale configure file \"%s\" ...",filename);
1100   if (xml == (const char *) NULL)
1101     return(MagickFalse);
1102   if (locale_list == (SplayTreeInfo *) NULL)
1103     {
1104       locale_list=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
1105         DestroyLocaleNode);
1106       if (locale_list == (SplayTreeInfo *) NULL)
1107         return(MagickFalse);
1108     }
1109   status=MagickTrue;
1110   locale_info=(LocaleInfo *) NULL;
1111   *tag='\0';
1112   *message='\0';
1113   *keyword='\0';
1114   fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
1115   token=AcquireString(xml);
1116   for (q=(char *) xml; *q != '\0'; )
1117   {
1118     /*
1119       Interpret XML.
1120     */
1121     GetMagickToken(q,&q,token);
1122     if (*token == '\0')
1123       break;
1124     (void) CopyMagickString(keyword,token,MaxTextExtent);
1125     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1126       {
1127         /*
1128           Doctype element.
1129         */
1130         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1131         {
1132           GetMagickToken(q,&q,token);
1133           while (isspace((int) ((unsigned char) *q)) != 0)
1134             q++;
1135         }
1136         continue;
1137       }
1138     if (LocaleNCompare(keyword,"<!--",4) == 0)
1139       {
1140         /*
1141           Comment element.
1142         */
1143         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1144         {
1145           GetMagickToken(q,&q,token);
1146           while (isspace((int) ((unsigned char) *q)) != 0)
1147             q++;
1148         }
1149         continue;
1150       }
1151     if (LocaleCompare(keyword,"<include") == 0)
1152       {
1153         /*
1154           Include element.
1155         */
1156         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1157         {
1158           (void) CopyMagickString(keyword,token,MaxTextExtent);
1159           GetMagickToken(q,&q,token);
1160           if (*token != '=')
1161             continue;
1162           GetMagickToken(q,&q,token);
1163           if (LocaleCompare(keyword,"locale") == 0)
1164             {
1165               if (LocaleCompare(locale,token) != 0)
1166                 break;
1167               continue;
1168             }
1169           if (LocaleCompare(keyword,"file") == 0)
1170             {
1171               if (depth > 200)
1172                 (void) ThrowMagickException(exception,GetMagickModule(),
1173                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1174               else
1175                 {
1176                   char
1177                     path[MaxTextExtent],
1178                     *xml;
1179
1180                   *path='\0';
1181                   GetPathComponent(filename,HeadPath,path);
1182                   if (*path != '\0')
1183                     (void) ConcatenateMagickString(path,DirectorySeparator,
1184                       MaxTextExtent);
1185                   if (*token == *DirectorySeparator)
1186                     (void) CopyMagickString(path,token,MaxTextExtent);
1187                   else
1188                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
1189                   xml=FileToString(path,~0UL,exception);
1190                   if (xml != (char *) NULL)
1191                     {
1192                       status=LoadLocaleList(xml,path,locale,depth+1,exception);
1193                       xml=(char *) RelinquishMagickMemory(xml);
1194                     }
1195                 }
1196             }
1197         }
1198         continue;
1199       }
1200     if (LocaleCompare(keyword,"<locale") == 0)
1201       {
1202         /*
1203           Locale element.
1204         */
1205         while ((*token != '>') && (*q != '\0'))
1206         {
1207           (void) CopyMagickString(keyword,token,MaxTextExtent);
1208           GetMagickToken(q,&q,token);
1209           if (*token != '=')
1210             continue;
1211           GetMagickToken(q,&q,token);
1212         }
1213         continue;
1214       }
1215     if (LocaleCompare(keyword,"</locale>") == 0)
1216       {
1217         ChopLocaleComponents(tag,1);
1218         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1219         continue;
1220       }
1221     if (LocaleCompare(keyword,"<localemap>") == 0)
1222       continue;
1223     if (LocaleCompare(keyword,"</localemap>") == 0)
1224       continue;
1225     if (LocaleCompare(keyword,"<message") == 0)
1226       {
1227         /*
1228           Message element.
1229         */
1230         while ((*token != '>') && (*q != '\0'))
1231         {
1232           (void) CopyMagickString(keyword,token,MaxTextExtent);
1233           GetMagickToken(q,&q,token);
1234           if (*token != '=')
1235             continue;
1236           GetMagickToken(q,&q,token);
1237           if (LocaleCompare(keyword,"name") == 0)
1238             {
1239               (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1240               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1241             }
1242         }
1243         for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1244         while (isspace((int) ((unsigned char) *p)) != 0)
1245           p++;
1246         q--;
1247         while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1248           q--;
1249         (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2),
1250           MaxTextExtent));
1251         locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
1252         if (locale_info == (LocaleInfo *) NULL)
1253           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1254         (void) ResetMagickMemory(locale_info,0,sizeof(*locale_info));
1255         locale_info->path=ConstantString(filename);
1256         locale_info->tag=ConstantString(tag);
1257         locale_info->message=ConstantString(message);
1258         locale_info->signature=MagickSignature;
1259         status=AddValueToSplayTree(locale_list,locale_info->tag,locale_info);
1260         if (status == MagickFalse)
1261           (void) ThrowMagickException(exception,GetMagickModule(),
1262             ResourceLimitError,"MemoryAllocationFailed","`%s'",
1263             locale_info->tag);
1264         (void) ConcatenateMagickString(tag,message,MaxTextExtent);
1265         (void) ConcatenateMagickString(tag,"\n",MaxTextExtent);
1266         q++;
1267         continue;
1268       }
1269     if (LocaleCompare(keyword,"</message>") == 0)
1270       {
1271         ChopLocaleComponents(tag,2);
1272         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1273         continue;
1274       }
1275     if (*keyword == '<')
1276       {
1277         /*
1278           Subpath element.
1279         */
1280         if (*(keyword+1) == '?')
1281           continue;
1282         if (*(keyword+1) == '/')
1283           {
1284             ChopLocaleComponents(tag,1);
1285             if (*tag != '\0')
1286               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1287             continue;
1288           }
1289         token[strlen(token)-1]='\0';
1290         (void) CopyMagickString(token,token+1,MaxTextExtent);
1291         (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1292         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1293         continue;
1294       }
1295     GetMagickToken(q,(const char **) NULL,token);
1296     if (*token != '=')
1297       continue;
1298   }
1299   token=(char *) RelinquishMagickMemory(token);
1300   (void) SetFatalErrorHandler(fatal_handler);
1301   return(status);
1302 }
1303 \f
1304 /*
1305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306 %                                                                             %
1307 %                                                                             %
1308 %                                                                             %
1309 %  L o a d L o c a l e L i s t s                                              %
1310 %                                                                             %
1311 %                                                                             %
1312 %                                                                             %
1313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1314 %
1315 %  LoadLocaleList() loads one or more locale configuration file which
1316 %  provides a mapping between locale attributes and a locale tag.
1317 %
1318 %  The format of the LoadLocaleLists method is:
1319 %
1320 %      MagickBooleanType LoadLocaleLists(const char *filename,
1321 %        ExceptionInfo *exception)
1322 %
1323 %  A description of each parameter follows:
1324 %
1325 %    o filename: the font file tag.
1326 %
1327 %    o locale: the actual locale.
1328 %
1329 %    o exception: return any errors or warnings in this structure.
1330 %
1331 */
1332 static MagickBooleanType LoadLocaleLists(const char *filename,
1333   const char *locale,ExceptionInfo *exception)
1334 {
1335 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
1336   return(LoadLocaleList(LocaleMap,"built-in",locale,0,exception));
1337 #else
1338   const StringInfo
1339     *option;
1340
1341   LinkedListInfo
1342     *options;
1343
1344   MagickStatusType
1345     status;
1346
1347   status=MagickFalse;
1348   options=GetLocaleOptions(filename,exception);
1349   option=(const StringInfo *) GetNextValueInLinkedList(options);
1350   while (option != (const StringInfo *) NULL)
1351   {
1352     status&=LoadLocaleList((const char *) GetStringInfoDatum(option),
1353       GetStringInfoPath(option),locale,0,exception);
1354     option=(const StringInfo *) GetNextValueInLinkedList(options);
1355   }
1356   options=DestroyLocaleOptions(options);
1357   if ((locale_list == (SplayTreeInfo *) NULL) ||
1358       (GetNumberOfNodesInSplayTree(locale_list) == 0))
1359     {
1360       options=GetLocaleOptions("english.xml",exception);
1361       option=(const StringInfo *) GetNextValueInLinkedList(options);
1362       while (option != (const StringInfo *) NULL)
1363       {
1364         status&=LoadLocaleList((const char *) GetStringInfoDatum(option),
1365           GetStringInfoPath(option),locale,0,exception);
1366         option=(const StringInfo *) GetNextValueInLinkedList(options);
1367       }
1368       options=DestroyLocaleOptions(options);
1369     }
1370   if ((locale_list == (SplayTreeInfo *) NULL) ||
1371       (GetNumberOfNodesInSplayTree(locale_list) == 0))
1372     status&=LoadLocaleList(LocaleMap,"built-in",locale,0,exception);
1373   return(status != 0 ? MagickTrue : MagickFalse);
1374 #endif
1375 }
1376 \f
1377 /*
1378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379 %                                                                             %
1380 %                                                                             %
1381 %                                                                             %
1382 +   L o c a l e C o m p o n e n t G e n e s i s                               %
1383 %                                                                             %
1384 %                                                                             %
1385 %                                                                             %
1386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 %
1388 %  LocaleComponentGenesis() instantiates the locale component.
1389 %
1390 %  The format of the LocaleComponentGenesis method is:
1391 %
1392 %      MagickBooleanType LocaleComponentGenesis(void)
1393 %
1394 */
1395 MagickPrivate MagickBooleanType LocaleComponentGenesis(void)
1396 {
1397   locale_semaphore=AcquireSemaphoreInfo();
1398   return(MagickTrue);
1399 }
1400 \f
1401 /*
1402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403 %                                                                             %
1404 %                                                                             %
1405 %                                                                             %
1406 +   L o c a l e C o m p o n e n t T e r m i n u s                             %
1407 %                                                                             %
1408 %                                                                             %
1409 %                                                                             %
1410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411 %
1412 %  LocaleComponentTerminus() destroys the locale component.
1413 %
1414 %  The format of the LocaleComponentTerminus method is:
1415 %
1416 %      LocaleComponentTerminus(void)
1417 %
1418 */
1419 MagickPrivate void LocaleComponentTerminus(void)
1420 {
1421   if (locale_semaphore == (SemaphoreInfo *) NULL)
1422     ActivateSemaphoreInfo(&locale_semaphore);
1423   LockSemaphoreInfo(locale_semaphore);
1424   if (locale_list != (SplayTreeInfo *) NULL)
1425     locale_list=DestroySplayTree(locale_list);
1426 #if defined(MAGICKCORE_HAVE_STRTOD_L)
1427   DestroyCLocale();
1428 #endif
1429   UnlockSemaphoreInfo(locale_semaphore);
1430   RelinquishSemaphoreInfo(&locale_semaphore);
1431 }