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