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