]> granicus.if.org Git - imagemagick/blob - magick/locale.c
(no commit message)
[imagemagick] / magick / 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 %                                John Cristy                                  %
17 %                                 July 2003                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2011 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 %    http://www.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 \f
39 /*
40   Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/client.h"
45 #include "magick/configure.h"
46 #include "magick/exception.h"
47 #include "magick/exception-private.h"
48 #include "magick/hashmap.h"
49 #include "magick/locale_.h"
50 #include "magick/log.h"
51 #include "magick/memory_.h"
52 #include "magick/semaphore.h"
53 #include "magick/splay-tree.h"
54 #include "magick/string_.h"
55 #include "magick/token.h"
56 #include "magick/utility.h"
57 #include "magick/xml-tree.h"
58 \f
59 /*
60   Define declarations.
61 */
62 #define LocaleFilename  "locale.xml"
63 #define MaxRecursionDepth  200
64 \f
65 /*
66   Static declarations.
67 */
68 static const char
69   *LocaleMap =
70     "<?xml version=\"1.0\"?>"
71     "<localemap>"
72     "  <locale name=\"C\">"
73     "    <Exception>"
74     "     <Message name=\"\">"
75     "     </Message>"
76     "    </Exception>"
77     "  </locale>"
78     "</localemap>";
79
80 static SemaphoreInfo
81   *locale_semaphore = (SemaphoreInfo *) NULL;
82
83 static SplayTreeInfo
84   *locale_list = (SplayTreeInfo *) NULL;
85
86 static volatile MagickBooleanType
87   instantiate_locale = MagickFalse;
88
89 static volatile locale_t
90   locale_cache = (locale_t) NULL;
91 \f
92 /*
93   Forward declarations.
94 */
95 static MagickBooleanType
96   InitializeLocaleList(ExceptionInfo *),
97   LoadLocaleLists(const char *,const char *,ExceptionInfo *);
98 \f
99 /*
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 +   A c q u i r e M a g i c k L o c a l e                                     %
105 %                                                                             %
106 %                                                                             %
107 %                                                                             %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 %
110 %  AcquireMagickLocale() allocates the C locale object, or (locale_t) 0 with
111 %  errno set if it cannot be acquired.
112 %
113 %  The format of the AcquireMagickLocale method is:
114 %
115 %      locale_t AcquireMagickLocale(void)
116 %
117 */
118 MagickExport locale_t AcquireMagickLocale(void)
119 {
120 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
121   if (locale_cache == (locale_t) NULL)
122     locale_cache=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
123 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
124   if (locale_cache == (locale_t) NULL)
125     locale_cache=_create_locale(LC_ALL,"C");
126 #endif
127   return(locale_cache);
128 }
129 \f
130 /*
131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132 %                                                                             %
133 %                                                                             %
134 %                                                                             %
135 %   D e s t r o y L o c a l e O p t i o n s                                   %
136 %                                                                             %
137 %                                                                             %
138 %                                                                             %
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 %
141 %  DestroyLocaleOptions() releases memory associated with an locale
142 %  messages.
143 %
144 %  The format of the DestroyProfiles method is:
145 %
146 %      LinkedListInfo *DestroyLocaleOptions(Image *image)
147 %
148 %  A description of each parameter follows:
149 %
150 %    o image: the image.
151 %
152 */
153
154 static void *DestroyOptions(void *message)
155 {
156   return(DestroyStringInfo((StringInfo *) message));
157 }
158
159 MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
160 {
161   assert(messages != (LinkedListInfo *) NULL);
162   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
163   return(DestroyLinkedList(messages,DestroyOptions));
164 }
165 \f
166 /*
167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168 %                                                                             %
169 %                                                                             %
170 %                                                                             %
171 +   D e s t r o y M a g i c k L o c a l e                                     %
172 %                                                                             %
173 %                                                                             %
174 %                                                                             %
175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 %
177 %  DestroyMagickLocale() releases the resources allocated for a locale object
178 %  returned by a call to the AcquireMagickLocale() method.
179 %
180 %  The format of the DestroyMagickLocale method is:
181 %
182 %      void DestroyMagickLocale(void)
183 %
184 */
185 MagickExport void DestroyMagickLocale(void)
186 {
187 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
188   if (locale_cache != (locale_t) NULL)
189     freelocale(locale_cache);
190 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
191   if (locale_cache != (locale_t) NULL)
192     _free_locale(locale_cache);
193 #endif
194   locale_cache=(locale_t) NULL;
195 }
196 \f
197 /*
198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 %                                                                             %
200 %                                                                             %
201 %                                                                             %
202 +   G e t L o c a l e I n f o _                                               %
203 %                                                                             %
204 %                                                                             %
205 %                                                                             %
206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 %
208 %  GetLocaleInfo_() searches the locale list for the specified tag and if
209 %  found returns attributes for that element.
210 %
211 %  The format of the GetLocaleInfo method is:
212 %
213 %      const LocaleInfo *GetLocaleInfo_(const char *tag,
214 %        ExceptionInfo *exception)
215 %
216 %  A description of each parameter follows:
217 %
218 %    o tag: the locale tag.
219 %
220 %    o exception: return any errors or warnings in this structure.
221 %
222 */
223 MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
224   ExceptionInfo *exception)
225 {
226   assert(exception != (ExceptionInfo *) NULL);
227   if ((locale_list == (SplayTreeInfo *) NULL) ||
228       (instantiate_locale == MagickFalse))
229     if (InitializeLocaleList(exception) == MagickFalse)
230       return((const LocaleInfo *) NULL);
231   if ((locale_list == (SplayTreeInfo *) NULL) ||
232       (GetNumberOfNodesInSplayTree(locale_list) == 0))
233     return((const LocaleInfo *) NULL);
234   if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
235     {
236       ResetSplayTreeIterator(locale_list);
237       return((const LocaleInfo *) GetNextValueInSplayTree(locale_list));
238     }
239   return((const LocaleInfo *) GetValueFromSplayTree(locale_list,tag));
240 }
241 \f
242 /*
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 %                                                                             %
245 %                                                                             %
246 %                                                                             %
247 %   G e t L o c a l e I n f o L i s t                                         %
248 %                                                                             %
249 %                                                                             %
250 %                                                                             %
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 %
253 %  GetLocaleInfoList() returns any locale messages that match the
254 %  specified pattern.
255 %
256 %  The format of the GetLocaleInfoList function is:
257 %
258 %      const LocaleInfo **GetLocaleInfoList(const char *pattern,
259 %        size_t *number_messages,ExceptionInfo *exception)
260 %
261 %  A description of each parameter follows:
262 %
263 %    o pattern: Specifies a pointer to a text string containing a pattern.
264 %
265 %    o number_messages:  This integer returns the number of locale messages in
266 %    the list.
267 %
268 %    o exception: return any errors or warnings in this structure.
269 %
270 */
271
272 #if defined(__cplusplus) || defined(c_plusplus)
273 extern "C" {
274 #endif
275
276 static int LocaleInfoCompare(const void *x,const void *y)
277 {
278   const LocaleInfo
279     **p,
280     **q;
281
282   p=(const LocaleInfo **) x,
283   q=(const LocaleInfo **) y;
284   if (LocaleCompare((*p)->path,(*q)->path) == 0)
285     return(LocaleCompare((*p)->tag,(*q)->tag));
286   return(LocaleCompare((*p)->path,(*q)->path));
287 }
288
289 #if defined(__cplusplus) || defined(c_plusplus)
290 }
291 #endif
292
293 MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
294   size_t *number_messages,ExceptionInfo *exception)
295 {
296   const LocaleInfo
297     **messages;
298
299   register const LocaleInfo
300     *p;
301
302   register ssize_t
303     i;
304
305   /*
306     Allocate locale list.
307   */
308   assert(pattern != (char *) NULL);
309   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
310   assert(number_messages != (size_t *) NULL);
311   *number_messages=0;
312   p=GetLocaleInfo_("*",exception);
313   if (p == (const LocaleInfo *) NULL)
314     return((const LocaleInfo **) NULL);
315   messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
316     GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
317   if (messages == (const LocaleInfo **) NULL)
318     return((const LocaleInfo **) NULL);
319   /*
320     Generate locale list.
321   */
322   LockSemaphoreInfo(locale_semaphore);
323   ResetSplayTreeIterator(locale_list);
324   p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
325   for (i=0; p != (const LocaleInfo *) NULL; )
326   {
327     if ((p->stealth == MagickFalse) &&
328         (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
329       messages[i++]=p;
330     p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
331   }
332   UnlockSemaphoreInfo(locale_semaphore);
333   qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
334   messages[i]=(LocaleInfo *) NULL;
335   *number_messages=(size_t) i;
336   return(messages);
337 }
338 \f
339 /*
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341 %                                                                             %
342 %                                                                             %
343 %                                                                             %
344 %   G e t L o c a l e L i s t                                                 %
345 %                                                                             %
346 %                                                                             %
347 %                                                                             %
348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349 %
350 %  GetLocaleList() returns any locale messages that match the specified
351 %  pattern.
352 %
353 %  The format of the GetLocaleList function is:
354 %
355 %      char **GetLocaleList(const char *pattern,size_t *number_messages,
356 %        Exceptioninfo *exception)
357 %
358 %  A description of each parameter follows:
359 %
360 %    o pattern: Specifies a pointer to a text string containing a pattern.
361 %
362 %    o number_messages:  This integer returns the number of messages in the
363 %      list.
364 %
365 %    o exception: return any errors or warnings in this structure.
366 %
367 */
368
369 #if defined(__cplusplus) || defined(c_plusplus)
370 extern "C" {
371 #endif
372
373 static int LocaleTagCompare(const void *x,const void *y)
374 {
375   register char
376     **p,
377     **q;
378
379   p=(char **) x;
380   q=(char **) y;
381   return(LocaleCompare(*p,*q));
382 }
383
384 #if defined(__cplusplus) || defined(c_plusplus)
385 }
386 #endif
387
388 MagickExport char **GetLocaleList(const char *pattern,
389   size_t *number_messages,ExceptionInfo *exception)
390 {
391   char
392     **messages;
393
394   register const LocaleInfo
395     *p;
396
397   register ssize_t
398     i;
399
400   /*
401     Allocate locale list.
402   */
403   assert(pattern != (char *) NULL);
404   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
405   assert(number_messages != (size_t *) NULL);
406   *number_messages=0;
407   p=GetLocaleInfo_("*",exception);
408   if (p == (const LocaleInfo *) NULL)
409     return((char **) NULL);
410   messages=(char **) AcquireQuantumMemory((size_t)
411     GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
412   if (messages == (char **) NULL)
413     return((char **) NULL);
414   LockSemaphoreInfo(locale_semaphore);
415   p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
416   for (i=0; p != (const LocaleInfo *) NULL; )
417   {
418     if ((p->stealth == MagickFalse) &&
419         (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
420       messages[i++]=ConstantString(p->tag);
421     p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
422   }
423   UnlockSemaphoreInfo(locale_semaphore);
424   qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
425   messages[i]=(char *) NULL;
426   *number_messages=(size_t) i;
427   return(messages);
428 }
429 \f
430 /*
431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
432 %                                                                             %
433 %                                                                             %
434 %                                                                             %
435 %   G e t L o c a l e M e s s a g e                                           %
436 %                                                                             %
437 %                                                                             %
438 %                                                                             %
439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
440 %
441 %  GetLocaleMessage() returns a message in the current locale that matches the
442 %  supplied tag.
443 %
444 %  The format of the GetLocaleMessage method is:
445 %
446 %      const char *GetLocaleMessage(const char *tag)
447 %
448 %  A description of each parameter follows:
449 %
450 %    o tag: Return a message that matches this tag in the current locale.
451 %
452 */
453 MagickExport const char *GetLocaleMessage(const char *tag)
454 {
455   char
456     name[MaxTextExtent];
457
458   const LocaleInfo
459     *locale_info;
460
461   ExceptionInfo
462     *exception;
463
464   if ((tag == (const char *) NULL) || (*tag == '\0'))
465     return(tag);
466   exception=AcquireExceptionInfo();
467   (void) FormatMagickString(name,MaxTextExtent,"%s/",tag);
468   locale_info=GetLocaleInfo_(name,exception);
469   exception=DestroyExceptionInfo(exception);
470   if (locale_info != (const LocaleInfo *) NULL)
471     return(locale_info->message);
472   return(tag);
473 }
474 \f
475 /*
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477 %                                                                             %
478 %                                                                             %
479 %                                                                             %
480 %  G e t L o c a l e O p t i o n s                                            %
481 %                                                                             %
482 %                                                                             %
483 %                                                                             %
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 %
486 %  GetLocaleOptions() returns any Magick configuration messages associated
487 %  with the specified filename.
488 %
489 %  The format of the GetLocaleOptions method is:
490 %
491 %      LinkedListInfo *GetLocaleOptions(const char *filename,
492 %        ExceptionInfo *exception)
493 %
494 %  A description of each parameter follows:
495 %
496 %    o filename: the locale file tag.
497 %
498 %    o exception: return any errors or warnings in this structure.
499 %
500 */
501 MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
502   ExceptionInfo *exception)
503 {
504   char
505     path[MaxTextExtent];
506
507   const char
508     *element;
509
510   LinkedListInfo
511     *messages,
512     *paths;
513
514   StringInfo
515     *xml;
516
517   assert(filename != (const char *) NULL);
518   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
519   assert(exception != (ExceptionInfo *) NULL);
520   (void) CopyMagickString(path,filename,MaxTextExtent);
521   /*
522     Load XML from configuration files to linked-list.
523   */
524   messages=NewLinkedList(0);
525   paths=GetConfigurePaths(filename,exception);
526   if (paths != (LinkedListInfo *) NULL)
527     {
528       ResetLinkedListIterator(paths);
529       element=(const char *) GetNextValueInLinkedList(paths);
530       while (element != (const char *) NULL)
531       {
532         (void) FormatMagickString(path,MaxTextExtent,"%s%s",element,filename);
533         (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
534           "Searching for locale file: \"%s\"",path);
535         xml=ConfigureFileToStringInfo(path);
536         if (xml != (StringInfo *) NULL)
537           (void) AppendValueToLinkedList(messages,xml);
538         element=(const char *) GetNextValueInLinkedList(paths);
539       }
540       paths=DestroyLinkedList(paths,RelinquishMagickMemory);
541     }
542 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
543   {
544     char
545       *blob;
546
547     blob=(char *) NTResourceToBlob(filename);
548     if (blob != (char *) NULL)
549       {
550         xml=StringToStringInfo(blob);
551         (void) AppendValueToLinkedList(messages,xml);
552         blob=DestroyString(blob);
553       }
554   }
555 #endif
556   ResetLinkedListIterator(messages);
557   return(messages);
558 }
559 \f
560 /*
561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 %                                                                             %
563 %                                                                             %
564 %                                                                             %
565 %   G e t L o c a l e V a l u e                                               %
566 %                                                                             %
567 %                                                                             %
568 %                                                                             %
569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
570 %
571 %  GetLocaleValue() returns the message associated with the locale info.
572 %
573 %  The format of the GetLocaleValue method is:
574 %
575 %      const char *GetLocaleValue(const LocaleInfo *locale_info)
576 %
577 %  A description of each parameter follows:
578 %
579 %    o locale_info:  The locale info.
580 %
581 */
582 MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
583 {
584   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
585   assert(locale_info != (LocaleInfo *) NULL);
586   assert(locale_info->signature == MagickSignature);
587   return(locale_info->message);
588 }
589 \f
590 /*
591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 %                                                                             %
593 %                                                                             %
594 %                                                                             %
595 +   I n i t i a l i z e L o c a l e L i s t                                   %
596 %                                                                             %
597 %                                                                             %
598 %                                                                             %
599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
600 %
601 %  InitializeLocaleList() initializes the locale list.
602 %
603 %  The format of the InitializeLocaleList method is:
604 %
605 %      MagickBooleanType InitializeLocaleList(ExceptionInfo *exception)
606 %
607 %  A description of each parameter follows.
608 %
609 %    o exception: return any errors or warnings in this structure.
610 %
611 */
612 static MagickBooleanType InitializeLocaleList(ExceptionInfo *exception)
613 {
614   if ((locale_list == (SplayTreeInfo *) NULL) &&
615       (instantiate_locale == MagickFalse))
616     {
617       if (locale_semaphore == (SemaphoreInfo *) NULL)
618         AcquireSemaphoreInfo(&locale_semaphore);
619       LockSemaphoreInfo(locale_semaphore);
620       if ((locale_list == (SplayTreeInfo *) NULL) &&
621           (instantiate_locale == MagickFalse))
622         {
623           char
624             *locale;
625
626           register const char
627             *p;
628
629           locale=(char *) NULL;
630           p=setlocale(LC_CTYPE,(const char *) NULL);
631           if (p != (const char *) NULL)
632             locale=ConstantString(p);
633           if (locale == (char *) NULL)
634             locale=GetEnvironmentValue("LC_ALL");
635           if (locale == (char *) NULL)
636             locale=GetEnvironmentValue("LC_MESSAGES");
637           if (locale == (char *) NULL)
638             locale=GetEnvironmentValue("LC_CTYPE");
639           if (locale == (char *) NULL)
640             locale=GetEnvironmentValue("LANG");
641           if (locale == (char *) NULL)
642             locale=ConstantString("C");
643           (void) LoadLocaleLists(LocaleFilename,locale,exception);
644           locale=DestroyString(locale);
645           instantiate_locale=MagickTrue;
646         }
647       UnlockSemaphoreInfo(locale_semaphore);
648     }
649   return(locale_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
650 }
651 \f
652 /*
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654 %                                                                             %
655 %                                                                             %
656 %                                                                             %
657 %  L i s t L o c a l e I n f o                                                %
658 %                                                                             %
659 %                                                                             %
660 %                                                                             %
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 %
663 %  ListLocaleInfo() lists the locale info to a file.
664 %
665 %  The format of the ListLocaleInfo method is:
666 %
667 %      MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
668 %
669 %  A description of each parameter follows.
670 %
671 %    o file:  An pointer to a FILE.
672 %
673 %    o exception: return any errors or warnings in this structure.
674 %
675 */
676 MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
677   ExceptionInfo *exception)
678 {
679   const char
680     *path;
681
682   const LocaleInfo
683     **locale_info;
684
685   register ssize_t
686     i;
687
688   size_t
689     number_messages;
690
691   if (file == (const FILE *) NULL)
692     file=stdout;
693   number_messages=0;
694   locale_info=GetLocaleInfoList("*",&number_messages,exception);
695   if (locale_info == (const LocaleInfo **) NULL)
696     return(MagickFalse);
697   path=(const char *) NULL;
698   for (i=0; i < (ssize_t) number_messages; i++)
699   {
700     if (locale_info[i]->stealth != MagickFalse)
701       continue;
702     if ((path == (const char *) NULL) ||
703         (LocaleCompare(path,locale_info[i]->path) != 0))
704       {
705         if (locale_info[i]->path != (char *) NULL)
706           (void) fprintf(file,"\nPath: %s\n\n",locale_info[i]->path);
707         (void) fprintf(file,"Tag/Message\n");
708         (void) fprintf(file,"-------------------------------------------------"
709           "------------------------------\n");
710       }
711     path=locale_info[i]->path;
712     (void) fprintf(file,"%s\n",locale_info[i]->tag);
713     if (locale_info[i]->message != (char *) NULL)
714       (void) fprintf(file,"  %s",locale_info[i]->message);
715     (void) fprintf(file,"\n");
716   }
717   (void) fflush(file);
718   locale_info=(const LocaleInfo **)
719     RelinquishMagickMemory((void *) locale_info);
720   return(MagickTrue);
721 }
722 \f
723 /*
724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725 %                                                                             %
726 %                                                                             %
727 %                                                                             %
728 +   L o a d L o c a l e L i s t                                               %
729 %                                                                             %
730 %                                                                             %
731 %                                                                             %
732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733 %
734 %  LoadLocaleList() loads the locale configuration file which provides a mapping
735 %  between locale attributes and a locale name.
736 %
737 %  The format of the LoadLocaleList method is:
738 %
739 %      MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
740 %        const size_t depth,ExceptionInfo *exception)
741 %
742 %  A description of each parameter follows:
743 %
744 %    o xml:  The locale list in XML format.
745 %
746 %    o filename:  The locale list filename.
747 %
748 %    o depth: depth of <include /> statements.
749 %
750 %    o exception: return any errors or warnings in this structure.
751 %
752 */
753
754 static void ChopLocaleComponents(char *path,const size_t components)
755 {
756   register char
757     *p;
758
759   ssize_t
760     count;
761
762   if (*path == '\0')
763     return;
764   p=path+strlen(path)-1;
765   if (*p == '/')
766     *p='\0';
767   for (count=0; (count < (ssize_t) components) && (p > path); p--)
768     if (*p == '/')
769       {
770         *p='\0';
771         count++;
772       }
773   if (count < (ssize_t) components)
774     *path='\0';
775 }
776
777 static void *DestroyLocaleNode(void *locale_info)
778 {
779   register LocaleInfo
780     *p;
781
782   p=(LocaleInfo *) locale_info;
783   if (p->path != (char *) NULL)
784     p->path=DestroyString(p->path);
785   if (p->tag != (char *) NULL)
786     p->tag=DestroyString(p->tag);
787   if (p->message != (char *) NULL)
788     p->message=DestroyString(p->message);
789   return(RelinquishMagickMemory(p));
790 }
791
792 static void LocaleFatalErrorHandler(
793   const ExceptionType magick_unused(severity),
794   const char *reason,const char *description)
795 {
796   if (reason == (char *) NULL)
797     return;
798   (void) fprintf(stderr,"%s: %s",GetClientName(),reason);
799   if (description != (char *) NULL)
800     (void) fprintf(stderr," (%s)",description);
801   (void) fprintf(stderr,".\n");
802   (void) fflush(stderr);
803   exit(1);
804 }
805
806
807 static MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
808   const char *locale,const size_t depth,ExceptionInfo *exception)
809 {
810   char
811     keyword[MaxTextExtent],
812     message[MaxTextExtent],
813     tag[MaxTextExtent],
814     *token;
815
816   const char
817     *q;
818
819   FatalErrorHandler
820     fatal_handler;
821
822   LocaleInfo
823     *locale_info;
824
825   MagickBooleanType
826     status;
827
828   register char
829     *p;
830
831   /*
832     Read the locale configure file.
833   */
834   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
835     "Loading locale configure file \"%s\" ...",filename);
836   if (xml == (const char *) NULL)
837     return(MagickFalse);
838   if (locale_list == (SplayTreeInfo *) NULL)
839     {
840       locale_list=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
841         DestroyLocaleNode);
842       if (locale_list == (SplayTreeInfo *) NULL)
843         return(MagickFalse);
844     }
845   status=MagickTrue;
846   locale_info=(LocaleInfo *) NULL;
847   *tag='\0';
848   *message='\0';
849   *keyword='\0';
850   fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
851   token=AcquireString(xml);
852   for (q=(char *) xml; *q != '\0'; )
853   {
854     /*
855       Interpret XML.
856     */
857     GetMagickToken(q,&q,token);
858     if (*token == '\0')
859       break;
860     (void) CopyMagickString(keyword,token,MaxTextExtent);
861     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
862       {
863         /*
864           Doctype element.
865         */
866         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
867         {
868           GetMagickToken(q,&q,token);
869           while (isspace((int) ((unsigned char) *q)) != 0)
870             q++;
871         }
872         continue;
873       }
874     if (LocaleNCompare(keyword,"<!--",4) == 0)
875       {
876         /*
877           Comment element.
878         */
879         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
880         {
881           GetMagickToken(q,&q,token);
882           while (isspace((int) ((unsigned char) *q)) != 0)
883             q++;
884         }
885         continue;
886       }
887     if (LocaleCompare(keyword,"<include") == 0)
888       {
889         /*
890           Include element.
891         */
892         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
893         {
894           (void) CopyMagickString(keyword,token,MaxTextExtent);
895           GetMagickToken(q,&q,token);
896           if (*token != '=')
897             continue;
898           GetMagickToken(q,&q,token);
899           if (LocaleCompare(keyword,"locale") == 0)
900             {
901               if (LocaleCompare(locale,token) != 0)
902                 break;
903               continue;
904             }
905           if (LocaleCompare(keyword,"file") == 0)
906             {
907               if (depth > 200)
908                 (void) ThrowMagickException(exception,GetMagickModule(),
909                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
910               else
911                 {
912                   char
913                     path[MaxTextExtent],
914                     *xml;
915
916                   *path='\0';
917                   GetPathComponent(filename,HeadPath,path);
918                   if (*path != '\0')
919                     (void) ConcatenateMagickString(path,DirectorySeparator,
920                       MaxTextExtent);
921                   if (*token == *DirectorySeparator)
922                     (void) CopyMagickString(path,token,MaxTextExtent);
923                   else
924                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
925                   xml=FileToString(path,~0,exception);
926                   if (xml != (char *) NULL)
927                     {
928                       status=LoadLocaleList(xml,path,locale,depth+1,exception);
929                       xml=(char *) RelinquishMagickMemory(xml);
930                     }
931                 }
932             }
933         }
934         continue;
935       }
936     if (LocaleCompare(keyword,"<locale") == 0)
937       {
938         /*
939           Locale element.
940         */
941         while ((*token != '>') && (*q != '\0'))
942         {
943           (void) CopyMagickString(keyword,token,MaxTextExtent);
944           GetMagickToken(q,&q,token);
945           if (*token != '=')
946             continue;
947           GetMagickToken(q,&q,token);
948         }
949         continue;
950       }
951     if (LocaleCompare(keyword,"</locale>") == 0)
952       {
953         ChopLocaleComponents(tag,1);
954         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
955         continue;
956       }
957     if (LocaleCompare(keyword,"<localemap>") == 0)
958       continue;
959     if (LocaleCompare(keyword,"</localemap>") == 0)
960       continue;
961     if (LocaleCompare(keyword,"<message") == 0)
962       {
963         /*
964           Message element.
965         */
966         while ((*token != '>') && (*q != '\0'))
967         {
968           (void) CopyMagickString(keyword,token,MaxTextExtent);
969           GetMagickToken(q,&q,token);
970           if (*token != '=')
971             continue;
972           GetMagickToken(q,&q,token);
973           if (LocaleCompare(keyword,"name") == 0)
974             {
975               (void) ConcatenateMagickString(tag,token,MaxTextExtent);
976               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
977             }
978         }
979         for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
980         while (isspace((int) ((unsigned char) *p)) != 0)
981           p++;
982         q--;
983         while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
984           q--;
985         (void) CopyMagickString(message,p,(size_t) (q-p+2));
986         locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
987         if (locale_info == (LocaleInfo *) NULL)
988           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
989         (void) ResetMagickMemory(locale_info,0,sizeof(*locale_info));
990         locale_info->path=ConstantString(filename);
991         locale_info->tag=ConstantString(tag);
992         locale_info->message=ConstantString(message);
993         locale_info->signature=MagickSignature;
994         status=AddValueToSplayTree(locale_list,locale_info->tag,locale_info);
995         if (status == MagickFalse)
996           (void) ThrowMagickException(exception,GetMagickModule(),
997             ResourceLimitError,"MemoryAllocationFailed","`%s'",
998             locale_info->tag);
999         (void) ConcatenateMagickString(tag,message,MaxTextExtent);
1000         (void) ConcatenateMagickString(tag,"\n",MaxTextExtent);
1001         q++;
1002         continue;
1003       }
1004     if (LocaleCompare(keyword,"</message>") == 0)
1005       {
1006         ChopLocaleComponents(tag,2);
1007         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1008         continue;
1009       }
1010     if (*keyword == '<')
1011       {
1012         /*
1013           Subpath element.
1014         */
1015         if (*(keyword+1) == '?')
1016           continue;
1017         if (*(keyword+1) == '/')
1018           {
1019             ChopLocaleComponents(tag,1);
1020             if (*tag != '\0')
1021               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1022             continue;
1023           }
1024         token[strlen(token)-1]='\0';
1025         (void) CopyMagickString(token,token+1,MaxTextExtent);
1026         (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1027         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1028         continue;
1029       }
1030     GetMagickToken(q,(const char **) NULL,token);
1031     if (*token != '=')
1032       continue;
1033   }
1034   token=(char *) RelinquishMagickMemory(token);
1035   (void) SetFatalErrorHandler(fatal_handler);
1036   return(status);
1037 }
1038 \f
1039 /*
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 %                                                                             %
1042 %                                                                             %
1043 %                                                                             %
1044 %  L o a d L o c a l e L i s t s                                              %
1045 %                                                                             %
1046 %                                                                             %
1047 %                                                                             %
1048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 %
1050 %  LoadLocaleList() loads one or more locale configuration file which
1051 %  provides a mapping between locale attributes and a locale tag.
1052 %
1053 %  The format of the LoadLocaleLists method is:
1054 %
1055 %      MagickBooleanType LoadLocaleLists(const char *filename,
1056 %        ExceptionInfo *exception)
1057 %
1058 %  A description of each parameter follows:
1059 %
1060 %    o filename: the font file tag.
1061 %
1062 %    o locale: the actual locale.
1063 %
1064 %    o exception: return any errors or warnings in this structure.
1065 %
1066 */
1067 static MagickBooleanType LoadLocaleLists(const char *filename,
1068   const char *locale,ExceptionInfo *exception)
1069 {
1070 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
1071   return(LoadLocaleList(LocaleMap,"built-in",locale,0,exception));
1072 #else
1073   const StringInfo
1074     *option;
1075
1076   LinkedListInfo
1077     *options;
1078
1079   MagickStatusType
1080     status;
1081
1082   status=MagickFalse;
1083   options=GetLocaleOptions(filename,exception);
1084   option=(const StringInfo *) GetNextValueInLinkedList(options);
1085   while (option != (const StringInfo *) NULL)
1086   {
1087     status|=LoadLocaleList((const char *) GetStringInfoDatum(option),
1088       GetStringInfoPath(option),locale,0,exception);
1089     option=(const StringInfo *) GetNextValueInLinkedList(options);
1090   }
1091   options=DestroyLocaleOptions(options);
1092   if ((locale_list == (SplayTreeInfo *) NULL) ||
1093       (GetNumberOfNodesInSplayTree(locale_list) == 0))
1094     {
1095       options=GetLocaleOptions("english.xml",exception);
1096       option=(const StringInfo *) GetNextValueInLinkedList(options);
1097       while (option != (const StringInfo *) NULL)
1098       {
1099         status|=LoadLocaleList((const char *) GetStringInfoDatum(option),
1100           GetStringInfoPath(option),locale,0,exception);
1101         option=(const StringInfo *) GetNextValueInLinkedList(options);
1102       }
1103       options=DestroyLocaleOptions(options);
1104     }
1105   if ((locale_list == (SplayTreeInfo *) NULL) ||
1106       (GetNumberOfNodesInSplayTree(locale_list) == 0))
1107     status|=LoadLocaleList(LocaleMap,"built-in",locale,0,exception);
1108   return(status != 0 ? MagickTrue : MagickFalse);
1109 #endif
1110 }
1111 \f
1112 /*
1113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1114 %                                                                             %
1115 %                                                                             %
1116 %                                                                             %
1117 +   L o c a l e C o m p o n e n t G e n e s i s                               %
1118 %                                                                             %
1119 %                                                                             %
1120 %                                                                             %
1121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122 %
1123 %  LocaleComponentGenesis() instantiates the locale component.
1124 %
1125 %  The format of the LocaleComponentGenesis method is:
1126 %
1127 %      MagickBooleanType LocaleComponentGenesis(void)
1128 %
1129 */
1130 MagickExport MagickBooleanType LocaleComponentGenesis(void)
1131 {
1132   AcquireSemaphoreInfo(&locale_semaphore);
1133   return(MagickTrue);
1134 }
1135 \f
1136 /*
1137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138 %                                                                             %
1139 %                                                                             %
1140 %                                                                             %
1141 +   L o c a l e C o m p o n e n t T e r m i n u s                             %
1142 %                                                                             %
1143 %                                                                             %
1144 %                                                                             %
1145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1146 %
1147 %  LocaleComponentTerminus() destroys the locale component.
1148 %
1149 %  The format of the LocaleComponentTerminus method is:
1150 %
1151 %      LocaleComponentTerminus(void)
1152 %
1153 */
1154 MagickExport void LocaleComponentTerminus(void)
1155 {
1156   if (locale_semaphore == (SemaphoreInfo *) NULL)
1157     AcquireSemaphoreInfo(&locale_semaphore);
1158   LockSemaphoreInfo(locale_semaphore);
1159   DestroyMagickLocale();
1160   instantiate_locale=MagickFalse;
1161   UnlockSemaphoreInfo(locale_semaphore);
1162   DestroySemaphoreInfo(&locale_semaphore);
1163 }