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