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