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