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