2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % L OOO CCCC AAA L EEEEE %
8 % L O O C AAAAA L EEE %
10 % LLLLL OOO CCCC A A LLLLL EEEEE %
13 % MagickCore Image Locale Methods %
20 % Copyright 1999-2018 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % https://imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/configure.h"
46 #include "MagickCore/exception.h"
47 #include "MagickCore/exception-private.h"
48 #include "MagickCore/image-private.h"
49 #include "MagickCore/linked-list.h"
50 #include "MagickCore/locale_.h"
51 #include "MagickCore/locale-private.h"
52 #include "MagickCore/log.h"
53 #include "MagickCore/memory_.h"
54 #include "MagickCore/memory-private.h"
55 #include "MagickCore/nt-base-private.h"
56 #include "MagickCore/semaphore.h"
57 #include "MagickCore/splay-tree.h"
58 #include "MagickCore/string_.h"
59 #include "MagickCore/string-private.h"
60 #include "MagickCore/token.h"
61 #include "MagickCore/utility.h"
62 #include "MagickCore/utility-private.h"
63 #include "MagickCore/xml-tree.h"
64 #include "MagickCore/xml-tree-private.h"
69 #if defined(MAGICKCORE_HAVE_NEWLOCALE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
70 # define MAGICKCORE_LOCALE_SUPPORT
72 #define LocaleFilename "locale.xml"
79 "<?xml version=\"1.0\"?>"
81 " <locale name=\"C\">"
83 " <Message name=\"\">"
90 #define asciimap AsciiMap
92 #if !defined(MAGICKCORE_HAVE_STRCASECMP) || !defined(MAGICKCORE_HAVE_STRNCASECMP)
93 static const unsigned char
96 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
97 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
98 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
99 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
100 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
101 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
102 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
103 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
104 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
105 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
106 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
107 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
108 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
109 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
110 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
111 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
112 0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xc5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
113 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
114 0xf8, 0xf9, 0xfa, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
115 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
116 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
117 0xfc, 0xfd, 0xfe, 0xff,
122 *locale_semaphore = (SemaphoreInfo *) NULL;
125 *locale_cache = (SplayTreeInfo *) NULL;
127 #if defined(MAGICKCORE_LOCALE_SUPPORT)
128 static volatile locale_t
129 c_locale = (locale_t) NULL;
133 Forward declarations.
135 static MagickBooleanType
136 IsLocaleTreeInstantiated(ExceptionInfo *),
137 LoadLocaleCache(SplayTreeInfo *,const char *,const char *,const char *,
138 const size_t,ExceptionInfo *);
140 #if defined(MAGICKCORE_LOCALE_SUPPORT)
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 + A c q u i r e C L o c a l e %
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152 % AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
153 % errno set if it cannot be acquired.
155 % The format of the AcquireCLocale method is:
157 % locale_t AcquireCLocale(void)
160 static locale_t AcquireCLocale(void)
162 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
163 if (c_locale == (locale_t) NULL)
164 c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
165 #elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
166 if (c_locale == (locale_t) NULL)
167 c_locale=_create_locale(LC_ALL,"C");
174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178 % A c q u i r e L o c a l e S p l a y T r e e %
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
184 % AcquireLocaleSplayTree() caches one or more locale configurations which
185 % provides a mapping between locale attributes and a locale tag.
187 % The format of the AcquireLocaleSplayTree method is:
189 % SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
190 % ExceptionInfo *exception)
192 % A description of each parameter follows:
194 % o filename: the font file tag.
196 % o locale: the actual locale.
198 % o exception: return any errors or warnings in this structure.
202 static void *DestroyLocaleNode(void *locale_info)
207 p=(LocaleInfo *) locale_info;
208 if (p->path != (char *) NULL)
209 p->path=DestroyString(p->path);
210 if (p->tag != (char *) NULL)
211 p->tag=DestroyString(p->tag);
212 if (p->message != (char *) NULL)
213 p->message=DestroyString(p->message);
214 return(RelinquishMagickMemory(p));
217 static SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
218 const char *locale,ExceptionInfo *exception)
226 cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
229 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
237 options=GetLocaleOptions(filename,exception);
238 option=(const StringInfo *) GetNextValueInLinkedList(options);
239 while (option != (const StringInfo *) NULL)
241 status&=LoadLocaleCache(cache,(const char *)
242 GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
244 option=(const StringInfo *) GetNextValueInLinkedList(options);
246 options=DestroyLocaleOptions(options);
247 if (GetNumberOfNodesInSplayTree(cache) == 0)
249 options=GetLocaleOptions("english.xml",exception);
250 option=(const StringInfo *) GetNextValueInLinkedList(options);
251 while (option != (const StringInfo *) NULL)
253 status&=LoadLocaleCache(cache,(const char *)
254 GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
256 option=(const StringInfo *) GetNextValueInLinkedList(options);
258 options=DestroyLocaleOptions(options);
262 if (GetNumberOfNodesInSplayTree(cache) == 0)
263 status&=LoadLocaleCache(cache,LocaleMap,"built-in",locale,0,
268 #if defined(MAGICKCORE_LOCALE_SUPPORT)
270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 + D e s t r o y C L o c a l e %
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 % DestroyCLocale() releases the resources allocated for a locale object
281 % returned by a call to the AcquireCLocale() method.
283 % The format of the DestroyCLocale method is:
285 % void DestroyCLocale(void)
288 static void DestroyCLocale(void)
290 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
291 if (c_locale != (locale_t) NULL)
292 freelocale(c_locale);
293 #elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
294 if (c_locale != (locale_t) NULL)
295 _free_locale(c_locale);
297 c_locale=(locale_t) NULL;
302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306 % D e s t r o y L o c a l e O p t i o n s %
310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 % DestroyLocaleOptions() releases memory associated with an locale
315 % The format of the DestroyProfiles method is:
317 % LinkedListInfo *DestroyLocaleOptions(Image *image)
319 % A description of each parameter follows:
321 % o image: the image.
325 static void *DestroyOptions(void *message)
327 return(DestroyStringInfo((StringInfo *) message));
330 MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
332 assert(messages != (LinkedListInfo *) NULL);
333 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
334 return(DestroyLinkedList(messages,DestroyOptions));
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 + F o r m a t L o c a l e F i l e %
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348 % FormatLocaleFile() prints formatted output of a variable argument list to a
349 % file in the "C" locale.
351 % The format of the FormatLocaleFile method is:
353 % ssize_t FormatLocaleFile(FILE *file,const char *format,...)
355 % A description of each parameter follows.
359 % o format: A file describing the format to use to write the remaining
364 MagickPrivate ssize_t FormatLocaleFileList(FILE *file,
365 const char *magick_restrict format,va_list operands)
370 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_VFPRINTF_L)
375 locale=AcquireCLocale();
376 if (locale == (locale_t) NULL)
377 n=(ssize_t) vfprintf(file,format,operands);
379 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
380 n=(ssize_t) vfprintf_l(file,format,locale,operands);
382 n=(ssize_t) vfprintf_l(file,locale,format,operands);
386 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
392 locale=AcquireCLocale();
393 if (locale == (locale_t) NULL)
394 n=(ssize_t) vfprintf(file,format,operands);
397 previous_locale=uselocale(locale);
398 n=(ssize_t) vfprintf(file,format,operands);
399 uselocale(previous_locale);
403 n=(ssize_t) vfprintf(file,format,operands);
409 MagickExport ssize_t FormatLocaleFile(FILE *file,
410 const char *magick_restrict format,...)
418 va_start(operands,format);
419 n=FormatLocaleFileList(file,format,operands);
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 + F o r m a t L o c a l e S t r i n g %
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 % FormatLocaleString() prints formatted output of a variable argument list to
436 % a string buffer in the "C" locale.
438 % The format of the FormatLocaleString method is:
440 % ssize_t FormatLocaleString(char *string,const size_t length,
441 % const char *format,...)
443 % A description of each parameter follows.
445 % o string: FormatLocaleString() returns the formatted string in this
448 % o length: the maximum length of the string.
450 % o format: A string describing the format to use to write the remaining
455 MagickPrivate ssize_t FormatLocaleStringList(char *magick_restrict string,
456 const size_t length,const char *magick_restrict format,va_list operands)
461 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_VSNPRINTF_L)
466 locale=AcquireCLocale();
467 if (locale == (locale_t) NULL)
468 n=(ssize_t) vsnprintf(string,length,format,operands);
470 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
471 n=(ssize_t) vsnprintf_l(string,length,format,locale,operands);
473 n=(ssize_t) vsnprintf_l(string,length,locale,format,operands);
476 #elif defined(MAGICKCORE_HAVE_VSNPRINTF)
477 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
483 locale=AcquireCLocale();
484 if (locale == (locale_t) NULL)
485 n=(ssize_t) vsnprintf(string,length,format,operands);
488 previous_locale=uselocale(locale);
489 n=(ssize_t) vsnprintf(string,length,format,operands);
490 uselocale(previous_locale);
494 n=(ssize_t) vsnprintf(string,length,format,operands);
497 n=(ssize_t) vsprintf(string,format,operands);
500 string[length-1]='\0';
504 MagickExport ssize_t FormatLocaleString(char *magick_restrict string,
505 const size_t length,const char *magick_restrict format,...)
513 va_start(operands,format);
514 n=FormatLocaleStringList(string,length,format,operands);
520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524 + G e t L o c a l e I n f o _ %
528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530 % GetLocaleInfo_() searches the locale list for the specified tag and if
531 % found returns attributes for that element.
533 % The format of the GetLocaleInfo method is:
535 % const LocaleInfo *GetLocaleInfo_(const char *tag,
536 % ExceptionInfo *exception)
538 % A description of each parameter follows:
540 % o tag: the locale tag.
542 % o exception: return any errors or warnings in this structure.
545 MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
546 ExceptionInfo *exception)
551 assert(exception != (ExceptionInfo *) NULL);
552 if (IsLocaleTreeInstantiated(exception) == MagickFalse)
553 return((const LocaleInfo *) NULL);
554 LockSemaphoreInfo(locale_semaphore);
555 if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
557 ResetSplayTreeIterator(locale_cache);
558 locale_info=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
559 UnlockSemaphoreInfo(locale_semaphore);
562 locale_info=(const LocaleInfo *) GetValueFromSplayTree(locale_cache,tag);
563 UnlockSemaphoreInfo(locale_semaphore);
568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
572 % G e t L o c a l e I n f o L i s t %
576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578 % GetLocaleInfoList() returns any locale messages that match the
581 % The format of the GetLocaleInfoList function is:
583 % const LocaleInfo **GetLocaleInfoList(const char *pattern,
584 % size_t *number_messages,ExceptionInfo *exception)
586 % A description of each parameter follows:
588 % o pattern: Specifies a pointer to a text string containing a pattern.
590 % o number_messages: This integer returns the number of locale messages in
593 % o exception: return any errors or warnings in this structure.
597 #if defined(__cplusplus) || defined(c_plusplus)
601 static int LocaleInfoCompare(const void *x,const void *y)
607 p=(const LocaleInfo **) x,
608 q=(const LocaleInfo **) y;
609 if (LocaleCompare((*p)->path,(*q)->path) == 0)
610 return(LocaleCompare((*p)->tag,(*q)->tag));
611 return(LocaleCompare((*p)->path,(*q)->path));
614 #if defined(__cplusplus) || defined(c_plusplus)
618 MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
619 size_t *number_messages,ExceptionInfo *exception)
624 register const LocaleInfo
631 Allocate locale list.
633 assert(pattern != (char *) NULL);
634 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
635 assert(number_messages != (size_t *) NULL);
637 p=GetLocaleInfo_("*",exception);
638 if (p == (const LocaleInfo *) NULL)
639 return((const LocaleInfo **) NULL);
640 messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
641 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
642 if (messages == (const LocaleInfo **) NULL)
643 return((const LocaleInfo **) NULL);
645 Generate locale list.
647 LockSemaphoreInfo(locale_semaphore);
648 ResetSplayTreeIterator(locale_cache);
649 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
650 for (i=0; p != (const LocaleInfo *) NULL; )
652 if ((p->stealth == MagickFalse) &&
653 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
655 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
657 UnlockSemaphoreInfo(locale_semaphore);
658 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
659 messages[i]=(LocaleInfo *) NULL;
660 *number_messages=(size_t) i;
665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669 % G e t L o c a l e L i s t %
673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675 % GetLocaleList() returns any locale messages that match the specified
678 % The format of the GetLocaleList function is:
680 % char **GetLocaleList(const char *pattern,size_t *number_messages,
681 % Exceptioninfo *exception)
683 % A description of each parameter follows:
685 % o pattern: Specifies a pointer to a text string containing a pattern.
687 % o number_messages: This integer returns the number of messages in the
690 % o exception: return any errors or warnings in this structure.
694 #if defined(__cplusplus) || defined(c_plusplus)
698 static int LocaleTagCompare(const void *x,const void *y)
706 return(LocaleCompare(*p,*q));
709 #if defined(__cplusplus) || defined(c_plusplus)
713 MagickExport char **GetLocaleList(const char *pattern,size_t *number_messages,
714 ExceptionInfo *exception)
719 register const LocaleInfo
726 Allocate locale list.
728 assert(pattern != (char *) NULL);
729 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
730 assert(number_messages != (size_t *) NULL);
732 p=GetLocaleInfo_("*",exception);
733 if (p == (const LocaleInfo *) NULL)
734 return((char **) NULL);
735 messages=(char **) AcquireQuantumMemory((size_t)
736 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
737 if (messages == (char **) NULL)
738 return((char **) NULL);
739 LockSemaphoreInfo(locale_semaphore);
740 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
741 for (i=0; p != (const LocaleInfo *) NULL; )
743 if ((p->stealth == MagickFalse) &&
744 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
745 messages[i++]=ConstantString(p->tag);
746 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
748 UnlockSemaphoreInfo(locale_semaphore);
749 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
750 messages[i]=(char *) NULL;
751 *number_messages=(size_t) i;
756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760 % G e t L o c a l e M e s s a g e %
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766 % GetLocaleMessage() returns a message in the current locale that matches the
769 % The format of the GetLocaleMessage method is:
771 % const char *GetLocaleMessage(const char *tag)
773 % A description of each parameter follows:
775 % o tag: Return a message that matches this tag in the current locale.
778 MagickExport const char *GetLocaleMessage(const char *tag)
781 name[MagickLocaleExtent];
789 if ((tag == (const char *) NULL) || (*tag == '\0'))
791 exception=AcquireExceptionInfo();
792 (void) FormatLocaleString(name,MagickLocaleExtent,"%s/",tag);
793 locale_info=GetLocaleInfo_(name,exception);
794 exception=DestroyExceptionInfo(exception);
795 if (locale_info != (const LocaleInfo *) NULL)
796 return(locale_info->message);
801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
805 % G e t L o c a l e O p t i o n s %
809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
811 % GetLocaleOptions() returns any Magick configuration messages associated
812 % with the specified filename.
814 % The format of the GetLocaleOptions method is:
816 % LinkedListInfo *GetLocaleOptions(const char *filename,
817 % ExceptionInfo *exception)
819 % A description of each parameter follows:
821 % o filename: the locale file tag.
823 % o exception: return any errors or warnings in this structure.
826 MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
827 ExceptionInfo *exception)
830 path[MagickPathExtent];
842 assert(filename != (const char *) NULL);
843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
844 assert(exception != (ExceptionInfo *) NULL);
845 (void) CopyMagickString(path,filename,MagickPathExtent);
847 Load XML from configuration files to linked-list.
849 messages=NewLinkedList(0);
850 paths=GetConfigurePaths(filename,exception);
851 if (paths != (LinkedListInfo *) NULL)
853 ResetLinkedListIterator(paths);
854 element=(const char *) GetNextValueInLinkedList(paths);
855 while (element != (const char *) NULL)
857 (void) FormatLocaleString(path,MagickPathExtent,"%s%s",element,
859 (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
860 "Searching for locale file: \"%s\"",path);
861 xml=ConfigureFileToStringInfo(path);
862 if (xml != (StringInfo *) NULL)
863 (void) AppendValueToLinkedList(messages,xml);
864 element=(const char *) GetNextValueInLinkedList(paths);
866 paths=DestroyLinkedList(paths,RelinquishMagickMemory);
868 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
873 blob=(char *) NTResourceToBlob(filename);
874 if (blob != (char *) NULL)
876 xml=AcquireStringInfo(0);
877 SetStringInfoLength(xml,strlen(blob)+1);
878 SetStringInfoDatum(xml,(const unsigned char *) blob);
879 blob=(char *) RelinquishMagickMemory(blob);
880 SetStringInfoPath(xml,filename);
881 (void) AppendValueToLinkedList(messages,xml);
885 ResetLinkedListIterator(messages);
890 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
894 % G e t L o c a l e V a l u e %
898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
900 % GetLocaleValue() returns the message associated with the locale info.
902 % The format of the GetLocaleValue method is:
904 % const char *GetLocaleValue(const LocaleInfo *locale_info)
906 % A description of each parameter follows:
908 % o locale_info: The locale info.
911 MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
914 assert(locale_info != (LocaleInfo *) NULL);
915 assert(locale_info->signature == MagickCoreSignature);
916 return(locale_info->message);
920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924 + I s L o c a l e T r e e I n s t a n t i a t e d %
928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
930 % IsLocaleTreeInstantiated() determines if the locale tree is instantiated.
931 % If not, it instantiates the tree and returns it.
933 % The format of the IsLocaleInstantiated method is:
935 % MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
937 % A description of each parameter follows.
939 % o exception: return any errors or warnings in this structure.
942 static MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
944 if (locale_cache == (SplayTreeInfo *) NULL)
946 if (locale_semaphore == (SemaphoreInfo *) NULL)
947 ActivateSemaphoreInfo(&locale_semaphore);
948 LockSemaphoreInfo(locale_semaphore);
949 if (locale_cache == (SplayTreeInfo *) NULL)
957 locale=(char *) NULL;
958 p=setlocale(LC_CTYPE,(const char *) NULL);
959 if (p != (const char *) NULL)
960 locale=ConstantString(p);
961 if (locale == (char *) NULL)
962 locale=GetEnvironmentValue("LC_ALL");
963 if (locale == (char *) NULL)
964 locale=GetEnvironmentValue("LC_MESSAGES");
965 if (locale == (char *) NULL)
966 locale=GetEnvironmentValue("LC_CTYPE");
967 if (locale == (char *) NULL)
968 locale=GetEnvironmentValue("LANG");
969 if (locale == (char *) NULL)
970 locale=ConstantString("C");
971 locale_cache=AcquireLocaleSplayTree(LocaleFilename,locale,exception);
972 locale=DestroyString(locale);
974 UnlockSemaphoreInfo(locale_semaphore);
976 return(locale_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 + I n t e r p r e t L o c a l e V a l u e %
988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990 % InterpretLocaleValue() interprets the string as a floating point number in
991 % the "C" locale and returns its value as a double. If sentinal is not a null
992 % pointer, the method also sets the value pointed by sentinal to point to the
993 % first character after the number.
995 % The format of the InterpretLocaleValue method is:
997 % double InterpretLocaleValue(const char *value,char **sentinal)
999 % A description of each parameter follows:
1001 % o value: the string value.
1003 % o sentinal: if sentinal is not NULL, a pointer to the character after the
1004 % last character used in the conversion is stored in the location
1005 % referenced by sentinal.
1008 MagickExport double InterpretLocaleValue(const char *magick_restrict string,
1009 char **magick_restrict sentinal)
1017 if ((*string == '0') && ((string[1] | 0x20)=='x'))
1018 value=(double) strtoul(string,&q,16);
1021 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_STRTOD_L)
1025 locale=AcquireCLocale();
1026 if (locale == (locale_t) NULL)
1027 value=strtod(string,&q);
1029 value=strtod_l(string,&q,locale);
1031 value=strtod(string,&q);
1034 if (sentinal != (char **) NULL)
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 % L i s t L o c a l e I n f o %
1048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050 % ListLocaleInfo() lists the locale info to a file.
1052 % The format of the ListLocaleInfo method is:
1054 % MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
1056 % A description of each parameter follows.
1058 % o file: An pointer to a FILE.
1060 % o exception: return any errors or warnings in this structure.
1063 MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
1064 ExceptionInfo *exception)
1078 if (file == (const FILE *) NULL)
1081 locale_info=GetLocaleInfoList("*",&number_messages,exception);
1082 if (locale_info == (const LocaleInfo **) NULL)
1083 return(MagickFalse);
1084 path=(const char *) NULL;
1085 for (i=0; i < (ssize_t) number_messages; i++)
1087 if (locale_info[i]->stealth != MagickFalse)
1089 if ((path == (const char *) NULL) ||
1090 (LocaleCompare(path,locale_info[i]->path) != 0))
1092 if (locale_info[i]->path != (char *) NULL)
1093 (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
1094 (void) FormatLocaleFile(file,"Tag/Message\n");
1095 (void) FormatLocaleFile(file,
1096 "-------------------------------------------------"
1097 "------------------------------\n");
1099 path=locale_info[i]->path;
1100 (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
1101 if (locale_info[i]->message != (char *) NULL)
1102 (void) FormatLocaleFile(file," %s",locale_info[i]->message);
1103 (void) FormatLocaleFile(file,"\n");
1105 (void) fflush(file);
1106 locale_info=(const LocaleInfo **)
1107 RelinquishMagickMemory((void *) locale_info);
1112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 + L o a d L o c a l e C a c h e %
1120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122 % LoadLocaleCache() loads the locale configurations which provides a mapping
1123 % between locale attributes and a locale name.
1125 % The format of the LoadLocaleCache method is:
1127 % MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1128 % const char *filename,const size_t depth,ExceptionInfo *exception)
1130 % A description of each parameter follows:
1132 % o xml: The locale list in XML format.
1134 % o filename: The locale list filename.
1136 % o depth: depth of <include /> statements.
1138 % o exception: return any errors or warnings in this structure.
1142 static void ChopLocaleComponents(char *path,const size_t components)
1152 p=path+strlen(path)-1;
1155 for (count=0; (count < (ssize_t) components) && (p > path); p--)
1161 if (count < (ssize_t) components)
1165 static void LocaleFatalErrorHandler(
1166 const ExceptionType magick_unused(severity),
1167 const char *reason,const char *description)
1169 magick_unreferenced(severity);
1171 if (reason == (char *) NULL)
1173 (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
1174 if (description != (char *) NULL)
1175 (void) FormatLocaleFile(stderr," (%s)",description);
1176 (void) FormatLocaleFile(stderr,".\n");
1177 (void) fflush(stderr);
1181 static MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1182 const char *filename,const char *locale,const size_t depth,ExceptionInfo *exception)
1185 keyword[MagickLocaleExtent],
1186 message[MagickLocaleExtent],
1187 tag[MagickLocaleExtent],
1209 Read the locale configure file.
1211 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1212 "Loading locale configure file \"%s\" ...",filename);
1213 if (xml == (const char *) NULL)
1214 return(MagickFalse);
1216 locale_info=(LocaleInfo *) NULL;
1220 fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
1221 token=AcquireString(xml);
1222 extent=strlen(token)+MagickPathExtent;
1223 for (q=(char *) xml; *q != '\0'; )
1228 GetNextToken(q,&q,extent,token);
1231 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1232 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1237 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1239 GetNextToken(q,&q,extent,token);
1240 while (isspace((int) ((unsigned char) *q)) != 0)
1245 if (LocaleNCompare(keyword,"<!--",4) == 0)
1250 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1252 GetNextToken(q,&q,extent,token);
1253 while (isspace((int) ((unsigned char) *q)) != 0)
1258 if (LocaleCompare(keyword,"<include") == 0)
1263 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1265 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1266 GetNextToken(q,&q,extent,token);
1269 GetNextToken(q,&q,extent,token);
1270 if (LocaleCompare(keyword,"locale") == 0)
1272 if (LocaleCompare(locale,token) != 0)
1276 if (LocaleCompare(keyword,"file") == 0)
1278 if (depth > MagickMaxRecursionDepth)
1279 (void) ThrowMagickException(exception,GetMagickModule(),
1280 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1284 path[MagickPathExtent],
1288 GetPathComponent(filename,HeadPath,path);
1290 (void) ConcatenateMagickString(path,DirectorySeparator,
1292 if (*token == *DirectorySeparator)
1293 (void) CopyMagickString(path,token,MagickPathExtent);
1295 (void) ConcatenateMagickString(path,token,MagickPathExtent);
1296 file_xml=FileToXML(path,~0UL);
1297 if (file_xml != (char *) NULL)
1299 status&=LoadLocaleCache(cache,file_xml,path,locale,
1301 file_xml=DestroyString(file_xml);
1308 if (LocaleCompare(keyword,"<locale") == 0)
1313 while ((*token != '>') && (*q != '\0'))
1315 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1316 GetNextToken(q,&q,extent,token);
1319 GetNextToken(q,&q,extent,token);
1323 if (LocaleCompare(keyword,"</locale>") == 0)
1325 ChopLocaleComponents(tag,1);
1326 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1329 if (LocaleCompare(keyword,"<localemap>") == 0)
1331 if (LocaleCompare(keyword,"</localemap>") == 0)
1333 if (LocaleCompare(keyword,"<message") == 0)
1338 while ((*token != '>') && (*q != '\0'))
1340 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1341 GetNextToken(q,&q,extent,token);
1344 GetNextToken(q,&q,extent,token);
1345 if (LocaleCompare(keyword,"name") == 0)
1347 (void) ConcatenateMagickString(tag,token,MagickLocaleExtent);
1348 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1351 for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1352 while (isspace((int) ((unsigned char) *p)) != 0)
1355 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1357 (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2),
1358 MagickLocaleExtent));
1359 locale_info=(LocaleInfo *) AcquireCriticalMemory(sizeof(*locale_info));
1360 (void) memset(locale_info,0,sizeof(*locale_info));
1361 locale_info->path=ConstantString(filename);
1362 locale_info->tag=ConstantString(tag);
1363 locale_info->message=ConstantString(message);
1364 locale_info->signature=MagickCoreSignature;
1365 status=AddValueToSplayTree(cache,locale_info->tag,locale_info);
1366 if (status == MagickFalse)
1367 (void) ThrowMagickException(exception,GetMagickModule(),
1368 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1370 (void) ConcatenateMagickString(tag,message,MagickLocaleExtent);
1371 (void) ConcatenateMagickString(tag,"\n",MagickLocaleExtent);
1375 if (LocaleCompare(keyword,"</message>") == 0)
1377 ChopLocaleComponents(tag,2);
1378 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1381 if (*keyword == '<')
1386 if (*(keyword+1) == '?')
1388 if (*(keyword+1) == '/')
1390 ChopLocaleComponents(tag,1);
1392 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1395 token[strlen(token)-1]='\0';
1396 (void) CopyMagickString(token,token+1,MagickLocaleExtent);
1397 (void) ConcatenateMagickString(tag,token,MagickLocaleExtent);
1398 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1401 GetNextToken(q,(const char **) NULL,extent,token);
1405 token=(char *) RelinquishMagickMemory(token);
1406 (void) SetFatalErrorHandler(fatal_handler);
1407 return(status != 0 ? MagickTrue : MagickFalse);
1411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415 % L o c a l e C o m p a r e %
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 % LocaleCompare() performs a case-insensitive comparison of two strings
1422 % byte-by-byte, according to the ordering of the current locale encoding.
1423 % LocaleCompare returns an integer greater than, equal to, or less than 0,
1424 % if the string pointed to by p is greater than, equal to, or less than the
1425 % string pointed to by q respectively. The sign of a non-zero return value
1426 % is determined by the sign of the difference between the values of the first
1427 % pair of bytes that differ in the strings being compared.
1429 % The format of the LocaleCompare method is:
1431 % int LocaleCompare(const char *p,const char *q)
1433 % A description of each parameter follows:
1435 % o p: A pointer to a character string.
1437 % o q: A pointer to a character string to compare to p.
1440 MagickExport int LocaleCompare(const char *p,const char *q)
1442 if ((p == (char *) NULL) && (q == (char *) NULL))
1444 if (p == (char *) NULL)
1446 if (q == (char *) NULL)
1448 #if defined(MAGICKCORE_HAVE_STRCASECMP)
1449 return(strcasecmp(p,q));
1458 c=(int) *((unsigned char *) p);
1459 d=(int) *((unsigned char *) q);
1460 if ((c == 0) || (AsciiMap[c] != AsciiMap[d]))
1465 return(AsciiMap[c]-(int) AsciiMap[d]);
1471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475 % L o c a l e L o w e r %
1479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481 % LocaleLower() transforms all of the characters in the supplied
1482 % null-terminated string, changing all uppercase letters to lowercase.
1484 % The format of the LocaleLower method is:
1486 % void LocaleLower(char *string)
1488 % A description of each parameter follows:
1490 % o string: A pointer to the string to convert to lower-case Locale.
1493 MagickExport void LocaleLower(char *string)
1498 assert(string != (char *) NULL);
1499 for (q=string; *q != '\0'; q++)
1500 *q=(char) tolower((int) *q);
1504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1508 % L o c a l e N C o m p a r e %
1512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1514 % LocaleNCompare() performs a case-insensitive comparison of two strings
1515 % byte-by-byte, according to the ordering of the current locale encoding.
1517 % LocaleNCompare returns an integer greater than, equal to, or less than 0,
1518 % if the string pointed to by p is greater than, equal to, or less than the
1519 % string pointed to by q respectively. The sign of a non-zero return value
1520 % is determined by the sign of the difference between the values of the first
1521 % pair of bytes that differ in the strings being compared.
1523 % The LocaleNCompare method makes the same comparison as LocaleCompare but
1524 % looks at a maximum of n bytes. Bytes following a null byte are not
1527 % The format of the LocaleNCompare method is:
1529 % int LocaleNCompare(const char *p,const char *q,const size_t n)
1531 % A description of each parameter follows:
1533 % o p: A pointer to a character string.
1535 % o q: A pointer to a character string to compare to p.
1537 % o length: the number of characters to compare in strings p and q.
1540 MagickExport int LocaleNCompare(const char *p,const char *q,const size_t length)
1542 if ((p == (char *) NULL) && (q == (char *) NULL))
1544 if (p == (char *) NULL)
1546 if (q == (char *) NULL)
1548 #if defined(MAGICKCORE_HAVE_STRNCASECMP)
1549 return(strncasecmp(p,q,length));
1559 for (i=length; i != 0; i--)
1561 c=(int) *((unsigned char *) p);
1562 d=(int) *((unsigned char *) q);
1563 if (AsciiMap[c] != AsciiMap[d])
1564 return(AsciiMap[c]-(int) AsciiMap[d]);
1576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1580 % L o c a l e U p p e r %
1584 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586 % LocaleUpper() transforms all of the characters in the supplied
1587 % null-terminated string, changing all lowercase letters to uppercase.
1589 % The format of the LocaleUpper method is:
1591 % void LocaleUpper(char *string)
1593 % A description of each parameter follows:
1595 % o string: A pointer to the string to convert to upper-case Locale.
1598 MagickExport void LocaleUpper(char *string)
1603 assert(string != (char *) NULL);
1604 for (q=string; *q != '\0'; q++)
1605 *q=(char) toupper((int) *q);
1609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1613 + L o c a l e C o m p o n e n t G e n e s i s %
1617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619 % LocaleComponentGenesis() instantiates the locale component.
1621 % The format of the LocaleComponentGenesis method is:
1623 % MagickBooleanType LocaleComponentGenesis(void)
1626 MagickPrivate MagickBooleanType LocaleComponentGenesis(void)
1628 if (locale_semaphore == (SemaphoreInfo *) NULL)
1629 locale_semaphore=AcquireSemaphoreInfo();
1634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638 + L o c a l e C o m p o n e n t T e r m i n u s %
1642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644 % LocaleComponentTerminus() destroys the locale component.
1646 % The format of the LocaleComponentTerminus method is:
1648 % LocaleComponentTerminus(void)
1651 MagickPrivate void LocaleComponentTerminus(void)
1653 if (locale_semaphore == (SemaphoreInfo *) NULL)
1654 ActivateSemaphoreInfo(&locale_semaphore);
1655 LockSemaphoreInfo(locale_semaphore);
1656 if (locale_cache != (SplayTreeInfo *) NULL)
1657 locale_cache=DestroySplayTree(locale_cache);
1658 #if defined(MAGICKCORE_LOCALE_SUPPORT)
1661 UnlockSemaphoreInfo(locale_semaphore);
1662 RelinquishSemaphoreInfo(&locale_semaphore);