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