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-2016 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 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/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) && !defined(__MINGW32__) 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 *cache; 193 194 cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL, 195 DestroyLocaleNode); 196 if (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(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(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(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(cache) == 0) 233 status&=LoadLocaleCache(cache,LocaleMap,"built-in",locale,0, 234 exception); 235 return(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) && !defined(__MINGW32__) 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 *magick_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, 380 const char *magick_restrict format,...) 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 *magick_restrict string, 426 const size_t length,const char *magick_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 *magick_restrict string, 475 const size_t length,const char *magick_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 *magick_restrict string, 979 char **magick_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 C a c h e % 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 *cache,const char *xml, 1098% const char *filename,const size_t depth,ExceptionInfo *exception) 1099% 1100% A description of each parameter follows: 1101% 1102% o xml: The locale list in XML format. 1103% 1104% o filename: The locale list filename. 1105% 1106% o depth: depth of <include /> statements. 1107% 1108% o exception: return any errors or warnings in this structure. 1109% 1110*/ 1111 1112static void ChopLocaleComponents(char *path,const size_t components) 1113{ 1114 register char 1115 *p; 1116 1117 ssize_t 1118 count; 1119 1120 if (*path == '\0') 1121 return; 1122 p=path+strlen(path)-1; 1123 if (*p == '/') 1124 *p='\0'; 1125 for (count=0; (count < (ssize_t) components) && (p > path); p--) 1126 if (*p == '/') 1127 { 1128 *p='\0'; 1129 count++; 1130 } 1131 if (count < (ssize_t) components) 1132 *path='\0'; 1133} 1134 1135static void LocaleFatalErrorHandler( 1136 const ExceptionType magick_unused(severity), 1137 const char *reason,const char *description) 1138{ 1139 magick_unreferenced(severity); 1140 1141 if (reason == (char *) NULL) 1142 return; 1143 (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason); 1144 if (description != (char *) NULL) 1145 (void) FormatLocaleFile(stderr," (%s)",description); 1146 (void) FormatLocaleFile(stderr,".\n"); 1147 (void) fflush(stderr); 1148 exit(1); 1149} 1150 1151static MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml, 1152 const char *filename,const char *locale,const size_t depth,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 size_t 1176 extent; 1177 1178 /* 1179 Read the locale configure file. 1180 */ 1181 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), 1182 "Loading locale configure file \"%s\" ...",filename); 1183 if (xml == (const char *) NULL) 1184 return(MagickFalse); 1185 status=MagickTrue; 1186 locale_info=(LocaleInfo *) NULL; 1187 *tag='\0'; 1188 *message='\0'; 1189 *keyword='\0'; 1190 fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler); 1191 token=AcquireString(xml); 1192 extent=strlen(token)+MagickPathExtent; 1193 for (q=(char *) xml; *q != '\0'; ) 1194 { 1195 /* 1196 Interpret XML. 1197 */ 1198 GetNextToken(q,&q,extent,token); 1199 if (*token == '\0') 1200 break; 1201 (void) CopyMagickString(keyword,token,MagickLocaleExtent); 1202 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0) 1203 { 1204 /* 1205 Doctype element. 1206 */ 1207 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0')) 1208 { 1209 GetNextToken(q,&q,extent,token); 1210 while (isspace((int) ((unsigned char) *q)) != 0) 1211 q++; 1212 } 1213 continue; 1214 } 1215 if (LocaleNCompare(keyword,"<!--",4) == 0) 1216 { 1217 /* 1218 Comment element. 1219 */ 1220 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0')) 1221 { 1222 GetNextToken(q,&q,extent,token); 1223 while (isspace((int) ((unsigned char) *q)) != 0) 1224 q++; 1225 } 1226 continue; 1227 } 1228 if (LocaleCompare(keyword,"<include") == 0) 1229 { 1230 /* 1231 Include element. 1232 */ 1233 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0')) 1234 { 1235 (void) CopyMagickString(keyword,token,MagickLocaleExtent); 1236 GetNextToken(q,&q,extent,token); 1237 if (*token != '=') 1238 continue; 1239 GetNextToken(q,&q,extent,token); 1240 if (LocaleCompare(keyword,"locale") == 0) 1241 { 1242 if (LocaleCompare(locale,token) != 0) 1243 break; 1244 continue; 1245 } 1246 if (LocaleCompare(keyword,"file") == 0) 1247 { 1248 if (depth > 200) 1249 (void) ThrowMagickException(exception,GetMagickModule(), 1250 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token); 1251 else 1252 { 1253 char 1254 path[MagickPathExtent], 1255 *file_xml; 1256 1257 *path='\0'; 1258 GetPathComponent(filename,HeadPath,path); 1259 if (*path != '\0') 1260 (void) ConcatenateMagickString(path,DirectorySeparator, 1261 MagickPathExtent); 1262 if (*token == *DirectorySeparator) 1263 (void) CopyMagickString(path,token,MagickPathExtent); 1264 else 1265 (void) ConcatenateMagickString(path,token,MagickPathExtent); 1266 file_xml=FileToXML(path,~0UL); 1267 if (file_xml != (char *) NULL) 1268 { 1269 status&=LoadLocaleCache(cache,file_xml,path,locale, 1270 depth+1,exception); 1271 file_xml=DestroyString(file_xml); 1272 } 1273 } 1274 } 1275 } 1276 continue; 1277 } 1278 if (LocaleCompare(keyword,"<locale") == 0) 1279 { 1280 /* 1281 Locale element. 1282 */ 1283 while ((*token != '>') && (*q != '\0')) 1284 { 1285 (void) CopyMagickString(keyword,token,MagickLocaleExtent); 1286 GetNextToken(q,&q,extent,token); 1287 if (*token != '=') 1288 continue; 1289 GetNextToken(q,&q,extent,token); 1290 } 1291 continue; 1292 } 1293 if (LocaleCompare(keyword,"</locale>") == 0) 1294 { 1295 ChopLocaleComponents(tag,1); 1296 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent); 1297 continue; 1298 } 1299 if (LocaleCompare(keyword,"<localemap>") == 0) 1300 continue; 1301 if (LocaleCompare(keyword,"</localemap>") == 0) 1302 continue; 1303 if (LocaleCompare(keyword,"<message") == 0) 1304 { 1305 /* 1306 Message 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 if (LocaleCompare(keyword,"name") == 0) 1316 { 1317 (void) ConcatenateMagickString(tag,token,MagickLocaleExtent); 1318 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent); 1319 } 1320 } 1321 for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ; 1322 while (isspace((int) ((unsigned char) *p)) != 0) 1323 p++; 1324 q--; 1325 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p)) 1326 q--; 1327 (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2), 1328 MagickLocaleExtent)); 1329 locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info)); 1330 if (locale_info == (LocaleInfo *) NULL) 1331 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1332 (void) ResetMagickMemory(locale_info,0,sizeof(*locale_info)); 1333 locale_info->path=ConstantString(filename); 1334 locale_info->tag=ConstantString(tag); 1335 locale_info->message=ConstantString(message); 1336 locale_info->signature=MagickCoreSignature; 1337 status=AddValueToSplayTree(cache,locale_info->tag,locale_info); 1338 if (status == MagickFalse) 1339 (void) ThrowMagickException(exception,GetMagickModule(), 1340 ResourceLimitError,"MemoryAllocationFailed","`%s'", 1341 locale_info->tag); 1342 (void) ConcatenateMagickString(tag,message,MagickLocaleExtent); 1343 (void) ConcatenateMagickString(tag,"\n",MagickLocaleExtent); 1344 q++; 1345 continue; 1346 } 1347 if (LocaleCompare(keyword,"</message>") == 0) 1348 { 1349 ChopLocaleComponents(tag,2); 1350 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent); 1351 continue; 1352 } 1353 if (*keyword == '<') 1354 { 1355 /* 1356 Subpath element. 1357 */ 1358 if (*(keyword+1) == '?') 1359 continue; 1360 if (*(keyword+1) == '/') 1361 { 1362 ChopLocaleComponents(tag,1); 1363 if (*tag != '\0') 1364 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent); 1365 continue; 1366 } 1367 token[strlen(token)-1]='\0'; 1368 (void) CopyMagickString(token,token+1,MagickLocaleExtent); 1369 (void) ConcatenateMagickString(tag,token,MagickLocaleExtent); 1370 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent); 1371 continue; 1372 } 1373 GetNextToken(q,(const char **) NULL,extent,token); 1374 if (*token != '=') 1375 continue; 1376 } 1377 token=(char *) RelinquishMagickMemory(token); 1378 (void) SetFatalErrorHandler(fatal_handler); 1379 return(status != 0 ? MagickTrue : MagickFalse); 1380} 1381 1382/* 1383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1384% % 1385% % 1386% % 1387% L o c a l e C o m p a r e % 1388% % 1389% % 1390% % 1391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1392% 1393% LocaleCompare() performs a case-insensitive comparison of two strings 1394% byte-by-byte, according to the ordering of the current locale encoding. 1395% LocaleCompare returns an integer greater than, equal to, or less than 0, 1396% if the string pointed to by p is greater than, equal to, or less than the 1397% string pointed to by q respectively. The sign of a non-zero return value 1398% is determined by the sign of the difference between the values of the first 1399% pair of bytes that differ in the strings being compared. 1400% 1401% The format of the LocaleCompare method is: 1402% 1403% int LocaleCompare(const char *p,const char *q) 1404% 1405% A description of each parameter follows: 1406% 1407% o p: A pointer to a character string. 1408% 1409% o q: A pointer to a character string to compare to p. 1410% 1411*/ 1412MagickExport int LocaleCompare(const char *p,const char *q) 1413{ 1414 if ((p == (char *) NULL) && (q == (char *) NULL)) 1415 return(0); 1416 if (p == (char *) NULL) 1417 return(-1); 1418 if (q == (char *) NULL) 1419 return(1); 1420#if defined(MAGICKCORE_HAVE_STRCASECMP) 1421 return(strcasecmp(p,q)); 1422#else 1423 { 1424 register int 1425 c, 1426 d; 1427 1428 for ( ; ; ) 1429 { 1430 c=(int) *((unsigned char *) p); 1431 d=(int) *((unsigned char *) q); 1432 if ((c == 0) || (AsciiMap[c] != AsciiMap[d])) 1433 break; 1434 p++; 1435 q++; 1436 } 1437 return(AsciiMap[c]-(int) AsciiMap[d]); 1438 } 1439#endif 1440} 1441 1442/* 1443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1444% % 1445% % 1446% % 1447% L o c a l e L o w e r % 1448% % 1449% % 1450% % 1451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1452% 1453% LocaleLower() transforms all of the characters in the supplied 1454% null-terminated string, changing all uppercase letters to lowercase. 1455% 1456% The format of the LocaleLower method is: 1457% 1458% void LocaleLower(char *string) 1459% 1460% A description of each parameter follows: 1461% 1462% o string: A pointer to the string to convert to lower-case Locale. 1463% 1464*/ 1465MagickExport void LocaleLower(char *string) 1466{ 1467 register char 1468 *q; 1469 1470 assert(string != (char *) NULL); 1471 for (q=string; *q != '\0'; q++) 1472 *q=(char) tolower((int) *q); 1473} 1474 1475/* 1476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1477% % 1478% % 1479% % 1480% L o c a l e N C o m p a r e % 1481% % 1482% % 1483% % 1484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1485% 1486% LocaleNCompare() performs a case-insensitive comparison of two strings 1487% byte-by-byte, according to the ordering of the current locale encoding. 1488% 1489% LocaleNCompare returns an integer greater than, equal to, or less than 0, 1490% if the string pointed to by p is greater than, equal to, or less than the 1491% string pointed to by q respectively. The sign of a non-zero return value 1492% is determined by the sign of the difference between the values of the first 1493% pair of bytes that differ in the strings being compared. 1494% 1495% The LocaleNCompare method makes the same comparison as LocaleCompare but 1496% looks at a maximum of n bytes. Bytes following a null byte are not 1497% compared. 1498% 1499% The format of the LocaleNCompare method is: 1500% 1501% int LocaleNCompare(const char *p,const char *q,const size_t n) 1502% 1503% A description of each parameter follows: 1504% 1505% o p: A pointer to a character string. 1506% 1507% o q: A pointer to a character string to compare to p. 1508% 1509% o length: the number of characters to compare in strings p and q. 1510% 1511*/ 1512MagickExport int LocaleNCompare(const char *p,const char *q,const size_t length) 1513{ 1514 if ((p == (char *) NULL) && (q == (char *) NULL)) 1515 return(0); 1516 if (p == (char *) NULL) 1517 return(-1); 1518 if (q == (char *) NULL) 1519 return(1); 1520#if defined(MAGICKCORE_HAVE_STRNCASECMP) 1521 return(strncasecmp(p,q,length)); 1522#else 1523 { 1524 register int 1525 c, 1526 d; 1527 1528 register size_t 1529 i; 1530 1531 for (i=length; i != 0; i--) 1532 { 1533 c=(int) *((unsigned char *) p); 1534 d=(int) *((unsigned char *) q); 1535 if (AsciiMap[c] != AsciiMap[d]) 1536 return(AsciiMap[c]-(int) AsciiMap[d]); 1537 if (c == 0) 1538 return(0); 1539 p++; 1540 q++; 1541 } 1542 return(0); 1543 } 1544#endif 1545} 1546 1547/* 1548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1549% % 1550% % 1551% % 1552% L o c a l e U p p e r % 1553% % 1554% % 1555% % 1556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1557% 1558% LocaleUpper() transforms all of the characters in the supplied 1559% null-terminated string, changing all lowercase letters to uppercase. 1560% 1561% The format of the LocaleUpper method is: 1562% 1563% void LocaleUpper(char *string) 1564% 1565% A description of each parameter follows: 1566% 1567% o string: A pointer to the string to convert to upper-case Locale. 1568% 1569*/ 1570MagickExport void LocaleUpper(char *string) 1571{ 1572 register char 1573 *q; 1574 1575 assert(string != (char *) NULL); 1576 for (q=string; *q != '\0'; q++) 1577 *q=(char) toupper((int) *q); 1578} 1579 1580/* 1581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1582% % 1583% % 1584% % 1585+ L o c a l e C o m p o n e n t G e n e s i s % 1586% % 1587% % 1588% % 1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1590% 1591% LocaleComponentGenesis() instantiates the locale component. 1592% 1593% The format of the LocaleComponentGenesis method is: 1594% 1595% MagickBooleanType LocaleComponentGenesis(void) 1596% 1597*/ 1598MagickPrivate MagickBooleanType LocaleComponentGenesis(void) 1599{ 1600 if (locale_semaphore == (SemaphoreInfo *) NULL) 1601 locale_semaphore=AcquireSemaphoreInfo(); 1602 return(MagickTrue); 1603} 1604 1605/* 1606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1607% % 1608% % 1609% % 1610+ L o c a l e C o m p o n e n t T e r m i n u s % 1611% % 1612% % 1613% % 1614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1615% 1616% LocaleComponentTerminus() destroys the locale component. 1617% 1618% The format of the LocaleComponentTerminus method is: 1619% 1620% LocaleComponentTerminus(void) 1621% 1622*/ 1623MagickPrivate void LocaleComponentTerminus(void) 1624{ 1625 if (locale_semaphore == (SemaphoreInfo *) NULL) 1626 ActivateSemaphoreInfo(&locale_semaphore); 1627 LockSemaphoreInfo(locale_semaphore); 1628 if (locale_cache != (SplayTreeInfo *) NULL) 1629 locale_cache=DestroySplayTree(locale_cache); 1630#if defined(MAGICKCORE_LOCALE_SUPPORT) 1631 DestroyCLocale(); 1632#endif 1633 UnlockSemaphoreInfo(locale_semaphore); 1634 RelinquishSemaphoreInfo(&locale_semaphore); 1635} 1636