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