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