MagickCore 6.9.13-53
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 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_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
475 {
476 locale_t
477 locale,
478 previous_locale;
479
480 locale=AcquireCLocale();
481 if (locale == (locale_t) NULL)
482 n=(ssize_t) vsnprintf(string,length,format,operands);
483 else
484 {
485 previous_locale=uselocale(locale);
486 n=(ssize_t) vsnprintf(string,length,format,operands);
487 uselocale(previous_locale);
488 }
489 }
490#else
491 n=(ssize_t) vsnprintf(string,length,format,operands);
492#endif
493 if (n < 0)
494 string[length-1]='\0';
495 return(n);
496}
497
498MagickExport ssize_t FormatLocaleString(char *magick_restrict string,
499 const size_t length,const char *magick_restrict format,...)
500{
501 ssize_t
502 n;
503
504 va_list
505 operands;
506
507 va_start(operands,format);
508 n=FormatLocaleStringList(string,length,format,operands);
509 va_end(operands);
510 return(n);
511}
512
513/*
514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
515% %
516% %
517% %
518+ G e t L o c a l e I n f o _ %
519% %
520% %
521% %
522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523%
524% GetLocaleInfo_() searches the locale list for the specified tag and if
525% found returns attributes for that element.
526%
527% The format of the GetLocaleInfo method is:
528%
529% const LocaleInfo *GetLocaleInfo_(const char *tag,
530% ExceptionInfo *exception)
531%
532% A description of each parameter follows:
533%
534% o tag: the locale tag.
535%
536% o exception: return any errors or warnings in this structure.
537%
538*/
539MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
540 ExceptionInfo *exception)
541{
542 const LocaleInfo
543 *locale_info;
544
545 assert(exception != (ExceptionInfo *) NULL);
546 if (IsLocaleTreeInstantiated(exception) == MagickFalse)
547 return((const LocaleInfo *) NULL);
548 LockSemaphoreInfo(locale_semaphore);
549 if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
550 {
551 ResetSplayTreeIterator(locale_cache);
552 locale_info=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
553 UnlockSemaphoreInfo(locale_semaphore);
554 return(locale_info);
555 }
556 locale_info=(const LocaleInfo *) GetValueFromSplayTree(locale_cache,tag);
557 UnlockSemaphoreInfo(locale_semaphore);
558 return(locale_info);
559}
560
561/*
562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
563% %
564% %
565% %
566% G e t L o c a l e I n f o L i s t %
567% %
568% %
569% %
570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
571%
572% GetLocaleInfoList() returns any locale messages that match the
573% specified pattern.
574%
575% The format of the GetLocaleInfoList function is:
576%
577% const LocaleInfo **GetLocaleInfoList(const char *pattern,
578% size_t *number_messages,ExceptionInfo *exception)
579%
580% A description of each parameter follows:
581%
582% o pattern: Specifies a pointer to a text string containing a pattern.
583%
584% o number_messages: This integer returns the number of locale messages in
585% the list.
586%
587% o exception: return any errors or warnings in this structure.
588%
589*/
590
591#if defined(__cplusplus) || defined(c_plusplus)
592extern "C" {
593#endif
594
595static int LocaleInfoCompare(const void *x,const void *y)
596{
597 const LocaleInfo
598 **p,
599 **q;
600
601 p=(const LocaleInfo **) x,
602 q=(const LocaleInfo **) y;
603 if (LocaleCompare((*p)->path,(*q)->path) == 0)
604 return(LocaleCompare((*p)->tag,(*q)->tag));
605 return(LocaleCompare((*p)->path,(*q)->path));
606}
607
608#if defined(__cplusplus) || defined(c_plusplus)
609}
610#endif
611
612MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
613 size_t *number_messages,ExceptionInfo *exception)
614{
615 const LocaleInfo
616 **messages;
617
618 const LocaleInfo
619 *p;
620
621 ssize_t
622 i;
623
624 /*
625 Allocate locale list.
626 */
627 assert(pattern != (char *) NULL);
628 assert(number_messages != (size_t *) NULL);
629 if (IsEventLogging() != MagickFalse)
630 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
631 *number_messages=0;
632 p=GetLocaleInfo_("*",exception);
633 if (p == (const LocaleInfo *) NULL)
634 return((const LocaleInfo **) NULL);
635 messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
636 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
637 if (messages == (const LocaleInfo **) NULL)
638 return((const LocaleInfo **) NULL);
639 /*
640 Generate locale list.
641 */
642 LockSemaphoreInfo(locale_semaphore);
643 ResetSplayTreeIterator(locale_cache);
644 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
645 for (i=0; p != (const LocaleInfo *) NULL; )
646 {
647 if ((p->stealth == MagickFalse) &&
648 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
649 messages[i++]=p;
650 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
651 }
652 UnlockSemaphoreInfo(locale_semaphore);
653 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
654 messages[i]=(LocaleInfo *) NULL;
655 *number_messages=(size_t) i;
656 return(messages);
657}
658
659/*
660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
661% %
662% %
663% %
664% G e t L o c a l e L i s t %
665% %
666% %
667% %
668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669%
670% GetLocaleList() returns any locale messages that match the specified
671% pattern.
672%
673% The format of the GetLocaleList function is:
674%
675% char **GetLocaleList(const char *pattern,size_t *number_messages,
676% Exceptioninfo *exception)
677%
678% A description of each parameter follows:
679%
680% o pattern: Specifies a pointer to a text string containing a pattern.
681%
682% o number_messages: This integer returns the number of messages in the
683% list.
684%
685% o exception: return any errors or warnings in this structure.
686%
687*/
688
689#if defined(__cplusplus) || defined(c_plusplus)
690extern "C" {
691#endif
692
693static int LocaleTagCompare(const void *x,const void *y)
694{
695 char
696 **p,
697 **q;
698
699 p=(char **) x;
700 q=(char **) y;
701 return(LocaleCompare(*p,*q));
702}
703
704#if defined(__cplusplus) || defined(c_plusplus)
705}
706#endif
707
708MagickExport char **GetLocaleList(const char *pattern,
709 size_t *number_messages,ExceptionInfo *exception)
710{
711 char
712 **messages;
713
714 const LocaleInfo
715 *p;
716
717 ssize_t
718 i;
719
720 /*
721 Allocate locale list.
722 */
723 assert(pattern != (char *) NULL);
724 assert(number_messages != (size_t *) NULL);
725 if (IsEventLogging() != MagickFalse)
726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
727 *number_messages=0;
728 p=GetLocaleInfo_("*",exception);
729 if (p == (const LocaleInfo *) NULL)
730 return((char **) NULL);
731 messages=(char **) AcquireQuantumMemory((size_t)
732 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
733 if (messages == (char **) NULL)
734 return((char **) NULL);
735 LockSemaphoreInfo(locale_semaphore);
736 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
737 for (i=0; p != (const LocaleInfo *) NULL; )
738 {
739 if ((p->stealth == MagickFalse) &&
740 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
741 messages[i++]=ConstantString(p->tag);
742 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
743 }
744 UnlockSemaphoreInfo(locale_semaphore);
745 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
746 messages[i]=(char *) NULL;
747 *number_messages=(size_t) i;
748 return(messages);
749}
750
751/*
752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753% %
754% %
755% %
756% G e t L o c a l e M e s s a g e %
757% %
758% %
759% %
760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761%
762% GetLocaleMessage() returns a message in the current locale that matches the
763% supplied tag.
764%
765% The format of the GetLocaleMessage method is:
766%
767% const char *GetLocaleMessage(const char *tag)
768%
769% A description of each parameter follows:
770%
771% o tag: Return a message that matches this tag in the current locale.
772%
773*/
774MagickExport const char *GetLocaleMessage(const char *tag)
775{
776 char
777 name[MaxTextExtent];
778
779 const LocaleInfo
780 *locale_info;
781
782 ExceptionInfo
783 *exception;
784
785 if ((tag == (const char *) NULL) || (*tag == '\0'))
786 return(tag);
787 exception=AcquireExceptionInfo();
788 (void) FormatLocaleString(name,MaxTextExtent,"%s/",tag);
789 locale_info=GetLocaleInfo_(name,exception);
790 exception=DestroyExceptionInfo(exception);
791 if (locale_info != (const LocaleInfo *) NULL)
792 return(locale_info->message);
793 return(tag);
794}
795
796/*
797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798% %
799% %
800% %
801% G e t L o c a l e O p t i o n s %
802% %
803% %
804% %
805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
806%
807% GetLocaleOptions() returns any Magick configuration messages associated
808% with the specified filename.
809%
810% The format of the GetLocaleOptions method is:
811%
812% LinkedListInfo *GetLocaleOptions(const char *filename,
813% ExceptionInfo *exception)
814%
815% A description of each parameter follows:
816%
817% o filename: the locale file tag.
818%
819% o exception: return any errors or warnings in this structure.
820%
821*/
822MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
823 ExceptionInfo *exception)
824{
825 char
826 path[MaxTextExtent];
827
828 const char
829 *element;
830
831 LinkedListInfo
832 *messages,
833 *paths;
834
835 StringInfo
836 *xml;
837
838 assert(filename != (const char *) NULL);
839 assert(exception != (ExceptionInfo *) NULL);
840 if (IsEventLogging() != MagickFalse)
841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
842 (void) CopyMagickString(path,filename,MaxTextExtent);
843 /*
844 Load XML from configuration files to linked-list.
845 */
846 messages=NewLinkedList(0);
847 paths=GetConfigurePaths(filename,exception);
848 if (paths != (LinkedListInfo *) NULL)
849 {
850 ResetLinkedListIterator(paths);
851 element=(const char *) GetNextValueInLinkedList(paths);
852 while (element != (const char *) NULL)
853 {
854 (void) FormatLocaleString(path,MaxTextExtent,"%s%s",element,filename);
855 (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
856 "Searching for locale file: \"%s\"",path);
857 xml=ConfigureFileToStringInfo(path);
858 if (xml != (StringInfo *) NULL)
859 (void) AppendValueToLinkedList(messages,xml);
860 element=(const char *) GetNextValueInLinkedList(paths);
861 }
862 paths=DestroyLinkedList(paths,RelinquishMagickMemory);
863 }
864#if defined(MAGICKCORE_WINDOWS_SUPPORT)
865 {
866 char
867 *blob;
868
869 blob=(char *) NTResourceToBlob(filename);
870 if (blob != (char *) NULL)
871 {
872 xml=AcquireStringInfo(0);
873 SetStringInfoLength(xml,strlen(blob)+1);
874 SetStringInfoDatum(xml,(const unsigned char *) blob);
875 blob=(char *) RelinquishMagickMemory(blob);
876 SetStringInfoPath(xml,filename);
877 (void) AppendValueToLinkedList(messages,xml);
878 }
879 }
880#endif
881 ResetLinkedListIterator(messages);
882 return(messages);
883}
884
885/*
886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
887% %
888% %
889% %
890% G e t L o c a l e V a l u e %
891% %
892% %
893% %
894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
895%
896% GetLocaleValue() returns the message associated with the locale info.
897%
898% The format of the GetLocaleValue method is:
899%
900% const char *GetLocaleValue(const LocaleInfo *locale_info)
901%
902% A description of each parameter follows:
903%
904% o locale_info: The locale info.
905%
906*/
907MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
908{
909 if (IsEventLogging() != MagickFalse)
910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
911 assert(locale_info != (LocaleInfo *) NULL);
912 assert(locale_info->signature == MagickCoreSignature);
913 return(locale_info->message);
914}
915
916/*
917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918% %
919% %
920% %
921+ I s L o c a l e T r e e I n s t a n t i a t e d %
922% %
923% %
924% %
925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926%
927% IsLocaleTreeInstantiated() determines if the locale tree is instantiated.
928% If not, it instantiates the tree and returns it.
929%
930% The format of the IsLocaleInstantiated method is:
931%
932% MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
933%
934% A description of each parameter follows.
935%
936% o exception: return any errors or warnings in this structure.
937%
938*/
939static MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
940{
941 if (locale_cache == (SplayTreeInfo *) NULL)
942 {
943 if (locale_semaphore == (SemaphoreInfo *) NULL)
944 ActivateSemaphoreInfo(&locale_semaphore);
945 LockSemaphoreInfo(locale_semaphore);
946 if (locale_cache == (SplayTreeInfo *) NULL)
947 {
948 char
949 *locale;
950
951 const char
952 *p;
953
954 locale=(char *) NULL;
955 p=setlocale(LC_CTYPE,(const char *) NULL);
956 if (p != (const char *) NULL)
957 locale=ConstantString(p);
958 if (locale == (char *) NULL)
959 locale=GetEnvironmentValue("LC_ALL");
960 if (locale == (char *) NULL)
961 locale=GetEnvironmentValue("LC_MESSAGES");
962 if (locale == (char *) NULL)
963 locale=GetEnvironmentValue("LC_CTYPE");
964 if (locale == (char *) NULL)
965 locale=GetEnvironmentValue("LANG");
966 if (locale == (char *) NULL)
967 locale=ConstantString("C");
968 locale_cache=AcquireLocaleSplayTree(LocaleFilename,locale,exception);
969 locale=DestroyString(locale);
970 }
971 UnlockSemaphoreInfo(locale_semaphore);
972 }
973 return(locale_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
974}
975
976/*
977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
978% %
979% %
980% %
981+ I n t e r p r e t L o c a l e V a l u e %
982% %
983% %
984% %
985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986%
987% InterpretLocaleValue() interprets the string as a floating point number in
988% the "C" locale and returns its value as a double. If sentinal is not a null
989% pointer, the method also sets the value pointed by sentinal to point to the
990% first character after the number.
991%
992% The format of the InterpretLocaleValue method is:
993%
994% double InterpretLocaleValue(const char *value,char **sentinal)
995%
996% A description of each parameter follows:
997%
998% o value: the string value.
999%
1000% o sentinal: if sentinal is not NULL, a pointer to the character after the
1001% last character used in the conversion is stored in the location
1002% referenced by sentinal.
1003%
1004*/
1005MagickExport double InterpretLocaleValue(const char *magick_restrict string,
1006 char **magick_restrict sentinal)
1007{
1008 char
1009 *q;
1010
1011 double
1012 value;
1013
1014 if ((*string == '0') && ((string[1] | 0x20)=='x'))
1015 value=(double) strtoul(string,&q,16);
1016 else
1017 {
1018#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_STRTOD_L)
1019 locale_t
1020 locale;
1021
1022 locale=AcquireCLocale();
1023 if (locale == (locale_t) NULL)
1024 value=strtod(string,&q);
1025 else
1026#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1027 value=_strtod_l(string,&q,locale);
1028#else
1029 value=strtod_l(string,&q,locale);
1030#endif
1031#else
1032 value=strtod(string,&q);
1033#endif
1034 }
1035 if (sentinal != (char **) NULL)
1036 *sentinal=q;
1037 return(value);
1038}
1039
1040/*
1041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042% %
1043% %
1044% %
1045% L i s t L o c a l e I n f o %
1046% %
1047% %
1048% %
1049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050%
1051% ListLocaleInfo() lists the locale info to a file.
1052%
1053% The format of the ListLocaleInfo method is:
1054%
1055% MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
1056%
1057% A description of each parameter follows.
1058%
1059% o file: An pointer to a FILE.
1060%
1061% o exception: return any errors or warnings in this structure.
1062%
1063*/
1064MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
1065 ExceptionInfo *exception)
1066{
1067 const char
1068 *path;
1069
1070 const LocaleInfo
1071 **locale_info;
1072
1073 ssize_t
1074 i;
1075
1076 size_t
1077 number_messages;
1078
1079 if (file == (const FILE *) NULL)
1080 file=stdout;
1081 number_messages=0;
1082 locale_info=GetLocaleInfoList("*",&number_messages,exception);
1083 if (locale_info == (const LocaleInfo **) NULL)
1084 return(MagickFalse);
1085 path=(const char *) NULL;
1086 for (i=0; i < (ssize_t) number_messages; i++)
1087 {
1088 if (locale_info[i]->stealth != MagickFalse)
1089 continue;
1090 if ((path == (const char *) NULL) ||
1091 (LocaleCompare(path,locale_info[i]->path) != 0))
1092 {
1093 if (locale_info[i]->path != (char *) NULL)
1094 (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
1095 (void) FormatLocaleFile(file,"Tag/Message\n");
1096 (void) FormatLocaleFile(file,
1097 "-------------------------------------------------"
1098 "------------------------------\n");
1099 }
1100 path=locale_info[i]->path;
1101 (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
1102 if (locale_info[i]->message != (char *) NULL)
1103 (void) FormatLocaleFile(file," %s",locale_info[i]->message);
1104 (void) FormatLocaleFile(file,"\n");
1105 }
1106 (void) fflush(file);
1107 locale_info=(const LocaleInfo **)
1108 RelinquishMagickMemory((void *) locale_info);
1109 return(MagickTrue);
1110}
1111
1112/*
1113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1114% %
1115% %
1116% %
1117+ L o a d L o c a l e C a c h e %
1118% %
1119% %
1120% %
1121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122%
1123% LoadLocaleCache() loads the locale configurations which provides a mapping
1124% between locale attributes and a locale name.
1125%
1126% The format of the LoadLocaleCache method is:
1127%
1128% MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1129% const char *filename,const size_t depth,ExceptionInfo *exception)
1130%
1131% A description of each parameter follows:
1132%
1133% o xml: The locale list in XML format.
1134%
1135% o filename: The locale list filename.
1136%
1137% o depth: depth of <include /> statements.
1138%
1139% o exception: return any errors or warnings in this structure.
1140%
1141*/
1142
1143static void ChopLocaleComponents(char *path,const size_t components)
1144{
1145 char
1146 *p;
1147
1148 ssize_t
1149 count;
1150
1151 if (*path == '\0')
1152 return;
1153 p=path+strlen(path)-1;
1154 if (*p == '/')
1155 *p='\0';
1156 for (count=0; (count < (ssize_t) components) && (p > path); p--)
1157 if (*p == '/')
1158 {
1159 *p='\0';
1160 count++;
1161 }
1162 if (count < (ssize_t) components)
1163 *path='\0';
1164}
1165
1166static void LocaleFatalErrorHandler(const ExceptionType severity,
1167 const char *reason,const char *description) magick_attribute((__noreturn__));
1168
1169static void LocaleFatalErrorHandler(
1170 const ExceptionType magick_unused(severity),
1171 const char *reason,const char *description)
1172{
1173 magick_unreferenced(severity);
1174
1175 (void) FormatLocaleFile(stderr,"%s:",GetClientName());
1176 if (reason != (char *) NULL)
1177 (void) FormatLocaleFile(stderr," %s",reason);
1178 if (description != (char *) NULL)
1179 (void) FormatLocaleFile(stderr," (%s)",description);
1180 (void) FormatLocaleFile(stderr,".\n");
1181 (void) fflush(stderr);
1182 exit(1);
1183}
1184
1185static MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1186 const char *filename,const char *locale,const size_t depth,
1187 ExceptionInfo *exception)
1188{
1189 char
1190 keyword[MaxTextExtent],
1191 message[MaxTextExtent],
1192 tag[MaxTextExtent],
1193 *token;
1194
1195 const char
1196 *q;
1197
1198 FatalErrorHandler
1199 fatal_handler;
1200
1201 LocaleInfo
1202 *locale_info;
1203
1204 MagickStatusType
1205 status;
1206
1207 char
1208 *p;
1209
1210 size_t
1211 extent;
1212
1213 /*
1214 Read the locale configure file.
1215 */
1216 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1217 "Loading locale configure file \"%s\" ...",filename);
1218 if (xml == (const char *) NULL)
1219 return(MagickFalse);
1220 status=MagickTrue;
1221 locale_info=(LocaleInfo *) NULL;
1222 *tag='\0';
1223 *message='\0';
1224 *keyword='\0';
1225 fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
1226 token=AcquireString(xml);
1227 extent=strlen(token)+MaxTextExtent;
1228 for (q=(char *) xml; *q != '\0'; )
1229 {
1230 /*
1231 Interpret XML.
1232 */
1233 (void) GetNextToken(q,&q,extent,token);
1234 if (*token == '\0')
1235 break;
1236 (void) CopyMagickString(keyword,token,MaxTextExtent);
1237 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1238 {
1239 /*
1240 Doctype element.
1241 */
1242 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1243 {
1244 (void) GetNextToken(q,&q,extent,token);
1245 while (isspace((int) ((unsigned char) *q)) != 0)
1246 q++;
1247 }
1248 continue;
1249 }
1250 if (LocaleNCompare(keyword,"<!--",4) == 0)
1251 {
1252 /*
1253 Comment element.
1254 */
1255 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1256 {
1257 (void) GetNextToken(q,&q,extent,token);
1258 while (isspace((int) ((unsigned char) *q)) != 0)
1259 q++;
1260 }
1261 continue;
1262 }
1263 if (LocaleCompare(keyword,"<include") == 0)
1264 {
1265 /*
1266 Include element.
1267 */
1268 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1269 {
1270 (void) CopyMagickString(keyword,token,MaxTextExtent);
1271 (void) GetNextToken(q,&q,extent,token);
1272 if (*token != '=')
1273 continue;
1274 (void) GetNextToken(q,&q,extent,token);
1275 if (LocaleCompare(keyword,"locale") == 0)
1276 {
1277 if (LocaleCompare(locale,token) != 0)
1278 break;
1279 continue;
1280 }
1281 if (LocaleCompare(keyword,"file") == 0)
1282 {
1283 if (depth > MagickMaxRecursionDepth)
1284 (void) ThrowMagickException(exception,GetMagickModule(),
1285 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1286 else
1287 {
1288 char
1289 path[MaxTextExtent],
1290 *xml;
1291
1292 *path='\0';
1293 GetPathComponent(filename,HeadPath,path);
1294 if (*path != '\0')
1295 (void) ConcatenateMagickString(path,DirectorySeparator,
1296 MaxTextExtent);
1297 if (*token == *DirectorySeparator)
1298 (void) CopyMagickString(path,token,MaxTextExtent);
1299 else
1300 (void) ConcatenateMagickString(path,token,MaxTextExtent);
1301 xml=FileToXML(path,~0UL);
1302 if (xml != (char *) NULL)
1303 {
1304 status&=LoadLocaleCache(cache,xml,path,locale,
1305 depth+1,exception);
1306 xml=(char *) RelinquishMagickMemory(xml);
1307 }
1308 }
1309 }
1310 }
1311 continue;
1312 }
1313 if (LocaleCompare(keyword,"<locale") == 0)
1314 {
1315 /*
1316 Locale element.
1317 */
1318 while ((*token != '>') && (*q != '\0'))
1319 {
1320 (void) CopyMagickString(keyword,token,MaxTextExtent);
1321 (void) GetNextToken(q,&q,extent,token);
1322 if (*token != '=')
1323 continue;
1324 (void) GetNextToken(q,&q,extent,token);
1325 }
1326 continue;
1327 }
1328 if (LocaleCompare(keyword,"</locale>") == 0)
1329 {
1330 ChopLocaleComponents(tag,1);
1331 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1332 continue;
1333 }
1334 if (LocaleCompare(keyword,"<localemap>") == 0)
1335 continue;
1336 if (LocaleCompare(keyword,"</localemap>") == 0)
1337 continue;
1338 if (LocaleCompare(keyword,"<message") == 0)
1339 {
1340 /*
1341 Message element.
1342 */
1343 while ((*token != '>') && (*q != '\0'))
1344 {
1345 (void) CopyMagickString(keyword,token,MaxTextExtent);
1346 (void) GetNextToken(q,&q,extent,token);
1347 if (*token != '=')
1348 continue;
1349 (void) GetNextToken(q,&q,extent,token);
1350 if (LocaleCompare(keyword,"name") == 0)
1351 {
1352 (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1353 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1354 }
1355 }
1356 for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1357 while (isspace((int) ((unsigned char) *p)) != 0)
1358 p++;
1359 q--;
1360 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1361 q--;
1362 (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2),
1363 MaxTextExtent));
1364 locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
1365 if (locale_info == (LocaleInfo *) NULL)
1366 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1367 (void) memset(locale_info,0,sizeof(*locale_info));
1368 locale_info->path=ConstantString(filename);
1369 locale_info->tag=ConstantString(tag);
1370 locale_info->message=ConstantString(message);
1371 locale_info->signature=MagickCoreSignature;
1372 status=AddValueToSplayTree(cache,locale_info->tag,locale_info);
1373 if (status == MagickFalse)
1374 (void) ThrowMagickException(exception,GetMagickModule(),
1375 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1376 locale_info->tag);
1377 (void) ConcatenateMagickString(tag,message,MaxTextExtent);
1378 (void) ConcatenateMagickString(tag,"\n",MaxTextExtent);
1379 q++;
1380 continue;
1381 }
1382 if (LocaleCompare(keyword,"</message>") == 0)
1383 {
1384 ChopLocaleComponents(tag,2);
1385 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1386 continue;
1387 }
1388 if (*keyword == '<')
1389 {
1390 /*
1391 Subpath element.
1392 */
1393 if (*(keyword+1) == '?')
1394 continue;
1395 if (*(keyword+1) == '/')
1396 {
1397 ChopLocaleComponents(tag,1);
1398 if (*tag != '\0')
1399 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1400 continue;
1401 }
1402 token[strlen(token)-1]='\0';
1403 (void) CopyMagickString(token,token+1,MaxTextExtent);
1404 (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1405 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1406 continue;
1407 }
1408 (void) GetNextToken(q,(const char **) NULL,extent,token);
1409 if (*token != '=')
1410 continue;
1411 }
1412 token=(char *) RelinquishMagickMemory(token);
1413 (void) SetFatalErrorHandler(fatal_handler);
1414 return(status != 0 ? MagickTrue : MagickFalse);
1415}
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419% %
1420% %
1421% %
1422% L o c a l e C o m p a r e %
1423% %
1424% %
1425% %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
1428% LocaleCompare() performs a case-insensitive comparison of two strings
1429% byte-by-byte, according to the ordering of the current locale encoding.
1430% LocaleCompare returns an integer greater than, equal to, or less than 0,
1431% if the string pointed to by p is greater than, equal to, or less than the
1432% string pointed to by q respectively. The sign of a non-zero return value
1433% is determined by the sign of the difference between the values of the first
1434% pair of bytes that differ in the strings being compared.
1435%
1436% The format of the LocaleCompare method is:
1437%
1438% int LocaleCompare(const char *p,const char *q)
1439%
1440% A description of each parameter follows:
1441%
1442% o p: A pointer to a character string.
1443%
1444% o q: A pointer to a character string to compare to p.
1445%
1446*/
1447MagickExport int LocaleCompare(const char *p,const char *q)
1448{
1449 if (p == (char *) NULL)
1450 {
1451 if (q == (char *) NULL)
1452 return(0);
1453 return(-1);
1454 }
1455 if (q == (char *) NULL)
1456 return(1);
1457#if defined(MAGICKCORE_HAVE_STRCASECMP)
1458 return(strcasecmp(p,q));
1459#else
1460 {
1461 int
1462 c,
1463 d;
1464
1465 for ( ; ; )
1466 {
1467 c=(int) *((unsigned char *) p);
1468 d=(int) *((unsigned char *) q);
1469 if ((c == 0) || (AsciiMap[c] != AsciiMap[d]))
1470 break;
1471 p++;
1472 q++;
1473 }
1474 return(AsciiMap[c]-(int) AsciiMap[d]);
1475 }
1476#endif
1477}
1478
1479/*
1480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481% %
1482% %
1483% %
1484% L o c a l e L o w e r %
1485% %
1486% %
1487% %
1488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489%
1490% LocaleLower() transforms all of the characters in the supplied
1491% null-terminated string, changing all uppercase letters to lowercase.
1492%
1493% The format of the LocaleLower method is:
1494%
1495% void LocaleLower(char *string)
1496%
1497% A description of each parameter follows:
1498%
1499% o string: A pointer to the string to convert to lower-case Locale.
1500%
1501*/
1502MagickExport void LocaleLower(char *string)
1503{
1504 char
1505 *q;
1506
1507 assert(string != (char *) NULL);
1508 for (q=string; *q != '\0'; q++)
1509 *q=(char) LocaleToLowercase((int) *q);
1510}
1511
1512/*
1513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1514% %
1515% %
1516% %
1517% L o c a l e L o w e r c a s e %
1518% %
1519% %
1520% %
1521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522%
1523% LocaleLowercase() converts the character to lowercase.
1524%
1525% The format of the LocaleLowercase method is:
1526%
1527% int LocaleLowercase(const int c)
1528%
1529% A description of each parameter follows:
1530%
1531% o If c is a uppercase letter, return its lowercase equivalent.
1532%
1533*/
1534MagickExport int LocaleLowercase(const int c)
1535{
1536 return(LocaleToLowercase(c));
1537}
1538
1539/*
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541% %
1542% %
1543% %
1544% L o c a l e N C o m p a r e %
1545% %
1546% %
1547% %
1548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549%
1550% LocaleNCompare() performs a case-insensitive comparison of two strings
1551% byte-by-byte, according to the ordering of the current locale encoding.
1552%
1553% LocaleNCompare returns an integer greater than, equal to, or less than 0,
1554% if the string pointed to by p is greater than, equal to, or less than the
1555% string pointed to by q respectively. The sign of a non-zero return value
1556% is determined by the sign of the difference between the values of the first
1557% pair of bytes that differ in the strings being compared.
1558%
1559% The LocaleNCompare method makes the same comparison as LocaleCompare but
1560% looks at a maximum of n bytes. Bytes following a null byte are not
1561% compared.
1562%
1563% The format of the LocaleNCompare method is:
1564%
1565% int LocaleNCompare(const char *p,const char *q,const size_t n)
1566%
1567% A description of each parameter follows:
1568%
1569% o p: A pointer to a character string.
1570%
1571% o q: A pointer to a character string to compare to p.
1572%
1573% o length: the number of characters to compare in strings p and q.
1574%
1575*/
1576MagickExport int LocaleNCompare(const char *p,const char *q,const size_t length)
1577{
1578 if (p == (char *) NULL)
1579 {
1580 if (q == (char *) NULL)
1581 return(0);
1582 return(-1);
1583 }
1584 if (q == (char *) NULL)
1585 return(1);
1586#if defined(MAGICKCORE_HAVE_STRNCASECMP)
1587 return(strncasecmp(p,q,length));
1588#else
1589 {
1590 int
1591 c,
1592 d;
1593
1594 size_t
1595 i;
1596
1597 for (i=length; i != 0; i--)
1598 {
1599 c=(int) *((unsigned char *) p);
1600 d=(int) *((unsigned char *) q);
1601 if (AsciiMap[c] != AsciiMap[d])
1602 return(AsciiMap[c]-(int) AsciiMap[d]);
1603 if (c == 0)
1604 return(0);
1605 p++;
1606 q++;
1607 }
1608 return(0);
1609 }
1610#endif
1611}
1612
1613/*
1614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615% %
1616% %
1617% %
1618% L o c a l e U p p e r %
1619% %
1620% %
1621% %
1622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623%
1624% LocaleUpper() transforms all of the characters in the supplied
1625% null-terminated string, changing all lowercase letters to uppercase.
1626%
1627% The format of the LocaleUpper method is:
1628%
1629% void LocaleUpper(char *string)
1630%
1631% A description of each parameter follows:
1632%
1633% o string: A pointer to the string to convert to upper-case Locale.
1634%
1635*/
1636MagickExport void LocaleUpper(char *string)
1637{
1638 char
1639 *q;
1640
1641 assert(string != (char *) NULL);
1642 for (q=string; *q != '\0'; q++)
1643 *q=(char) LocaleToUppercase((int) *q);
1644}
1645
1646/*
1647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1648% %
1649% %
1650% %
1651% L o c a l e U p p e r c a s e %
1652% %
1653% %
1654% %
1655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1656%
1657% LocaleUppercase() converts the character to uppercase.
1658%
1659% The format of the LocaleUppercase method is:
1660%
1661% int LocaleUppercase(const int c)
1662%
1663% A description of each parameter follows:
1664%
1665% o If c is a lowercase letter, return its uppercase equivalent.
1666%
1667*/
1668MagickExport int LocaleUppercase(const int c)
1669{
1670 return(LocaleToUppercase(c));
1671}
1672
1673/*
1674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675% %
1676% %
1677% %
1678+ L o c a l e C o m p o n e n t G e n e s i s %
1679% %
1680% %
1681% %
1682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683%
1684% LocaleComponentGenesis() instantiates the locale component.
1685%
1686% The format of the LocaleComponentGenesis method is:
1687%
1688% MagickBooleanType LocaleComponentGenesis(void)
1689%
1690*/
1691MagickExport MagickBooleanType LocaleComponentGenesis(void)
1692{
1693 if (locale_semaphore == (SemaphoreInfo *) NULL)
1694 locale_semaphore=AllocateSemaphoreInfo();
1695#if defined(MAGICKCORE_LOCALE_SUPPORT)
1696 (void) AcquireCLocale();
1697#endif
1698 return(MagickTrue);
1699}
1700
1701/*
1702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703% %
1704% %
1705% %
1706+ L o c a l e C o m p o n e n t T e r m i n u s %
1707% %
1708% %
1709% %
1710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1711%
1712% LocaleComponentTerminus() destroys the locale component.
1713%
1714% The format of the LocaleComponentTerminus method is:
1715%
1716% LocaleComponentTerminus(void)
1717%
1718*/
1719MagickExport void LocaleComponentTerminus(void)
1720{
1721 if (locale_semaphore == (SemaphoreInfo *) NULL)
1722 ActivateSemaphoreInfo(&locale_semaphore);
1723 LockSemaphoreInfo(locale_semaphore);
1724 if (locale_cache != (SplayTreeInfo *) NULL)
1725 locale_cache=DestroySplayTree(locale_cache);
1726#if defined(MAGICKCORE_LOCALE_SUPPORT)
1727 DestroyCLocale();
1728#endif
1729 UnlockSemaphoreInfo(locale_semaphore);
1730 DestroySemaphoreInfo(&locale_semaphore);
1731}