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