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