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