MagickCore 7.1.1
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
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% Cristy %
17% July 2003 %
18% %
19% %
20% Copyright @ 2003 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% https://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
39/*
40 Include declarations.
41*/
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"
65
66/*
67 Define declarations.
68*/
69#if (defined(MAGICKCORE_HAVE_NEWLOCALE) || defined(MAGICKCORE_WINDOWS_SUPPORT)) && !defined(__MINGW32__)
70# define MAGICKCORE_LOCALE_SUPPORT
71#endif
72#define LocaleFilename "locale.xml"
73
74/*
75 Static declarations.
76*/
77static const char
78 *LocaleMap =
79 "<?xml version=\"1.0\"?>"
80 "<localemap>"
81 " <locale name=\"C\">"
82 " <Exception>"
83 " <Message name=\"\">"
84 " </Message>"
85 " </Exception>"
86 " </locale>"
87 "</localemap>";
88
89static SemaphoreInfo
90 *locale_semaphore = (SemaphoreInfo *) NULL;
91
92static SplayTreeInfo
93 *locale_cache = (SplayTreeInfo *) NULL;
94
95#if defined(MAGICKCORE_LOCALE_SUPPORT)
96static volatile locale_t
97 c_locale = (locale_t) NULL;
98#endif
99
100/*
101 Forward declarations.
102*/
103static MagickBooleanType
104 IsLocaleTreeInstantiated(ExceptionInfo *),
105 LoadLocaleCache(SplayTreeInfo *,const char *,const char *,const char *,
106 const size_t,ExceptionInfo *);
107
108#if defined(MAGICKCORE_LOCALE_SUPPORT)
109/*
110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111% %
112% %
113% %
114+ A c q u i r e C L o c a l e %
115% %
116% %
117% %
118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119%
120% AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
121% errno set if it cannot be acquired.
122%
123% The format of the AcquireCLocale method is:
124%
125% locale_t AcquireCLocale(void)
126%
127*/
128static locale_t AcquireCLocale(void)
129{
130#if defined(MAGICKCORE_HAVE_NEWLOCALE)
131 if (c_locale == (locale_t) NULL)
132 c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
133#elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
134 if (c_locale == (locale_t) NULL)
135 c_locale=_create_locale(LC_ALL,"C");
136#endif
137 return(c_locale);
138}
139#endif
140
141/*
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143% %
144% %
145% %
146% A c q u i r e L o c a l e S p l a y T r e e %
147% %
148% %
149% %
150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151%
152% AcquireLocaleSplayTree() caches one or more locale configurations which
153% provides a mapping between locale attributes and a locale tag.
154%
155% The format of the AcquireLocaleSplayTree method is:
156%
157% SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
158% ExceptionInfo *exception)
159%
160% A description of each parameter follows:
161%
162% o filename: the font file tag.
163%
164% o locale: the actual locale.
165%
166% o exception: return any errors or warnings in this structure.
167%
168*/
169
170static void *DestroyLocaleNode(void *locale_info)
171{
173 *p;
174
175 p=(LocaleInfo *) locale_info;
176 if (p->path != (char *) NULL)
177 p->path=DestroyString(p->path);
178 if (p->tag != (char *) NULL)
179 p->tag=DestroyString(p->tag);
180 if (p->message != (char *) NULL)
181 p->message=DestroyString(p->message);
182 return(RelinquishMagickMemory(p));
183}
184
185static SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
186 const char *locale,ExceptionInfo *exception)
187{
189 *cache;
190
191 cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
192 DestroyLocaleNode);
193#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
194 {
195 const StringInfo
196 *option;
197
199 *options;
200
201 options=GetLocaleOptions(filename,exception);
202 option=(const StringInfo *) GetNextValueInLinkedList(options);
203 while (option != (const StringInfo *) NULL)
204 {
205 (void) LoadLocaleCache(cache,(const char *)
206 GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
207 exception);
208 option=(const StringInfo *) GetNextValueInLinkedList(options);
209 }
210 options=DestroyLocaleOptions(options);
211 if (GetNumberOfNodesInSplayTree(cache) == 0)
212 {
213 options=GetLocaleOptions("english.xml",exception);
214 option=(const StringInfo *) GetNextValueInLinkedList(options);
215 while (option != (const StringInfo *) NULL)
216 {
217 (void) LoadLocaleCache(cache,(const char *)
218 GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
219 exception);
220 option=(const StringInfo *) GetNextValueInLinkedList(options);
221 }
222 options=DestroyLocaleOptions(options);
223 }
224 }
225#else
226 magick_unreferenced(filename);
227#endif
228 if (GetNumberOfNodesInSplayTree(cache) == 0)
229 (void) LoadLocaleCache(cache,LocaleMap,"built-in",locale,0,
230 exception);
231 return(cache);
232}
233
234#if defined(MAGICKCORE_LOCALE_SUPPORT)
235/*
236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237% %
238% %
239% %
240+ D e s t r o y C L o c a l e %
241% %
242% %
243% %
244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245%
246% DestroyCLocale() releases the resources allocated for a locale object
247% returned by a call to the AcquireCLocale() method.
248%
249% The format of the DestroyCLocale method is:
250%
251% void DestroyCLocale(void)
252%
253*/
254static void DestroyCLocale(void)
255{
256 if (c_locale != (locale_t) NULL)
257 freelocale(c_locale);
258 c_locale=(locale_t) NULL;
259}
260#endif
261
262/*
263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264% %
265% %
266% %
267% D e s t r o y L o c a l e O p t i o n s %
268% %
269% %
270% %
271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272%
273% DestroyLocaleOptions() releases memory associated with an locale
274% messages.
275%
276% The format of the DestroyProfiles method is:
277%
278% LinkedListInfo *DestroyLocaleOptions(Image *image)
279%
280% A description of each parameter follows:
281%
282% o image: the image.
283%
284*/
285
286static void *DestroyOptions(void *message)
287{
288 return(DestroyStringInfo((StringInfo *) message));
289}
290
291MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
292{
293 assert(messages != (LinkedListInfo *) NULL);
294 if (IsEventLogging() != MagickFalse)
295 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
296 return(DestroyLinkedList(messages,DestroyOptions));
297}
298
299/*
300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301% %
302% %
303% %
304+ F o r m a t L o c a l e F i l e %
305% %
306% %
307% %
308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309%
310% FormatLocaleFile() prints formatted output of a variable argument list to a
311% file in the "C" locale.
312%
313% The format of the FormatLocaleFile method is:
314%
315% ssize_t FormatLocaleFile(FILE *file,const char *format,...)
316%
317% A description of each parameter follows.
318%
319% o file: the file.
320%
321% o format: A file describing the format to use to write the remaining
322% arguments.
323%
324*/
325
326MagickPrivate ssize_t FormatLocaleFileList(FILE *file,
327 const char *magick_restrict format,va_list operands)
328{
329 ssize_t
330 n;
331
332#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_VFPRINTF_L)
333 {
334 locale_t
335 locale;
336
337 locale=AcquireCLocale();
338 if (locale == (locale_t) NULL)
339 n=(ssize_t) vfprintf(file,format,operands);
340 else
341#if defined(MAGICKCORE_WINDOWS_SUPPORT)
342 n=(ssize_t) vfprintf_l(file,format,locale,operands);
343#else
344 n=(ssize_t) vfprintf_l(file,locale,format,operands);
345#endif
346 }
347#else
348#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
349 {
350 locale_t
351 locale,
352 previous_locale;
353
354 locale=AcquireCLocale();
355 if (locale == (locale_t) NULL)
356 n=(ssize_t) vfprintf(file,format,operands);
357 else
358 {
359 previous_locale=uselocale(locale);
360 n=(ssize_t) vfprintf(file,format,operands);
361 uselocale(previous_locale);
362 }
363 }
364#else
365 n=(ssize_t) vfprintf(file,format,operands);
366#endif
367#endif
368 return(n);
369}
370
371MagickExport ssize_t FormatLocaleFile(FILE *file,
372 const char *magick_restrict format,...)
373{
374 ssize_t
375 n;
376
377 va_list
378 operands;
379
380 va_start(operands,format);
381 n=FormatLocaleFileList(file,format,operands);
382 va_end(operands);
383 return(n);
384}
385
386/*
387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388% %
389% %
390% %
391+ F o r m a t L o c a l e S t r i n g %
392% %
393% %
394% %
395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396%
397% FormatLocaleString() prints formatted output of a variable argument list to
398% a string buffer in the "C" locale.
399%
400% The format of the FormatLocaleString method is:
401%
402% ssize_t FormatLocaleString(char *string,const size_t length,
403% const char *format,...)
404%
405% A description of each parameter follows.
406%
407% o string: FormatLocaleString() returns the formatted string in this
408% character buffer.
409%
410% o length: the maximum length of the string.
411%
412% o format: A string describing the format to use to write the remaining
413% arguments.
414%
415*/
416
417MagickPrivate ssize_t FormatLocaleStringList(char *magick_restrict string,
418 const size_t length,const char *magick_restrict format,va_list operands)
419{
420 ssize_t
421 n;
422
423#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_VSNPRINTF_L)
424 {
425 locale_t
426 locale;
427
428 locale=AcquireCLocale();
429 if (locale == (locale_t) NULL)
430 n=(ssize_t) vsnprintf(string,length,format,operands);
431 else
432#if defined(MAGICKCORE_WINDOWS_SUPPORT)
433 n=(ssize_t) vsnprintf_l(string,length,format,locale,operands);
434#else
435 n=(ssize_t) vsnprintf_l(string,length,locale,format,operands);
436#endif
437 }
438#elif defined(MAGICKCORE_HAVE_VSNPRINTF)
439#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
440 {
441 locale_t
442 locale,
443 previous_locale;
444
445 locale=AcquireCLocale();
446 if (locale == (locale_t) NULL)
447 n=(ssize_t) vsnprintf(string,length,format,operands);
448 else
449 {
450 previous_locale=uselocale(locale);
451 n=(ssize_t) vsnprintf(string,length,format,operands);
452 uselocale(previous_locale);
453 }
454 }
455#else
456 n=(ssize_t) vsnprintf(string,length,format,operands);
457#endif
458#else
459 n=(ssize_t) vsprintf(string,format,operands);
460#endif
461 if (n < 0)
462 string[length-1]='\0';
463 return(n);
464}
465
466MagickExport ssize_t FormatLocaleString(char *magick_restrict string,
467 const size_t length,const char *magick_restrict format,...)
468{
469 ssize_t
470 n;
471
472 va_list
473 operands;
474
475 va_start(operands,format);
476 n=FormatLocaleStringList(string,length,format,operands);
477 va_end(operands);
478 return(n);
479}
480
481/*
482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483% %
484% %
485% %
486+ G e t L o c a l e I n f o _ %
487% %
488% %
489% %
490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491%
492% GetLocaleInfo_() searches the locale list for the specified tag and if
493% found returns attributes for that element.
494%
495% The format of the GetLocaleInfo method is:
496%
497% const LocaleInfo *GetLocaleInfo_(const char *tag,
498% ExceptionInfo *exception)
499%
500% A description of each parameter follows:
501%
502% o tag: the locale tag.
503%
504% o exception: return any errors or warnings in this structure.
505%
506*/
507MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
508 ExceptionInfo *exception)
509{
510 const LocaleInfo
511 *locale_info;
512
513 assert(exception != (ExceptionInfo *) NULL);
514 if (IsLocaleTreeInstantiated(exception) == MagickFalse)
515 return((const LocaleInfo *) NULL);
516 LockSemaphoreInfo(locale_semaphore);
517 if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
518 {
519 ResetSplayTreeIterator(locale_cache);
520 locale_info=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
521 UnlockSemaphoreInfo(locale_semaphore);
522 return(locale_info);
523 }
524 locale_info=(const LocaleInfo *) GetValueFromSplayTree(locale_cache,tag);
525 UnlockSemaphoreInfo(locale_semaphore);
526 return(locale_info);
527}
528
529/*
530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
531% %
532% %
533% %
534% G e t L o c a l e I n f o L i s t %
535% %
536% %
537% %
538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539%
540% GetLocaleInfoList() returns any locale messages that match the
541% specified pattern.
542%
543% The format of the GetLocaleInfoList function is:
544%
545% const LocaleInfo **GetLocaleInfoList(const char *pattern,
546% size_t *number_messages,ExceptionInfo *exception)
547%
548% A description of each parameter follows:
549%
550% o pattern: Specifies a pointer to a text string containing a pattern.
551%
552% o number_messages: This integer returns the number of locale messages in
553% the list.
554%
555% o exception: return any errors or warnings in this structure.
556%
557*/
558
559#if defined(__cplusplus) || defined(c_plusplus)
560extern "C" {
561#endif
562
563static int LocaleInfoCompare(const void *x,const void *y)
564{
565 const LocaleInfo
566 **p,
567 **q;
568
569 p=(const LocaleInfo **) x,
570 q=(const LocaleInfo **) y;
571 if (LocaleCompare((*p)->path,(*q)->path) == 0)
572 return(LocaleCompare((*p)->tag,(*q)->tag));
573 return(LocaleCompare((*p)->path,(*q)->path));
574}
575
576#if defined(__cplusplus) || defined(c_plusplus)
577}
578#endif
579
580MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
581 size_t *number_messages,ExceptionInfo *exception)
582{
583 const LocaleInfo
584 **messages;
585
586 const LocaleInfo
587 *p;
588
589 ssize_t
590 i;
591
592 /*
593 Allocate locale list.
594 */
595 assert(pattern != (char *) NULL);
596 assert(number_messages != (size_t *) NULL);
597 if (IsEventLogging() != MagickFalse)
598 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
599 *number_messages=0;
600 p=GetLocaleInfo_("*",exception);
601 if (p == (const LocaleInfo *) NULL)
602 return((const LocaleInfo **) NULL);
603 messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
604 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
605 if (messages == (const LocaleInfo **) NULL)
606 return((const LocaleInfo **) NULL);
607 /*
608 Generate locale list.
609 */
610 LockSemaphoreInfo(locale_semaphore);
611 ResetSplayTreeIterator(locale_cache);
612 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
613 for (i=0; p != (const LocaleInfo *) NULL; )
614 {
615 if ((p->stealth == MagickFalse) &&
616 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
617 messages[i++]=p;
618 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
619 }
620 UnlockSemaphoreInfo(locale_semaphore);
621 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
622 messages[i]=(LocaleInfo *) NULL;
623 *number_messages=(size_t) i;
624 return(messages);
625}
626
627/*
628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629% %
630% %
631% %
632% G e t L o c a l e L i s t %
633% %
634% %
635% %
636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
637%
638% GetLocaleList() returns any locale messages that match the specified
639% pattern.
640%
641% The format of the GetLocaleList function is:
642%
643% char **GetLocaleList(const char *pattern,size_t *number_messages,
644% Exceptioninfo *exception)
645%
646% A description of each parameter follows:
647%
648% o pattern: Specifies a pointer to a text string containing a pattern.
649%
650% o number_messages: This integer returns the number of messages in the
651% list.
652%
653% o exception: return any errors or warnings in this structure.
654%
655*/
656
657#if defined(__cplusplus) || defined(c_plusplus)
658extern "C" {
659#endif
660
661static int LocaleTagCompare(const void *x,const void *y)
662{
663 char
664 **p,
665 **q;
666
667 p=(char **) x;
668 q=(char **) y;
669 return(LocaleCompare(*p,*q));
670}
671
672#if defined(__cplusplus) || defined(c_plusplus)
673}
674#endif
675
676MagickExport char **GetLocaleList(const char *pattern,size_t *number_messages,
677 ExceptionInfo *exception)
678{
679 char
680 **messages;
681
682 const LocaleInfo
683 *p;
684
685 ssize_t
686 i;
687
688 /*
689 Allocate locale list.
690 */
691 assert(pattern != (char *) NULL);
692 assert(number_messages != (size_t *) NULL);
693 if (IsEventLogging() != MagickFalse)
694 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
695 *number_messages=0;
696 p=GetLocaleInfo_("*",exception);
697 if (p == (const LocaleInfo *) NULL)
698 return((char **) NULL);
699 messages=(char **) AcquireQuantumMemory((size_t)
700 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
701 if (messages == (char **) NULL)
702 return((char **) NULL);
703 LockSemaphoreInfo(locale_semaphore);
704 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
705 for (i=0; p != (const LocaleInfo *) NULL; )
706 {
707 if ((p->stealth == MagickFalse) &&
708 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
709 messages[i++]=ConstantString(p->tag);
710 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
711 }
712 UnlockSemaphoreInfo(locale_semaphore);
713 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
714 messages[i]=(char *) NULL;
715 *number_messages=(size_t) i;
716 return(messages);
717}
718
719/*
720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721% %
722% %
723% %
724% G e t L o c a l e M e s s a g e %
725% %
726% %
727% %
728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729%
730% GetLocaleMessage() returns a message in the current locale that matches the
731% supplied tag.
732%
733% The format of the GetLocaleMessage method is:
734%
735% const char *GetLocaleMessage(const char *tag)
736%
737% A description of each parameter follows:
738%
739% o tag: Return a message that matches this tag in the current locale.
740%
741*/
742MagickExport const char *GetLocaleMessage(const char *tag)
743{
744 char
745 name[MagickLocaleExtent];
746
747 const LocaleInfo
748 *locale_info;
749
751 *exception;
752
753 if ((tag == (const char *) NULL) || (*tag == '\0'))
754 return(tag);
755 exception=AcquireExceptionInfo();
756 (void) FormatLocaleString(name,MagickLocaleExtent,"%s/",tag);
757 locale_info=GetLocaleInfo_(name,exception);
758 exception=DestroyExceptionInfo(exception);
759 if (locale_info != (const LocaleInfo *) NULL)
760 return(locale_info->message);
761 return(tag);
762}
763
764/*
765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766% %
767% %
768% %
769% G e t L o c a l e O p t i o n s %
770% %
771% %
772% %
773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
774%
775% GetLocaleOptions() returns any Magick configuration messages associated
776% with the specified filename.
777%
778% The format of the GetLocaleOptions method is:
779%
780% LinkedListInfo *GetLocaleOptions(const char *filename,
781% ExceptionInfo *exception)
782%
783% A description of each parameter follows:
784%
785% o filename: the locale file tag.
786%
787% o exception: return any errors or warnings in this structure.
788%
789*/
790MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
791 ExceptionInfo *exception)
792{
793 char
794 path[MagickPathExtent];
795
796 const char
797 *element;
798
800 *messages,
801 *paths;
802
804 *xml;
805
806 assert(filename != (const char *) NULL);
807 assert(exception != (ExceptionInfo *) NULL);
808 if (IsEventLogging() != MagickFalse)
809 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
810 (void) CopyMagickString(path,filename,MagickPathExtent);
811 /*
812 Load XML from configuration files to linked-list.
813 */
814 messages=NewLinkedList(0);
815 paths=GetConfigurePaths(filename,exception);
816 if (paths != (LinkedListInfo *) NULL)
817 {
818 ResetLinkedListIterator(paths);
819 element=(const char *) GetNextValueInLinkedList(paths);
820 while (element != (const char *) NULL)
821 {
822 (void) FormatLocaleString(path,MagickPathExtent,"%s%s",element,
823 filename);
824 (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
825 "Searching for locale file: \"%s\"",path);
826 xml=ConfigureFileToStringInfo(path);
827 if (xml != (StringInfo *) NULL)
828 (void) AppendValueToLinkedList(messages,xml);
829 element=(const char *) GetNextValueInLinkedList(paths);
830 }
831 paths=DestroyLinkedList(paths,RelinquishMagickMemory);
832 }
833#if defined(MAGICKCORE_WINDOWS_SUPPORT)
834 {
835 char
836 *blob;
837
838 blob=(char *) NTResourceToBlob(filename);
839 if (blob != (char *) NULL)
840 {
841 xml=AcquireStringInfo(0);
842 SetStringInfoLength(xml,strlen(blob)+1);
843 SetStringInfoDatum(xml,(const unsigned char *) blob);
844 blob=(char *) RelinquishMagickMemory(blob);
845 SetStringInfoPath(xml,filename);
846 (void) AppendValueToLinkedList(messages,xml);
847 }
848 }
849#endif
850 ResetLinkedListIterator(messages);
851 return(messages);
852}
853
854/*
855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856% %
857% %
858% %
859% G e t L o c a l e V a l u e %
860% %
861% %
862% %
863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864%
865% GetLocaleValue() returns the message associated with the locale info.
866%
867% The format of the GetLocaleValue method is:
868%
869% const char *GetLocaleValue(const LocaleInfo *locale_info)
870%
871% A description of each parameter follows:
872%
873% o locale_info: The locale info.
874%
875*/
876MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
877{
878 if (IsEventLogging() != MagickFalse)
879 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
880 assert(locale_info != (LocaleInfo *) NULL);
881 assert(locale_info->signature == MagickCoreSignature);
882 return(locale_info->message);
883}
884
885/*
886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
887% %
888% %
889% %
890+ I s L o c a l e T r e e I n s t a n t i a t e d %
891% %
892% %
893% %
894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
895%
896% IsLocaleTreeInstantiated() determines if the locale tree is instantiated.
897% If not, it instantiates the tree and returns it.
898%
899% The format of the IsLocaleInstantiated method is:
900%
901% MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
902%
903% A description of each parameter follows.
904%
905% o exception: return any errors or warnings in this structure.
906%
907*/
908static MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
909{
910 if (locale_cache == (SplayTreeInfo *) NULL)
911 {
912 if (locale_semaphore == (SemaphoreInfo *) NULL)
913 ActivateSemaphoreInfo(&locale_semaphore);
914 LockSemaphoreInfo(locale_semaphore);
915 if (locale_cache == (SplayTreeInfo *) NULL)
916 {
917 char
918 *locale;
919
920 const char
921 *p;
922
923 locale=(char *) NULL;
924 p=setlocale(LC_CTYPE,(const char *) NULL);
925 if (p != (const char *) NULL)
926 locale=ConstantString(p);
927 if (locale == (char *) NULL)
928 locale=GetEnvironmentValue("LC_ALL");
929 if (locale == (char *) NULL)
930 locale=GetEnvironmentValue("LC_MESSAGES");
931 if (locale == (char *) NULL)
932 locale=GetEnvironmentValue("LC_CTYPE");
933 if (locale == (char *) NULL)
934 locale=GetEnvironmentValue("LANG");
935 if (locale == (char *) NULL)
936 locale=ConstantString("C");
937 locale_cache=AcquireLocaleSplayTree(LocaleFilename,locale,exception);
938 locale=DestroyString(locale);
939 }
940 UnlockSemaphoreInfo(locale_semaphore);
941 }
942 return(locale_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
943}
944
945/*
946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
947% %
948% %
949% %
950+ I n t e r p r e t L o c a l e V a l u e %
951% %
952% %
953% %
954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
955%
956% InterpretLocaleValue() interprets the string as a floating point number in
957% the "C" locale and returns its value as a double. If sentinel is not a null
958% pointer, the method also sets the value pointed by sentinel to point to the
959% first character after the number.
960%
961% The format of the InterpretLocaleValue method is:
962%
963% double InterpretLocaleValue(const char *value,char **sentinel)
964%
965% A description of each parameter follows:
966%
967% o value: the string value.
968%
969% o sentinel: if sentinel is not NULL, a pointer to the character after the
970% last character used in the conversion is stored in the location
971% referenced by sentinel.
972%
973*/
974MagickExport double InterpretLocaleValue(const char *magick_restrict string,
975 char *magick_restrict *sentinel)
976{
977 char
978 *q;
979
980 double
981 value;
982
983 if ((*string == '0') && ((string[1] | 0x20)=='x'))
984 value=(double) strtoul(string,&q,16);
985 else
986 {
987#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_STRTOD_L)
988 locale_t
989 locale;
990
991 locale=AcquireCLocale();
992 if (locale == (locale_t) NULL)
993 value=strtod(string,&q);
994 else
995 value=strtod_l(string,&q,locale);
996#else
997 value=strtod(string,&q);
998#endif
999 }
1000 if (sentinel != (char **) NULL)
1001 *sentinel=q;
1002 return(value);
1003}
1004
1005/*
1006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1007% %
1008% %
1009% %
1010% L i s t L o c a l e I n f o %
1011% %
1012% %
1013% %
1014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015%
1016% ListLocaleInfo() lists the locale info to a file.
1017%
1018% The format of the ListLocaleInfo method is:
1019%
1020% MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
1021%
1022% A description of each parameter follows.
1023%
1024% o file: An pointer to a FILE.
1025%
1026% o exception: return any errors or warnings in this structure.
1027%
1028*/
1029MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
1030 ExceptionInfo *exception)
1031{
1032 const char
1033 *path;
1034
1035 const LocaleInfo
1036 **locale_info;
1037
1038 ssize_t
1039 i;
1040
1041 size_t
1042 number_messages;
1043
1044 if (file == (const FILE *) NULL)
1045 file=stdout;
1046 number_messages=0;
1047 locale_info=GetLocaleInfoList("*",&number_messages,exception);
1048 if (locale_info == (const LocaleInfo **) NULL)
1049 return(MagickFalse);
1050 path=(const char *) NULL;
1051 for (i=0; i < (ssize_t) number_messages; i++)
1052 {
1053 if (locale_info[i]->stealth != MagickFalse)
1054 continue;
1055 if ((path == (const char *) NULL) ||
1056 (LocaleCompare(path,locale_info[i]->path) != 0))
1057 {
1058 if (locale_info[i]->path != (char *) NULL)
1059 (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
1060 (void) FormatLocaleFile(file,"Tag/Message\n");
1061 (void) FormatLocaleFile(file,
1062 "-------------------------------------------------"
1063 "------------------------------\n");
1064 }
1065 path=locale_info[i]->path;
1066 (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
1067 if (locale_info[i]->message != (char *) NULL)
1068 (void) FormatLocaleFile(file," %s",locale_info[i]->message);
1069 (void) FormatLocaleFile(file,"\n");
1070 }
1071 (void) fflush(file);
1072 locale_info=(const LocaleInfo **)
1073 RelinquishMagickMemory((void *) locale_info);
1074 return(MagickTrue);
1075}
1076
1077/*
1078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079% %
1080% %
1081% %
1082+ L o a d L o c a l e C a c h e %
1083% %
1084% %
1085% %
1086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087%
1088% LoadLocaleCache() loads the locale configurations which provides a mapping
1089% between locale attributes and a locale name.
1090%
1091% The format of the LoadLocaleCache method is:
1092%
1093% MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1094% const char *filename,const size_t depth,ExceptionInfo *exception)
1095%
1096% A description of each parameter follows:
1097%
1098% o xml: The locale list in XML format.
1099%
1100% o filename: The locale list filename.
1101%
1102% o depth: depth of <include /> statements.
1103%
1104% o exception: return any errors or warnings in this structure.
1105%
1106*/
1107
1108static void ChopLocaleComponents(char *path,const size_t components)
1109{
1110 char
1111 *p;
1112
1113 ssize_t
1114 count;
1115
1116 if (*path == '\0')
1117 return;
1118 p=path+strlen(path)-1;
1119 if (*p == '/')
1120 *p='\0';
1121 for (count=0; (count < (ssize_t) components) && (p > path); p--)
1122 if (*p == '/')
1123 {
1124 *p='\0';
1125 count++;
1126 }
1127 if (count < (ssize_t) components)
1128 *path='\0';
1129}
1130
1131
1132static void LocaleFatalErrorHandler(const ExceptionType severity,
1133 const char *reason,const char *description) magick_attribute((__noreturn__));
1134
1135static void LocaleFatalErrorHandler(
1136 const ExceptionType magick_unused(severity),
1137 const char *reason,const char *description)
1138{
1139 magick_unreferenced(severity);
1140
1141 (void) FormatLocaleFile(stderr,"%s: ",GetClientName());
1142 if (reason != (char *) NULL)
1143 (void) FormatLocaleFile(stderr," %s",reason);
1144 if (description != (char *) NULL)
1145 (void) FormatLocaleFile(stderr," (%s)",description);
1146 (void) FormatLocaleFile(stderr,".\n");
1147 (void) fflush(stderr);
1148 exit(1);
1149}
1150
1151static MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1152 const char *filename,const char *locale,const size_t depth,ExceptionInfo *exception)
1153{
1154 char
1155 keyword[MagickLocaleExtent],
1156 message[MagickLocaleExtent],
1157 tag[MagickLocaleExtent],
1158 *token;
1159
1160 const char
1161 *q;
1162
1163 FatalErrorHandler
1164 fatal_handler;
1165
1167 *locale_info;
1168
1169 MagickStatusType
1170 status;
1171
1172 char
1173 *p;
1174
1175 size_t
1176 extent;
1177
1178 /*
1179 Read the locale configure file.
1180 */
1181 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1182 "Loading locale configure file \"%s\" ...",filename);
1183 if (xml == (const char *) NULL)
1184 return(MagickFalse);
1185 status=MagickTrue;
1186 locale_info=(LocaleInfo *) NULL;
1187 *tag='\0';
1188 *message='\0';
1189 *keyword='\0';
1190 fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
1191 token=AcquireString(xml);
1192 extent=strlen(token)+MagickPathExtent;
1193 for (q=(char *) xml; *q != '\0'; )
1194 {
1195 /*
1196 Interpret XML.
1197 */
1198 (void) GetNextToken(q,&q,extent,token);
1199 if (*token == '\0')
1200 break;
1201 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1202 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1203 {
1204 /*
1205 Doctype element.
1206 */
1207 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1208 {
1209 (void) GetNextToken(q,&q,extent,token);
1210 while (isspace((int) ((unsigned char) *q)) != 0)
1211 q++;
1212 }
1213 continue;
1214 }
1215 if (LocaleNCompare(keyword,"<!--",4) == 0)
1216 {
1217 /*
1218 Comment element.
1219 */
1220 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1221 {
1222 (void) GetNextToken(q,&q,extent,token);
1223 while (isspace((int) ((unsigned char) *q)) != 0)
1224 q++;
1225 }
1226 continue;
1227 }
1228 if (LocaleCompare(keyword,"<include") == 0)
1229 {
1230 /*
1231 Include element.
1232 */
1233 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1234 {
1235 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1236 (void) GetNextToken(q,&q,extent,token);
1237 if (*token != '=')
1238 continue;
1239 (void) GetNextToken(q,&q,extent,token);
1240 if (LocaleCompare(keyword,"locale") == 0)
1241 {
1242 if (LocaleCompare(locale,token) != 0)
1243 break;
1244 continue;
1245 }
1246 if (LocaleCompare(keyword,"file") == 0)
1247 {
1248 if (depth > MagickMaxRecursionDepth)
1249 (void) ThrowMagickException(exception,GetMagickModule(),
1250 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1251 else
1252 {
1253 char
1254 path[MagickPathExtent],
1255 *file_xml;
1256
1257 *path='\0';
1258 GetPathComponent(filename,HeadPath,path);
1259 if (*path != '\0')
1260 (void) ConcatenateMagickString(path,DirectorySeparator,
1261 MagickPathExtent);
1262 if (*token == *DirectorySeparator)
1263 (void) CopyMagickString(path,token,MagickPathExtent);
1264 else
1265 (void) ConcatenateMagickString(path,token,MagickPathExtent);
1266 file_xml=FileToXML(path,~0UL);
1267 if (file_xml != (char *) NULL)
1268 {
1269 status&=(MagickStatusType) LoadLocaleCache(cache,file_xml,
1270 path,locale,depth+1,exception);
1271 file_xml=DestroyString(file_xml);
1272 }
1273 }
1274 }
1275 }
1276 continue;
1277 }
1278 if (LocaleCompare(keyword,"<locale") == 0)
1279 {
1280 /*
1281 Locale element.
1282 */
1283 while ((*token != '>') && (*q != '\0'))
1284 {
1285 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1286 (void) GetNextToken(q,&q,extent,token);
1287 if (*token != '=')
1288 continue;
1289 (void) GetNextToken(q,&q,extent,token);
1290 }
1291 continue;
1292 }
1293 if (LocaleCompare(keyword,"</locale>") == 0)
1294 {
1295 ChopLocaleComponents(tag,1);
1296 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1297 continue;
1298 }
1299 if (LocaleCompare(keyword,"<localemap>") == 0)
1300 continue;
1301 if (LocaleCompare(keyword,"</localemap>") == 0)
1302 continue;
1303 if (LocaleCompare(keyword,"<message") == 0)
1304 {
1305 /*
1306 Message element.
1307 */
1308 while ((*token != '>') && (*q != '\0'))
1309 {
1310 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1311 (void) GetNextToken(q,&q,extent,token);
1312 if (*token != '=')
1313 continue;
1314 (void) GetNextToken(q,&q,extent,token);
1315 if (LocaleCompare(keyword,"name") == 0)
1316 {
1317 (void) ConcatenateMagickString(tag,token,MagickLocaleExtent);
1318 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1319 }
1320 }
1321 for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1322 while (isspace((int) ((unsigned char) *p)) != 0)
1323 p++;
1324 q--;
1325 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1326 q--;
1327 (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2),
1328 MagickLocaleExtent));
1329 locale_info=(LocaleInfo *) AcquireCriticalMemory(sizeof(*locale_info));
1330 (void) memset(locale_info,0,sizeof(*locale_info));
1331 locale_info->path=ConstantString(filename);
1332 locale_info->tag=ConstantString(tag);
1333 locale_info->message=ConstantString(message);
1334 locale_info->signature=MagickCoreSignature;
1335 status=AddValueToSplayTree(cache,locale_info->tag,locale_info);
1336 if (status == MagickFalse)
1337 (void) ThrowMagickException(exception,GetMagickModule(),
1338 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1339 locale_info->tag);
1340 (void) ConcatenateMagickString(tag,message,MagickLocaleExtent);
1341 (void) ConcatenateMagickString(tag,"\n",MagickLocaleExtent);
1342 q++;
1343 continue;
1344 }
1345 if (LocaleCompare(keyword,"</message>") == 0)
1346 {
1347 ChopLocaleComponents(tag,2);
1348 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1349 continue;
1350 }
1351 if (*keyword == '<')
1352 {
1353 /*
1354 Subpath element.
1355 */
1356 if (*(keyword+1) == '?')
1357 continue;
1358 if (*(keyword+1) == '/')
1359 {
1360 ChopLocaleComponents(tag,1);
1361 if (*tag != '\0')
1362 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1363 continue;
1364 }
1365 token[strlen(token)-1]='\0';
1366 (void) CopyMagickString(token,token+1,MagickLocaleExtent);
1367 (void) ConcatenateMagickString(tag,token,MagickLocaleExtent);
1368 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
1369 continue;
1370 }
1371 (void) GetNextToken(q,(const char **) NULL,extent,token);
1372 if (*token != '=')
1373 continue;
1374 }
1375 token=(char *) RelinquishMagickMemory(token);
1376 (void) SetFatalErrorHandler(fatal_handler);
1377 return(status != 0 ? MagickTrue : MagickFalse);
1378}
1379
1380/*
1381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1382% %
1383% %
1384% %
1385% L o c a l e C o m p a r e %
1386% %
1387% %
1388% %
1389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1390%
1391% LocaleCompare() performs a case-insensitive comparison of two strings
1392% byte-by-byte, according to the ordering of the current locale encoding.
1393% LocaleCompare returns an integer greater than, equal to, or less than 0,
1394% if the string pointed to by p is greater than, equal to, or less than the
1395% string pointed to by q respectively. The sign of a non-zero return value
1396% is determined by the sign of the difference between the values of the first
1397% pair of bytes that differ in the strings being compared.
1398%
1399% The format of the LocaleCompare method is:
1400%
1401% int LocaleCompare(const char *p,const char *q)
1402%
1403% A description of each parameter follows:
1404%
1405% o p: A pointer to a character string.
1406%
1407% o q: A pointer to a character string to compare to p.
1408%
1409*/
1410MagickExport int LocaleCompare(const char *p,const char *q)
1411{
1412 if (p == (char *) NULL)
1413 {
1414 if (q == (char *) NULL)
1415 return(0);
1416 return(-1);
1417 }
1418 if (q == (char *) NULL)
1419 return(1);
1420 {
1421 const unsigned char
1422 *r = (const unsigned char *) p,
1423 *s = (const unsigned char *) q;
1424
1425 for ( ; (*r != '\0') && (*s != '\0') && ((*r == *s) ||
1426 (LocaleToLowercase((int) *r) == LocaleToLowercase((int) *s))); r++, s++);
1427 return(LocaleToLowercase((int) *r)-LocaleToLowercase((int) *s));
1428 }
1429}
1430
1431/*
1432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433% %
1434% %
1435% %
1436% L o c a l e L o w e r %
1437% %
1438% %
1439% %
1440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1441%
1442% LocaleLower() transforms all of the characters in the supplied
1443% null-terminated string, changing all uppercase letters to lowercase.
1444%
1445% The format of the LocaleLower method is:
1446%
1447% void LocaleLower(char *string)
1448%
1449% A description of each parameter follows:
1450%
1451% o string: A pointer to the string to convert to lower-case Locale.
1452%
1453*/
1454MagickExport void LocaleLower(char *string)
1455{
1456 char
1457 *q;
1458
1459 assert(string != (char *) NULL);
1460 for (q=string; *q != '\0'; q++)
1461 *q=(char) LocaleToLowercase((int) *q);
1462}
1463
1464/*
1465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466% %
1467% %
1468% %
1469% L o c a l e L o w e r c a s e %
1470% %
1471% %
1472% %
1473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474%
1475% LocaleLowercase() converts the character to lowercase.
1476%
1477% The format of the LocaleLowercase method is:
1478%
1479% void LocaleLowercase(const int c)
1480%
1481% A description of each parameter follows:
1482%
1483% o If c is a uppercase letter, return its lowercase equivalent.
1484%
1485*/
1486MagickExport int LocaleLowercase(const int c)
1487{
1488 return(LocaleToLowercase(c));
1489}
1490
1491/*
1492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1493% %
1494% %
1495% %
1496% L o c a l e N C o m p a r e %
1497% %
1498% %
1499% %
1500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1501%
1502% LocaleNCompare() performs a case-insensitive comparison of two strings
1503% byte-by-byte, according to the ordering of the current locale encoding.
1504%
1505% LocaleNCompare returns an integer greater than, equal to, or less than 0,
1506% if the string pointed to by p is greater than, equal to, or less than the
1507% string pointed to by q respectively. The sign of a non-zero return value
1508% is determined by the sign of the difference between the values of the first
1509% pair of bytes that differ in the strings being compared.
1510%
1511% The LocaleNCompare method makes the same comparison as LocaleCompare but
1512% looks at a maximum of n bytes. Bytes following a null byte are not
1513% compared.
1514%
1515% The format of the LocaleNCompare method is:
1516%
1517% int LocaleNCompare(const char *p,const char *q,const size_t n)
1518%
1519% A description of each parameter follows:
1520%
1521% o p: A pointer to a character string.
1522%
1523% o q: A pointer to a character string to compare to p.
1524%
1525% o length: the number of characters to compare in strings p and q.
1526%
1527*/
1528MagickExport int LocaleNCompare(const char *p,const char *q,const size_t length)
1529{
1530 if (p == (char *) NULL)
1531 {
1532 if (q == (char *) NULL)
1533 return(0);
1534 return(-1);
1535 }
1536 if (q == (char *) NULL)
1537 return(1);
1538 if (length == 0)
1539 return(0);
1540 {
1541 const unsigned char
1542 *s = (const unsigned char *) p,
1543 *t = (const unsigned char *) q;
1544
1545 size_t
1546 n = length;
1547
1548 for (n--; (*s != '\0') && (*t != '\0') && (n != 0) && ((*s == *t) ||
1549 (LocaleToLowercase((int) *s) == LocaleToLowercase((int) *t))); s++, t++, n--);
1550 return(LocaleToLowercase((int) *s)-LocaleToLowercase((int) *t));
1551 }
1552}
1553
1554/*
1555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556% %
1557% %
1558% %
1559% L o c a l e U p p e r %
1560% %
1561% %
1562% %
1563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1564%
1565% LocaleUpper() transforms all of the characters in the supplied
1566% null-terminated string, changing all lowercase letters to uppercase.
1567%
1568% The format of the LocaleUpper method is:
1569%
1570% void LocaleUpper(char *string)
1571%
1572% A description of each parameter follows:
1573%
1574% o string: A pointer to the string to convert to upper-case Locale.
1575%
1576*/
1577MagickExport void LocaleUpper(char *string)
1578{
1579 char
1580 *q;
1581
1582 assert(string != (char *) NULL);
1583 for (q=string; *q != '\0'; q++)
1584 *q=(char) LocaleToUppercase((int) *q);
1585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
1592% L o c a l e U p p e r c a s e %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
1598% LocaleUppercase() converts the character to uppercase.
1599%
1600% The format of the LocaleUppercase method is:
1601%
1602% void LocaleUppercase(const int c)
1603%
1604% A description of each parameter follows:
1605%
1606% o If c is a lowercase letter, return its uppercase equivalent.
1607%
1608*/
1609MagickExport int LocaleUppercase(const int c)
1610{
1611 return(LocaleToUppercase(c));
1612}
1613
1614/*
1615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616% %
1617% %
1618% %
1619+ L o c a l e C o m p o n e n t G e n e s i s %
1620% %
1621% %
1622% %
1623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624%
1625% LocaleComponentGenesis() instantiates the locale component.
1626%
1627% The format of the LocaleComponentGenesis method is:
1628%
1629% MagickBooleanType LocaleComponentGenesis(void)
1630%
1631*/
1632MagickPrivate MagickBooleanType LocaleComponentGenesis(void)
1633{
1634 if (locale_semaphore == (SemaphoreInfo *) NULL)
1635 locale_semaphore=AcquireSemaphoreInfo();
1636#if defined(MAGICKCORE_LOCALE_SUPPORT)
1637 (void) AcquireCLocale();
1638#endif
1639 return(MagickTrue);
1640}
1641
1642/*
1643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644% %
1645% %
1646% %
1647+ L o c a l e C o m p o n e n t T e r m i n u s %
1648% %
1649% %
1650% %
1651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1652%
1653% LocaleComponentTerminus() destroys the locale component.
1654%
1655% The format of the LocaleComponentTerminus method is:
1656%
1657% LocaleComponentTerminus(void)
1658%
1659*/
1660MagickPrivate void LocaleComponentTerminus(void)
1661{
1662 if (locale_semaphore == (SemaphoreInfo *) NULL)
1663 ActivateSemaphoreInfo(&locale_semaphore);
1664 LockSemaphoreInfo(locale_semaphore);
1665 if (locale_cache != (SplayTreeInfo *) NULL)
1666 locale_cache=DestroySplayTree(locale_cache);
1667#if defined(MAGICKCORE_LOCALE_SUPPORT)
1668 DestroyCLocale();
1669#endif
1670 UnlockSemaphoreInfo(locale_semaphore);
1671 RelinquishSemaphoreInfo(&locale_semaphore);
1672}