MagickCore  6.9.13-51
Convert, Edit, Or Compose Bitmap Images
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 */
81 static 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)
97 static 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 
125 static SemaphoreInfo
126  *locale_semaphore = (SemaphoreInfo *) NULL;
127 
128 static SplayTreeInfo
129  *locale_cache = (SplayTreeInfo *) NULL;
130 
131 #if defined(MAGICKCORE_LOCALE_SUPPORT)
132 static volatile locale_t
133  c_locale = (locale_t) NULL;
134 #endif
135 ␌
136 /*
137  Forward declarations.
138 */
139 static 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 */
164 static 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 
206 static 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 
221 static SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
222  const char *locale,ExceptionInfo *exception)
223 {
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 
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 */
286 static 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 
322 static void *DestroyOptions(void *message)
323 {
324  return(DestroyStringInfo((StringInfo *) message));
325 }
326 
327 MagickExport 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 
362 MagickExport 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 
407 MagickExport 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 
453 MagickExport 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 
498 MagickExport 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 */
539 MagickExport 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)
592 extern "C" {
593 #endif
594 
595 static 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 
612 MagickExport 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)
690 extern "C" {
691 #endif
692 
693 static 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 
708 MagickExport 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 */
774 MagickExport const char *GetLocaleMessage(const char *tag)
775 {
776  char
777  name[MaxTextExtent];
778 
779  const LocaleInfo
780  *locale_info;
781 
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 */
822 MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
823  ExceptionInfo *exception)
824 {
825  char
826  path[MaxTextExtent];
827 
828  const char
829  *element;
830 
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 */
907 MagickExport 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 */
939 static 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 */
1005 MagickExport 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 */
1064 MagickExport 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 
1143 static 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 
1166 static void LocaleFatalErrorHandler(const ExceptionType severity,
1167  const char *reason,const char *description) magick_attribute((__noreturn__));
1168 
1169 static 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 
1185 static 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 */
1447 MagickExport 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 */
1502 MagickExport 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 */
1534 MagickExport 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 */
1576 MagickExport 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 */
1636 MagickExport 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 */
1668 MagickExport 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 */
1691 MagickExport 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 */
1719 MagickExport 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 }