MagickCore  7.0.3
locale.c
Go to the documentation of this file.
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-2019 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 "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/configure.h"
46 #include "MagickCore/exception.h"
49 #include "MagickCore/linked-list.h"
50 #include "MagickCore/locale_.h"
52 #include "MagickCore/log.h"
53 #include "MagickCore/memory_.h"
56 #include "MagickCore/semaphore.h"
57 #include "MagickCore/splay-tree.h"
58 #include "MagickCore/string_.h"
60 #include "MagickCore/token.h"
61 #include "MagickCore/utility.h"
63 #include "MagickCore/xml-tree.h"
65 
66 /*
67  Define declarations.
68 */
69 #if (defined(MAGICKCORE_HAVE_NEWLOCALE) || defined(MAGICKCORE_WINDOWS_SUPPORT)) && !defined(__MINGW32__)
70 # define MAGICKCORE_LOCALE_SUPPORT
71 #endif
72 #define LocaleFilename "locale.xml"
73 
74 /*
75  Static declarations.
76 */
77 static const char
79  "<?xml version=\"1.0\"?>"
80  "<localemap>"
81  " <locale name=\"C\">"
82  " <Exception>"
83  " <Message name=\"\">"
84  " </Message>"
85  " </Exception>"
86  " </locale>"
87  "</localemap>";
88 
89 #ifdef __VMS
90 #define asciimap AsciiMap
91 #endif
92 #if !defined(MAGICKCORE_HAVE_STRCASECMP) || !defined(MAGICKCORE_HAVE_STRNCASECMP)
93 static const unsigned char
95  {
96  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
97  0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
98  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
99  0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
100  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
101  0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
102  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
103  0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
104  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
105  0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
106  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
107  0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
108  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
109  0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
110  0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
111  0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
112  0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xc5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
113  0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
114  0xf8, 0xf9, 0xfa, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
115  0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
116  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
117  0xfc, 0xfd, 0xfe, 0xff,
118  };
119 #endif
120 
121 static SemaphoreInfo
123 
124 static SplayTreeInfo
126 
127 #if defined(MAGICKCORE_LOCALE_SUPPORT)
128 static volatile locale_t
129  c_locale = (locale_t) NULL;
130 #endif
131 
132 /*
133  Forward declarations.
134 */
135 static MagickBooleanType
137  LoadLocaleCache(SplayTreeInfo *,const char *,const char *,const char *,
138  const size_t,ExceptionInfo *);
139 
140 #if defined(MAGICKCORE_LOCALE_SUPPORT)
141 /*
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 % %
144 % %
145 % %
146 + A c q u i r e C L o c a l e %
147 % %
148 % %
149 % %
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151 %
152 % AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
153 % errno set if it cannot be acquired.
154 %
155 % The format of the AcquireCLocale method is:
156 %
157 % locale_t AcquireCLocale(void)
158 %
159 */
160 static locale_t AcquireCLocale(void)
161 {
162 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
163  if (c_locale == (locale_t) NULL)
164  c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
165 #elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
166  if (c_locale == (locale_t) NULL)
167  c_locale=_create_locale(LC_ALL,"C");
168 #endif
169  return(c_locale);
170 }
171 #endif
172 
173 /*
174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
175 % %
176 % %
177 % %
178 % A c q u i r e L o c a l e S p l a y T r e e %
179 % %
180 % %
181 % %
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
183 %
184 % AcquireLocaleSplayTree() caches one or more locale configurations which
185 % provides a mapping between locale attributes and a locale tag.
186 %
187 % The format of the AcquireLocaleSplayTree method is:
188 %
189 % SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
190 % ExceptionInfo *exception)
191 %
192 % A description of each parameter follows:
193 %
194 % o filename: the font file tag.
195 %
196 % o locale: the actual locale.
197 %
198 % o exception: return any errors or warnings in this structure.
199 %
200 */
201 
202 static void *DestroyLocaleNode(void *locale_info)
203 {
204  register LocaleInfo
205  *p;
206 
207  p=(LocaleInfo *) locale_info;
208  if (p->path != (char *) NULL)
209  p->path=DestroyString(p->path);
210  if (p->tag != (char *) NULL)
211  p->tag=DestroyString(p->tag);
212  if (p->message != (char *) NULL)
214  return(RelinquishMagickMemory(p));
215 }
216 
217 static SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
218  const char *locale,ExceptionInfo *exception)
219 {
221  status;
222 
224  *cache;
225 
226  cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
228  status=MagickTrue;
229 #if !defined(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 *)
242  GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
243  exception);
244  option=(const StringInfo *) GetNextValueInLinkedList(options);
245  }
246  options=DestroyLocaleOptions(options);
247  if (GetNumberOfNodesInSplayTree(cache) == 0)
248  {
249  options=GetLocaleOptions("english.xml",exception);
250  option=(const StringInfo *) GetNextValueInLinkedList(options);
251  while (option != (const StringInfo *) NULL)
252  {
253  status&=LoadLocaleCache(cache,(const char *)
254  GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
255  exception);
256  option=(const StringInfo *) GetNextValueInLinkedList(options);
257  }
258  options=DestroyLocaleOptions(options);
259  }
260  }
261 #endif
262  if (GetNumberOfNodesInSplayTree(cache) == 0)
263  status&=LoadLocaleCache(cache,LocaleMap,"built-in",locale,0,
264  exception);
265  return(cache);
266 }
267 
268 #if defined(MAGICKCORE_LOCALE_SUPPORT)
269 /*
270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271 % %
272 % %
273 % %
274 + D e s t r o y C L o c a l e %
275 % %
276 % %
277 % %
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 %
280 % DestroyCLocale() releases the resources allocated for a locale object
281 % returned by a call to the AcquireCLocale() method.
282 %
283 % The format of the DestroyCLocale method is:
284 %
285 % void DestroyCLocale(void)
286 %
287 */
288 static void DestroyCLocale(void)
289 {
290  if (c_locale != (locale_t) NULL)
291  freelocale(c_locale);
292  c_locale=(locale_t) NULL;
293 }
294 #endif
295 
296 /*
297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298 % %
299 % %
300 % %
301 % D e s t r o y L o c a l e O p t i o n s %
302 % %
303 % %
304 % %
305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306 %
307 % DestroyLocaleOptions() releases memory associated with an locale
308 % messages.
309 %
310 % The format of the DestroyProfiles method is:
311 %
312 % LinkedListInfo *DestroyLocaleOptions(Image *image)
313 %
314 % A description of each parameter follows:
315 %
316 % o image: the image.
317 %
318 */
319 
320 static void *DestroyOptions(void *message)
321 {
322  return(DestroyStringInfo((StringInfo *) message));
323 }
324 
326 {
327  assert(messages != (LinkedListInfo *) NULL);
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 
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 
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 
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);
550  if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
551  {
553  locale_info=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
555  return(locale_info);
556  }
557  locale_info=(const LocaleInfo *) GetValueFromSplayTree(locale_cache,tag);
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  register const LocaleInfo
620  *p;
621 
622  register ssize_t
623  i;
624 
625  /*
626  Allocate locale list.
627  */
628  assert(pattern != (char *) NULL);
629  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
630  assert(number_messages != (size_t *) NULL);
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  */
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;
651  }
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  register 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,size_t *number_messages,
709  ExceptionInfo *exception)
710 {
711  char
712  **messages;
713 
714  register const LocaleInfo
715  *p;
716 
717  register ssize_t
718  i;
719 
720  /*
721  Allocate locale list.
722  */
723  assert(pattern != (char *) NULL);
724  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
725  assert(number_messages != (size_t *) NULL);
726  *number_messages=0;
727  p=GetLocaleInfo_("*",exception);
728  if (p == (const LocaleInfo *) NULL)
729  return((char **) NULL);
730  messages=(char **) AcquireQuantumMemory((size_t)
731  GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
732  if (messages == (char **) NULL)
733  return((char **) NULL);
736  for (i=0; p != (const LocaleInfo *) NULL; )
737  {
738  if ((p->stealth == MagickFalse) &&
739  (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
740  messages[i++]=ConstantString(p->tag);
742  }
744  qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
745  messages[i]=(char *) NULL;
746  *number_messages=(size_t) i;
747  return(messages);
748 }
749 
750 /*
751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
752 % %
753 % %
754 % %
755 % G e t L o c a l e M e s s a g e %
756 % %
757 % %
758 % %
759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760 %
761 % GetLocaleMessage() returns a message in the current locale that matches the
762 % supplied tag.
763 %
764 % The format of the GetLocaleMessage method is:
765 %
766 % const char *GetLocaleMessage(const char *tag)
767 %
768 % A description of each parameter follows:
769 %
770 % o tag: Return a message that matches this tag in the current locale.
771 %
772 */
773 MagickExport const char *GetLocaleMessage(const char *tag)
774 {
775  char
776  name[MagickLocaleExtent];
777 
778  const LocaleInfo
779  *locale_info;
780 
782  *exception;
783 
784  if ((tag == (const char *) NULL) || (*tag == '\0'))
785  return(tag);
786  exception=AcquireExceptionInfo();
787  (void) FormatLocaleString(name,MagickLocaleExtent,"%s/",tag);
788  locale_info=GetLocaleInfo_(name,exception);
789  exception=DestroyExceptionInfo(exception);
790  if (locale_info != (const LocaleInfo *) NULL)
791  return(locale_info->message);
792  return(tag);
793 }
794 
795 /*
796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797 % %
798 % %
799 % %
800 % G e t L o c a l e O p t i o n s %
801 % %
802 % %
803 % %
804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
805 %
806 % GetLocaleOptions() returns any Magick configuration messages associated
807 % with the specified filename.
808 %
809 % The format of the GetLocaleOptions method is:
810 %
811 % LinkedListInfo *GetLocaleOptions(const char *filename,
812 % ExceptionInfo *exception)
813 %
814 % A description of each parameter follows:
815 %
816 % o filename: the locale file tag.
817 %
818 % o exception: return any errors or warnings in this structure.
819 %
820 */
822  ExceptionInfo *exception)
823 {
824  char
825  path[MagickPathExtent];
826 
827  const char
828  *element;
829 
831  *messages,
832  *paths;
833 
834  StringInfo
835  *xml;
836 
837  assert(filename != (const char *) NULL);
838  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
839  assert(exception != (ExceptionInfo *) NULL);
840  (void) CopyMagickString(path,filename,MagickPathExtent);
841  /*
842  Load XML from configuration files to linked-list.
843  */
844  messages=NewLinkedList(0);
845  paths=GetConfigurePaths(filename,exception);
846  if (paths != (LinkedListInfo *) NULL)
847  {
849  element=(const char *) GetNextValueInLinkedList(paths);
850  while (element != (const char *) NULL)
851  {
852  (void) FormatLocaleString(path,MagickPathExtent,"%s%s",element,
853  filename);
855  "Searching for locale file: \"%s\"",path);
856  xml=ConfigureFileToStringInfo(path);
857  if (xml != (StringInfo *) NULL)
858  (void) AppendValueToLinkedList(messages,xml);
859  element=(const char *) GetNextValueInLinkedList(paths);
860  }
862  }
863 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
864  {
865  char
866  *blob;
867 
868  blob=(char *) NTResourceToBlob(filename);
869  if (blob != (char *) NULL)
870  {
871  xml=AcquireStringInfo(0);
872  SetStringInfoLength(xml,strlen(blob)+1);
873  SetStringInfoDatum(xml,(const unsigned char *) blob);
874  blob=(char *) RelinquishMagickMemory(blob);
875  SetStringInfoPath(xml,filename);
876  (void) AppendValueToLinkedList(messages,xml);
877  }
878  }
879 #endif
880  ResetLinkedListIterator(messages);
881  return(messages);
882 }
883 
884 /*
885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
886 % %
887 % %
888 % %
889 % G e t L o c a l e V a l u e %
890 % %
891 % %
892 % %
893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
894 %
895 % GetLocaleValue() returns the message associated with the locale info.
896 %
897 % The format of the GetLocaleValue method is:
898 %
899 % const char *GetLocaleValue(const LocaleInfo *locale_info)
900 %
901 % A description of each parameter follows:
902 %
903 % o locale_info: The locale info.
904 %
905 */
906 MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
907 {
908  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
909  assert(locale_info != (LocaleInfo *) NULL);
910  assert(locale_info->signature == MagickCoreSignature);
911  return(locale_info->message);
912 }
913 
914 /*
915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916 % %
917 % %
918 % %
919 + I s L o c a l e T r e e I n s t a n t i a t e d %
920 % %
921 % %
922 % %
923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924 %
925 % IsLocaleTreeInstantiated() determines if the locale tree is instantiated.
926 % If not, it instantiates the tree and returns it.
927 %
928 % The format of the IsLocaleInstantiated method is:
929 %
930 % MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
931 %
932 % A description of each parameter follows.
933 %
934 % o exception: return any errors or warnings in this structure.
935 %
936 */
938 {
939  if (locale_cache == (SplayTreeInfo *) NULL)
940  {
941  if (locale_semaphore == (SemaphoreInfo *) NULL)
944  if (locale_cache == (SplayTreeInfo *) NULL)
945  {
946  char
947  *locale;
948 
949  register const char
950  *p;
951 
952  locale=(char *) NULL;
953  p=setlocale(LC_CTYPE,(const char *) NULL);
954  if (p != (const char *) NULL)
955  locale=ConstantString(p);
956  if (locale == (char *) NULL)
957  locale=GetEnvironmentValue("LC_ALL");
958  if (locale == (char *) NULL)
959  locale=GetEnvironmentValue("LC_MESSAGES");
960  if (locale == (char *) NULL)
961  locale=GetEnvironmentValue("LC_CTYPE");
962  if (locale == (char *) NULL)
963  locale=GetEnvironmentValue("LANG");
964  if (locale == (char *) NULL)
965  locale=ConstantString("C");
967  locale=DestroyString(locale);
968  }
970  }
971  return(locale_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
972 }
973 
974 /*
975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976 % %
977 % %
978 % %
979 + I n t e r p r e t L o c a l e V a l u e %
980 % %
981 % %
982 % %
983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 %
985 % InterpretLocaleValue() interprets the string as a floating point number in
986 % the "C" locale and returns its value as a double. If sentinal is not a null
987 % pointer, the method also sets the value pointed by sentinal to point to the
988 % first character after the number.
989 %
990 % The format of the InterpretLocaleValue method is:
991 %
992 % double InterpretLocaleValue(const char *value,char **sentinal)
993 %
994 % A description of each parameter follows:
995 %
996 % o value: the string value.
997 %
998 % o sentinal: if sentinal is not NULL, a pointer to the character after the
999 % last character used in the conversion is stored in the location
1000 % referenced by sentinal.
1001 %
1002 */
1004  char **magick_restrict sentinal)
1005 {
1006  char
1007  *q;
1008 
1009  double
1010  value;
1011 
1012  if ((*string == '0') && ((string[1] | 0x20)=='x'))
1013  value=(double) strtoul(string,&q,16);
1014  else
1015  {
1016 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_STRTOD_L)
1017  locale_t
1018  locale;
1019 
1020  locale=AcquireCLocale();
1021  if (locale == (locale_t) NULL)
1022  value=strtod(string,&q);
1023  else
1024  value=strtod_l(string,&q,locale);
1025 #else
1026  value=strtod(string,&q);
1027 #endif
1028  }
1029  if (sentinal != (char **) NULL)
1030  *sentinal=q;
1031  return(value);
1032 }
1033 
1034 /*
1035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036 % %
1037 % %
1038 % %
1039 % L i s t L o c a l e I n f o %
1040 % %
1041 % %
1042 % %
1043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 %
1045 % ListLocaleInfo() lists the locale info to a file.
1046 %
1047 % The format of the ListLocaleInfo method is:
1048 %
1049 % MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
1050 %
1051 % A description of each parameter follows.
1052 %
1053 % o file: An pointer to a FILE.
1054 %
1055 % o exception: return any errors or warnings in this structure.
1056 %
1057 */
1059  ExceptionInfo *exception)
1060 {
1061  const char
1062  *path;
1063 
1064  const LocaleInfo
1065  **locale_info;
1066 
1067  register ssize_t
1068  i;
1069 
1070  size_t
1071  number_messages;
1072 
1073  if (file == (const FILE *) NULL)
1074  file=stdout;
1075  number_messages=0;
1076  locale_info=GetLocaleInfoList("*",&number_messages,exception);
1077  if (locale_info == (const LocaleInfo **) NULL)
1078  return(MagickFalse);
1079  path=(const char *) NULL;
1080  for (i=0; i < (ssize_t) number_messages; i++)
1081  {
1082  if (locale_info[i]->stealth != MagickFalse)
1083  continue;
1084  if ((path == (const char *) NULL) ||
1085  (LocaleCompare(path,locale_info[i]->path) != 0))
1086  {
1087  if (locale_info[i]->path != (char *) NULL)
1088  (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
1089  (void) FormatLocaleFile(file,"Tag/Message\n");
1090  (void) FormatLocaleFile(file,
1091  "-------------------------------------------------"
1092  "------------------------------\n");
1093  }
1094  path=locale_info[i]->path;
1095  (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
1096  if (locale_info[i]->message != (char *) NULL)
1097  (void) FormatLocaleFile(file," %s",locale_info[i]->message);
1098  (void) FormatLocaleFile(file,"\n");
1099  }
1100  (void) fflush(file);
1101  locale_info=(const LocaleInfo **)
1102  RelinquishMagickMemory((void *) locale_info);
1103  return(MagickTrue);
1104 }
1105 
1106 /*
1107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1108 % %
1109 % %
1110 % %
1111 + L o a d L o c a l e C a c h e %
1112 % %
1113 % %
1114 % %
1115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 %
1117 % LoadLocaleCache() loads the locale configurations which provides a mapping
1118 % between locale attributes and a locale name.
1119 %
1120 % The format of the LoadLocaleCache method is:
1121 %
1122 % MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1123 % const char *filename,const size_t depth,ExceptionInfo *exception)
1124 %
1125 % A description of each parameter follows:
1126 %
1127 % o xml: The locale list in XML format.
1128 %
1129 % o filename: The locale list filename.
1130 %
1131 % o depth: depth of <include /> statements.
1132 %
1133 % o exception: return any errors or warnings in this structure.
1134 %
1135 */
1136 
1137 static void ChopLocaleComponents(char *path,const size_t components)
1138 {
1139  register char
1140  *p;
1141 
1142  ssize_t
1143  count;
1144 
1145  if (*path == '\0')
1146  return;
1147  p=path+strlen(path)-1;
1148  if (*p == '/')
1149  *p='\0';
1150  for (count=0; (count < (ssize_t) components) && (p > path); p--)
1151  if (*p == '/')
1152  {
1153  *p='\0';
1154  count++;
1155  }
1156  if (count < (ssize_t) components)
1157  *path='\0';
1158 }
1159 
1161  const ExceptionType magick_unused(severity),
1162  const char *reason,const char *description)
1163 {
1164  magick_unreferenced(severity);
1165 
1166  if (reason == (char *) NULL)
1167  return;
1168  (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
1169  if (description != (char *) NULL)
1170  (void) FormatLocaleFile(stderr," (%s)",description);
1171  (void) FormatLocaleFile(stderr,".\n");
1172  (void) fflush(stderr);
1173  exit(1);
1174 }
1175 
1176 static MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1177  const char *filename,const char *locale,const size_t depth,ExceptionInfo *exception)
1178 {
1179  char
1180  keyword[MagickLocaleExtent],
1181  message[MagickLocaleExtent],
1182  tag[MagickLocaleExtent],
1183  *token;
1184 
1185  const char
1186  *q;
1187 
1189  fatal_handler;
1190 
1191  LocaleInfo
1192  *locale_info;
1193 
1195  status;
1196 
1197  register char
1198  *p;
1199 
1200  size_t
1201  extent;
1202 
1203  /*
1204  Read the locale configure file.
1205  */
1207  "Loading locale configure file \"%s\" ...",filename);
1208  if (xml == (const char *) NULL)
1209  return(MagickFalse);
1210  status=MagickTrue;
1211  locale_info=(LocaleInfo *) NULL;
1212  *tag='\0';
1213  *message='\0';
1214  *keyword='\0';
1216  token=AcquireString(xml);
1217  extent=strlen(token)+MagickPathExtent;
1218  for (q=(char *) xml; *q != '\0'; )
1219  {
1220  /*
1221  Interpret XML.
1222  */
1223  (void) GetNextToken(q,&q,extent,token);
1224  if (*token == '\0')
1225  break;
1226  (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1227  if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1228  {
1229  /*
1230  Doctype element.
1231  */
1232  while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1233  {
1234  (void) GetNextToken(q,&q,extent,token);
1235  while (isspace((int) ((unsigned char) *q)) != 0)
1236  q++;
1237  }
1238  continue;
1239  }
1240  if (LocaleNCompare(keyword,"<!--",4) == 0)
1241  {
1242  /*
1243  Comment element.
1244  */
1245  while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1246  {
1247  (void) GetNextToken(q,&q,extent,token);
1248  while (isspace((int) ((unsigned char) *q)) != 0)
1249  q++;
1250  }
1251  continue;
1252  }
1253  if (LocaleCompare(keyword,"<include") == 0)
1254  {
1255  /*
1256  Include element.
1257  */
1258  while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1259  {
1260  (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1261  (void) GetNextToken(q,&q,extent,token);
1262  if (*token != '=')
1263  continue;
1264  (void) GetNextToken(q,&q,extent,token);
1265  if (LocaleCompare(keyword,"locale") == 0)
1266  {
1267  if (LocaleCompare(locale,token) != 0)
1268  break;
1269  continue;
1270  }
1271  if (LocaleCompare(keyword,"file") == 0)
1272  {
1273  if (depth > MagickMaxRecursionDepth)
1274  (void) ThrowMagickException(exception,GetMagickModule(),
1275  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1276  else
1277  {
1278  char
1279  path[MagickPathExtent],
1280  *file_xml;
1281 
1282  *path='\0';
1283  GetPathComponent(filename,HeadPath,path);
1284  if (*path != '\0')
1287  if (*token == *DirectorySeparator)
1288  (void) CopyMagickString(path,token,MagickPathExtent);
1289  else
1290  (void) ConcatenateMagickString(path,token,MagickPathExtent);
1291  file_xml=FileToXML(path,~0UL);
1292  if (file_xml != (char *) NULL)
1293  {
1294  status&=LoadLocaleCache(cache,file_xml,path,locale,
1295  depth+1,exception);
1296  file_xml=DestroyString(file_xml);
1297  }
1298  }
1299  }
1300  }
1301  continue;
1302  }
1303  if (LocaleCompare(keyword,"<locale") == 0)
1304  {
1305  /*
1306  Locale element.
1307  */
1308  while ((*token != '>') && (*q != '\0'))
1309  {
1310  (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1311  (void) GetNextToken(q,&q,extent,token);
1312  if (*token != '=')
1313  continue;
1314  (void) GetNextToken(q,&q,extent,token);
1315  }
1316  continue;
1317  }
1318  if (LocaleCompare(keyword,"</locale>") == 0)
1319  {
1320  ChopLocaleComponents(tag,1);
1322  continue;
1323  }
1324  if (LocaleCompare(keyword,"<localemap>") == 0)
1325  continue;
1326  if (LocaleCompare(keyword,"</localemap>") == 0)
1327  continue;
1328  if (LocaleCompare(keyword,"<message") == 0)
1329  {
1330  /*
1331  Message element.
1332  */
1333  while ((*token != '>') && (*q != '\0'))
1334  {
1335  (void) CopyMagickString(keyword,token,MagickLocaleExtent);
1336  (void) GetNextToken(q,&q,extent,token);
1337  if (*token != '=')
1338  continue;
1339  (void) GetNextToken(q,&q,extent,token);
1340  if (LocaleCompare(keyword,"name") == 0)
1341  {
1342  (void) ConcatenateMagickString(tag,token,MagickLocaleExtent);
1344  }
1345  }
1346  for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1347  while (isspace((int) ((unsigned char) *p)) != 0)
1348  p++;
1349  q--;
1350  while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1351  q--;
1352  (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2),
1354  locale_info=(LocaleInfo *) AcquireCriticalMemory(sizeof(*locale_info));
1355  (void) memset(locale_info,0,sizeof(*locale_info));
1356  locale_info->path=ConstantString(filename);
1357  locale_info->tag=ConstantString(tag);
1358  locale_info->message=ConstantString(message);
1359  locale_info->signature=MagickCoreSignature;
1360  status=AddValueToSplayTree(cache,locale_info->tag,locale_info);
1361  if (status == MagickFalse)
1362  (void) ThrowMagickException(exception,GetMagickModule(),
1363  ResourceLimitError,"MemoryAllocationFailed","`%s'",
1364  locale_info->tag);
1365  (void) ConcatenateMagickString(tag,message,MagickLocaleExtent);
1367  q++;
1368  continue;
1369  }
1370  if (LocaleCompare(keyword,"</message>") == 0)
1371  {
1372  ChopLocaleComponents(tag,2);
1374  continue;
1375  }
1376  if (*keyword == '<')
1377  {
1378  /*
1379  Subpath element.
1380  */
1381  if (*(keyword+1) == '?')
1382  continue;
1383  if (*(keyword+1) == '/')
1384  {
1385  ChopLocaleComponents(tag,1);
1386  if (*tag != '\0')
1388  continue;
1389  }
1390  token[strlen(token)-1]='\0';
1391  (void) CopyMagickString(token,token+1,MagickLocaleExtent);
1392  (void) ConcatenateMagickString(tag,token,MagickLocaleExtent);
1394  continue;
1395  }
1396  (void) GetNextToken(q,(const char **) NULL,extent,token);
1397  if (*token != '=')
1398  continue;
1399  }
1400  token=(char *) RelinquishMagickMemory(token);
1401  (void) SetFatalErrorHandler(fatal_handler);
1402  return(status != 0 ? MagickTrue : MagickFalse);
1403 }
1404 
1405 /*
1406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407 % %
1408 % %
1409 % %
1410 % L o c a l e C o m p a r e %
1411 % %
1412 % %
1413 % %
1414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415 %
1416 % LocaleCompare() performs a case-insensitive comparison of two strings
1417 % byte-by-byte, according to the ordering of the current locale encoding.
1418 % LocaleCompare returns an integer greater than, equal to, or less than 0,
1419 % if the string pointed to by p is greater than, equal to, or less than the
1420 % string pointed to by q respectively. The sign of a non-zero return value
1421 % is determined by the sign of the difference between the values of the first
1422 % pair of bytes that differ in the strings being compared.
1423 %
1424 % The format of the LocaleCompare method is:
1425 %
1426 % int LocaleCompare(const char *p,const char *q)
1427 %
1428 % A description of each parameter follows:
1429 %
1430 % o p: A pointer to a character string.
1431 %
1432 % o q: A pointer to a character string to compare to p.
1433 %
1434 */
1435 MagickExport int LocaleCompare(const char *p,const char *q)
1436 {
1437  if (p == (char *) NULL)
1438  {
1439  if (q == (char *) NULL)
1440  return(0);
1441  return(-1);
1442  }
1443  if (q == (char *) NULL)
1444  return(1);
1445 #if defined(MAGICKCORE_HAVE_STRCASECMP)
1446  return(strcasecmp(p,q));
1447 #else
1448  {
1449  register int
1450  c,
1451  d;
1452 
1453  for ( ; ; )
1454  {
1455  c=(int) *((unsigned char *) p);
1456  d=(int) *((unsigned char *) q);
1457  if ((c == 0) || (AsciiMap[c] != AsciiMap[d]))
1458  break;
1459  p++;
1460  q++;
1461  }
1462  return(AsciiMap[c]-(int) AsciiMap[d]);
1463  }
1464 #endif
1465 }
1466 
1467 /*
1468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1469 % %
1470 % %
1471 % %
1472 % L o c a l e L o w e r %
1473 % %
1474 % %
1475 % %
1476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477 %
1478 % LocaleLower() transforms all of the characters in the supplied
1479 % null-terminated string, changing all uppercase letters to lowercase.
1480 %
1481 % The format of the LocaleLower method is:
1482 %
1483 % void LocaleLower(char *string)
1484 %
1485 % A description of each parameter follows:
1486 %
1487 % o string: A pointer to the string to convert to lower-case Locale.
1488 %
1489 */
1490 MagickExport void LocaleLower(char *string)
1491 {
1492  register char
1493  *q;
1494 
1495  assert(string != (char *) NULL);
1496  for (q=string; *q != '\0'; q++)
1497  *q=(char) LocaleLowercase((int) *q);
1498 }
1499 
1500 /*
1501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502 % %
1503 % %
1504 % %
1505 % L o c a l e L o w e r c a s e %
1506 % %
1507 % %
1508 % %
1509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1510 %
1511 % LocaleLowercase() convert to lowercase.
1512 %
1513 % The format of the LocaleLowercase method is:
1514 %
1515 % void LocaleLowercase(const int c)
1516 %
1517 % A description of each parameter follows:
1518 %
1519 % o If c is a uppercase letter, return its lowercase equivalent.
1520 %
1521 */
1523 {
1524  if (c == EOF)
1525  return(c);
1526 #if defined(MAGICKCORE_LOCALE_SUPPORT)
1527  if (c_locale != (locale_t) NULL)
1528  return(tolower_l((int) ((unsigned char) c),c_locale));
1529 #endif
1530  return(tolower((int) ((unsigned char) 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  register int
1585  c,
1586  d;
1587 
1588  register 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  register char
1633  *q;
1634 
1635  assert(string != (char *) NULL);
1636  for (q=string; *q != '\0'; q++)
1637  *q=(char) LocaleUppercase((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() convert to uppercase.
1652 %
1653 % The format of the LocaleUppercase method is:
1654 %
1655 % void 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 */
1663 {
1664  if (c == EOF)
1665  return(c);
1666 #if defined(MAGICKCORE_LOCALE_SUPPORT)
1667  if (c_locale != (locale_t) NULL)
1668  return(toupper_l((int) ((unsigned char) c),c_locale));
1669 #endif
1670  return(toupper((int) ((unsigned char) 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 */
1692 {
1693  if (locale_semaphore == (SemaphoreInfo *) NULL)
1695  (void) AcquireCLocale();
1696  return(MagickTrue);
1697 }
1698 
1699 /*
1700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701 % %
1702 % %
1703 % %
1704 + L o c a l e C o m p o n e n t T e r m i n u s %
1705 % %
1706 % %
1707 % %
1708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1709 %
1710 % LocaleComponentTerminus() destroys the locale component.
1711 %
1712 % The format of the LocaleComponentTerminus method is:
1713 %
1714 % LocaleComponentTerminus(void)
1715 %
1716 */
1718 {
1719  if (locale_semaphore == (SemaphoreInfo *) NULL)
1722  if (locale_cache != (SplayTreeInfo *) NULL)
1724 #if defined(MAGICKCORE_LOCALE_SUPPORT)
1725  DestroyCLocale();
1726 #endif
1729 }
#define magick_restrict
Definition: MagickCore.h:41
static void * DestroyLocaleNode(void *locale_info)
Definition: locale.c:202
#define MagickMaxRecursionDepth
Definition: studio.h:344
MagickExport MagickBooleanType AddValueToSplayTree(SplayTreeInfo *splay_tree, const void *key, const void *value)
Definition: splay-tree.c:154
static void ChopLocaleComponents(char *path, const size_t components)
Definition: locale.c:1137
MagickExport void SetStringInfoPath(StringInfo *string_info, const char *path)
Definition: string.c:1821
MagickExport void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
Definition: semaphore.c:450
MagickExport void ResetLinkedListIterator(LinkedListInfo *list_info)
Definition: linked-list.c:959
MagickExport int LocaleLowercase(const int c)
Definition: locale.c:1522
MagickPrivate ssize_t FormatLocaleStringList(char *magick_restrict, const size_t, const char *magick_restrict, va_list) magick_attribute((__format__(__printf__
MagickExport LinkedListInfo * DestroyLinkedList(LinkedListInfo *list_info, void *(*relinquish_value)(void *))
Definition: linked-list.c:219
MagickExport size_t ConcatenateMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:426
MagickExport SemaphoreInfo * AcquireSemaphoreInfo(void)
Definition: semaphore.c:192
static const char * LocaleMap
Definition: locale.c:78
static void * DestroyOptions(void *message)
Definition: locale.c:320
#define LocaleFilename
Definition: locale.c:72
MagickExport ExceptionInfo * AcquireExceptionInfo(void)
Definition: exception.c:115
static SplayTreeInfo * AcquireLocaleSplayTree(const char *filename, const char *locale, ExceptionInfo *exception)
Definition: locale.c:217
MagickExport MagickBooleanType AppendValueToLinkedList(LinkedListInfo *list_info, const void *value)
Definition: linked-list.c:111
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:499
MagickExport LinkedListInfo * GetLocaleOptions(const char *filename, ExceptionInfo *exception)
Definition: locale.c:821
static void * AcquireCriticalMemory(const size_t size)
static int LocaleTagCompare(const void *x, const void *y)
Definition: locale.c:693
MagickExport size_t GetNextToken(const char *start, const char **end, const size_t extent, char *token)
Definition: token.c:173
Definition: log.h:52
MagickExport void * GetNextValueInLinkedList(LinkedListInfo *list_info)
Definition: linked-list.c:305
ExceptionType
Definition: exception.h:27
MagickExport const void * GetNextValueInSplayTree(SplayTreeInfo *splay_tree)
Definition: splay-tree.c:823
#define MagickCoreSignature
MagickExport int LocaleUppercase(const int c)
Definition: locale.c:1662
MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
Definition: semaphore.c:293
MagickExport unsigned char * GetStringInfoDatum(const StringInfo *string_info)
Definition: string.c:1215
MagickPrivate ssize_t FormatLocaleFileList(FILE *file, const char *magick_restrict format, va_list operands)
Definition: locale.c:359
MagickExport void GetPathComponent(const char *path, PathType type, char *component)
Definition: utility.c:1213
MagickExport ssize_t FormatLocaleFile(FILE *file, const char *magick_restrict format,...)
Definition: locale.c:404
MagickBooleanType
Definition: magick-type.h:158
#define DirectorySeparator
Definition: studio.h:259
unsigned int MagickStatusType
Definition: magick-type.h:121
MagickExport char * AcquireString(const char *source)
Definition: string.c:129
MagickExport void LocaleLower(char *string)
Definition: locale.c:1490
char * message
Definition: locale_.h:30
MagickExport StringInfo * DestroyStringInfo(StringInfo *string_info)
Definition: string.c:850
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:543
MagickExport int LocaleNCompare(const char *p, const char *q, const size_t length)
Definition: locale.c:1570
#define magick_unused(x)
static MagickBooleanType LoadLocaleCache(SplayTreeInfo *, const char *, const char *, const char *, const size_t, ExceptionInfo *)
Definition: locale.c:1176
MagickExport SplayTreeInfo * DestroySplayTree(SplayTreeInfo *splay_tree)
Definition: splay-tree.c:682
MagickExport MagickBooleanType GlobExpression(const char *expression, const char *pattern, const MagickBooleanType case_insensitive)
Definition: token.c:352
#define MagickPathExtent
char * tag
Definition: locale_.h:30
MagickExport SplayTreeInfo * NewSplayTree(int(*compare)(const void *, const void *), void *(*relinquish_key)(void *), void *(*relinquish_value)(void *))
Definition: splay-tree.c:1141
size_t signature
Definition: locale_.h:38
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1413
MagickExport MagickBooleanType ListLocaleInfo(FILE *file, ExceptionInfo *exception)
Definition: locale.c:1058
MagickExport char ** GetLocaleList(const char *pattern, size_t *number_messages, ExceptionInfo *exception)
Definition: locale.c:708
#define MagickLocaleExtent
MagickExport FatalErrorHandler SetFatalErrorHandler(FatalErrorHandler handler)
Definition: exception.c:910
static SemaphoreInfo * locale_semaphore
Definition: locale.c:122
static int LocaleInfoCompare(const void *x, const void *y)
Definition: locale.c:596
MagickExport char * GetEnvironmentValue(const char *name)
Definition: string.c:1182
MagickExport StringInfo * ConfigureFileToStringInfo(const char *filename)
Definition: string.c:592
MagickExport LinkedListInfo * NewLinkedList(const size_t capacity)
Definition: linked-list.c:713
static void LocaleFatalErrorHandler(const ExceptionType magick_unused(severity), const char *reason, const char *description)
Definition: locale.c:1160
static SplayTreeInfo * locale_cache
Definition: locale.c:125
MagickExport size_t CopyMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:755
MagickExport const void * GetValueFromSplayTree(SplayTreeInfo *splay_tree, const void *key)
Definition: splay-tree.c:921
MagickExport const char * GetClientName(void)
Definition: client.c:65
MagickExport StringInfo * AcquireStringInfo(const size_t length)
Definition: string.c:187
static const unsigned char AsciiMap[]
Definition: locale.c:94
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1435
MagickExport LinkedListInfo * DestroyLocaleOptions(LinkedListInfo *messages)
Definition: locale.c:325
#define GetMagickModule()
Definition: log.h:28
MagickExport int CompareSplayTreeString(const void *target, const void *source)
Definition: splay-tree.c:412
MagickExport LinkedListInfo * GetConfigurePaths(const char *filename, ExceptionInfo *exception)
Definition: configure.c:731
MagickExport const char * GetStringInfoPath(const StringInfo *string_info)
Definition: string.c:1302
char * path
Definition: locale_.h:30
MagickExport const char * GetLocaleMessage(const char *tag)
Definition: locale.c:773
MagickExport void SetStringInfoLength(StringInfo *string_info, const size_t length)
Definition: string.c:1745
MagickExport char * DestroyString(char *string)
Definition: string.c:823
MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
Definition: semaphore.c:97
MagickExport const LocaleInfo * GetLocaleInfo_(const char *tag, ExceptionInfo *exception)
Definition: locale.c:540
#define MagickMin(x, y)
Definition: image-private.h:27
MagickExport void ResetSplayTreeIterator(SplayTreeInfo *splay_tree)
Definition: splay-tree.c:1472
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1069
#define magick_unreferenced(x)
MagickExport size_t GetNumberOfNodesInSplayTree(const SplayTreeInfo *splay_tree)
Definition: splay-tree.c:976
static MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *)
Definition: locale.c:937
MagickPrivate MagickBooleanType LocaleComponentGenesis(void)
Definition: locale.c:1691
MagickExport const char * GetLocaleValue(const LocaleInfo *locale_info)
Definition: locale.c:906
#define MagickPrivate
MagickPrivate char * FileToXML(const char *, const size_t)
Definition: xml-tree.c:599
MagickBooleanType stealth
Definition: locale_.h:35
#define MagickExport
void(* FatalErrorHandler)(const ExceptionType, const char *, const char *)
Definition: exception.h:130
MagickExport const LocaleInfo ** GetLocaleInfoList(const char *pattern, size_t *number_messages, ExceptionInfo *exception)
Definition: locale.c:613
MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
Definition: semaphore.c:351
MagickExport void LocaleUpper(char *string)
Definition: locale.c:1630
MagickExport char * ConstantString(const char *source)
Definition: string.c:700
MagickExport void SetStringInfoDatum(StringInfo *string_info, const unsigned char *source)
Definition: string.c:1712
MagickPrivate void LocaleComponentTerminus(void)
Definition: locale.c:1717
MagickExport ExceptionInfo * DestroyExceptionInfo(ExceptionInfo *exception)
Definition: exception.c:418
MagickExport double InterpretLocaleValue(const char *magick_restrict string, char **magick_restrict sentinal)
Definition: locale.c:1003