MagickCore  6.7.5
locale.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                  L       OOO    CCCC   AAA   L      EEEEE                   %
00007 %                  L      O   O  C      A   A  L      E                       %
00008 %                  L      O   O  C      AAAAA  L      EEE                     %
00009 %                  L      O   O  C      A   A  L      E                       %
00010 %                  LLLLL   OOO    CCCC  A   A  LLLLL  EEEEE                   %
00011 %                                                                             %
00012 %                                                                             %
00013 %                      MagickCore Image Locale Methods                        %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 2003                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "MagickCore/studio.h"
00043 #include "MagickCore/blob.h"
00044 #include "MagickCore/client.h"
00045 #include "MagickCore/configure.h"
00046 #include "MagickCore/exception.h"
00047 #include "MagickCore/exception-private.h"
00048 #include "MagickCore/hashmap.h"
00049 #include "MagickCore/locale_.h"
00050 #include "MagickCore/locale-private.h"
00051 #include "MagickCore/log.h"
00052 #include "MagickCore/memory_.h"
00053 #include "MagickCore/semaphore.h"
00054 #include "MagickCore/splay-tree.h"
00055 #include "MagickCore/string_.h"
00056 #include "MagickCore/string-private.h"
00057 #include "MagickCore/token.h"
00058 #include "MagickCore/utility.h"
00059 #include "MagickCore/utility-private.h"
00060 #include "MagickCore/xml-tree.h"
00061 
00062 /*
00063   Define declarations.
00064 */
00065 #define LocaleFilename  "locale.xml"
00066 #define MaxRecursionDepth  200
00067 
00068 /*
00069   Typedef declarations.
00070 */
00071 #if defined(__CYGWIN__)
00072 typedef struct _locale_t *locale_t;
00073 #endif
00074 
00075 /*
00076   Static declarations.
00077 */
00078 static const char
00079   *LocaleMap =
00080     "<?xml version=\"1.0\"?>"
00081     "<localemap>"
00082     "  <locale name=\"C\">"
00083     "    <Exception>"
00084     "     <Message name=\"\">"
00085     "     </Message>"
00086     "    </Exception>"
00087     "  </locale>"
00088     "</localemap>";
00089 
00090 static SemaphoreInfo
00091   *locale_semaphore = (SemaphoreInfo *) NULL;
00092 
00093 static SplayTreeInfo
00094   *locale_list = (SplayTreeInfo *) NULL;
00095 
00096 #if defined(MAGICKCORE_HAVE_STRTOD_L)
00097 static volatile locale_t
00098   c_locale = (locale_t) NULL;
00099 #endif
00100 
00101 static volatile MagickBooleanType
00102   instantiate_locale = MagickFalse;
00103 
00104 /*
00105   Forward declarations.
00106 */
00107 static MagickBooleanType
00108   InitializeLocaleList(ExceptionInfo *),
00109   LoadLocaleLists(const char *,const char *,ExceptionInfo *);
00110 
00111 #if defined(MAGICKCORE_HAVE_STRTOD_L)
00112 /*
00113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00114 %                                                                             %
00115 %                                                                             %
00116 %                                                                             %
00117 +   A c q u i r e C L o c a l e                                               %
00118 %                                                                             %
00119 %                                                                             %
00120 %                                                                             %
00121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00122 %
00123 %  AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
00124 %  errno set if it cannot be acquired.
00125 %
00126 %  The format of the AcquireCLocale method is:
00127 %
00128 %      locale_t AcquireCLocale(void)
00129 %
00130 */
00131 static locale_t AcquireCLocale(void)
00132 {
00133 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
00134   if (c_locale == (locale_t) NULL)
00135     c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
00136 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
00137   if (c_locale == (locale_t) NULL)
00138     c_locale=_create_locale(LC_ALL,"C");
00139 #endif
00140   return(c_locale);
00141 }
00142 #endif
00143 
00144 #if defined(MAGICKCORE_HAVE_STRTOD_L)
00145 /*
00146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00147 %                                                                             %
00148 %                                                                             %
00149 %                                                                             %
00150 +   D e s t r o y C L o c a l e                                               %
00151 %                                                                             %
00152 %                                                                             %
00153 %                                                                             %
00154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00155 %
00156 %  DestroyCLocale() releases the resources allocated for a locale object
00157 %  returned by a call to the AcquireCLocale() method.
00158 %
00159 %  The format of the DestroyCLocale method is:
00160 %
00161 %      void DestroyCLocale(void)
00162 %
00163 */
00164 static void DestroyCLocale(void)
00165 {
00166 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
00167   if (c_locale != (locale_t) NULL)
00168     freelocale(c_locale);
00169 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
00170   if (c_locale != (locale_t) NULL)
00171     _free_locale(c_locale);
00172 #endif
00173   c_locale=(locale_t) NULL;
00174 }
00175 #endif
00176 
00177 /*
00178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00179 %                                                                             %
00180 %                                                                             %
00181 %                                                                             %
00182 %   D e s t r o y L o c a l e O p t i o n s                                   %
00183 %                                                                             %
00184 %                                                                             %
00185 %                                                                             %
00186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00187 %
00188 %  DestroyLocaleOptions() releases memory associated with an locale
00189 %  messages.
00190 %
00191 %  The format of the DestroyProfiles method is:
00192 %
00193 %      LinkedListInfo *DestroyLocaleOptions(Image *image)
00194 %
00195 %  A description of each parameter follows:
00196 %
00197 %    o image: the image.
00198 %
00199 */
00200 
00201 static void *DestroyOptions(void *message)
00202 {
00203   return(DestroyStringInfo((StringInfo *) message));
00204 }
00205 
00206 MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
00207 {
00208   assert(messages != (LinkedListInfo *) NULL);
00209   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00210   return(DestroyLinkedList(messages,DestroyOptions));
00211 }
00212 
00213 /*
00214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00215 %                                                                             %
00216 %                                                                             %
00217 %                                                                             %
00218 +  F o r m a t L o c a l e F i l e                                            %
00219 %                                                                             %
00220 %                                                                             %
00221 %                                                                             %
00222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00223 %
00224 %  FormatLocaleFile() prints formatted output of a variable argument list to a
00225 %  file in the "C" locale.
00226 %
00227 %  The format of the FormatLocaleFile method is:
00228 %
00229 %      ssize_t FormatLocaleFile(FILE *file,const char *format,...)
00230 %
00231 %  A description of each parameter follows.
00232 %
00233 %   o file:  the file.
00234 %
00235 %   o format:  A file describing the format to use to write the remaining
00236 %     arguments.
00237 %
00238 */
00239 
00240 MagickPrivate ssize_t FormatLocaleFileList(FILE *file,
00241   const char *restrict format,va_list operands)
00242 {
00243   ssize_t
00244     n;
00245 
00246 #if defined(MAGICKCORE_HAVE_VFPRINTF_L)
00247   {
00248     locale_t
00249       locale;
00250 
00251     locale=AcquireCLocale();
00252     if (locale == (locale_t) NULL)
00253       n=(ssize_t) vfprintf(file,format,operands);
00254     else
00255 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
00256       n=(ssize_t) vfprintf_l(file,format,locale,operands);
00257 #else
00258       n=(ssize_t) vfprintf_l(file,locale,format,operands);
00259 #endif
00260   }
00261 #else
00262 #if defined(MAGICKCORE_HAVE_USELOCALE)
00263   {
00264     locale_t
00265       locale,
00266       previous_locale;
00267 
00268     locale=AcquireCLocale();
00269     if (locale == (locale_t) NULL)
00270       n=(ssize_t) vfprintf(file,format,operands);
00271     else
00272       {
00273         previous_locale=uselocale(locale);
00274         n=(ssize_t) vfprintf(file,format,operands);
00275         uselocale(previous_locale);
00276       }
00277   }
00278 #else
00279   n=(ssize_t) vfprintf(file,format,operands);
00280 #endif
00281 #endif
00282   return(n);
00283 }
00284 
00285 MagickExport ssize_t FormatLocaleFile(FILE *file,const char *restrict format,
00286   ...)
00287 {
00288   ssize_t
00289     n;
00290 
00291   va_list
00292     operands;
00293 
00294   va_start(operands,format);
00295   n=FormatLocaleFileList(file,format,operands);
00296   va_end(operands);
00297   return(n);
00298 }
00299 
00300 /*
00301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00302 %                                                                             %
00303 %                                                                             %
00304 %                                                                             %
00305 +  F o r m a t L o c a l e S t r i n g                                        %
00306 %                                                                             %
00307 %                                                                             %
00308 %                                                                             %
00309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00310 %
00311 %  FormatLocaleString() prints formatted output of a variable argument list to
00312 %  a string buffer in the "C" locale.
00313 %
00314 %  The format of the FormatLocaleString method is:
00315 %
00316 %      ssize_t FormatLocaleString(char *string,const size_t length,
00317 %        const char *format,...)
00318 %
00319 %  A description of each parameter follows.
00320 %
00321 %   o string:  FormatLocaleString() returns the formatted string in this
00322 %     character buffer.
00323 %
00324 %   o length: the maximum length of the string.
00325 %
00326 %   o format:  A string describing the format to use to write the remaining
00327 %     arguments.
00328 %
00329 */
00330 
00331 MagickPrivate ssize_t FormatLocaleStringList(char *restrict string,
00332   const size_t length,const char *restrict format,va_list operands)
00333 {
00334   ssize_t
00335     n;
00336 
00337 #if defined(MAGICKCORE_HAVE_VSNPRINTF_L)
00338   {
00339     locale_t
00340       locale;
00341 
00342     locale=AcquireCLocale();
00343     if (locale == (locale_t) NULL)
00344       n=(ssize_t) vsnprintf(string,length,format,operands);
00345     else
00346 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
00347       n=(ssize_t) vsnprintf_l(string,length,format,locale,operands);
00348 #else
00349       n=(ssize_t) vsnprintf_l(string,length,locale,format,operands);
00350 #endif
00351   }
00352 #elif defined(MAGICKCORE_HAVE_VSNPRINTF)
00353 #if defined(MAGICKCORE_HAVE_USELOCALE)
00354   {
00355     locale_t
00356       locale,
00357       previous_locale;
00358 
00359     locale=AcquireCLocale();
00360     if (locale == (locale_t) NULL)
00361       n=(ssize_t) vsnprintf(string,length,format,operands);
00362     else
00363       {
00364         previous_locale=uselocale(locale);
00365         n=(ssize_t) vsnprintf(string,length,format,operands);
00366         uselocale(previous_locale);
00367       }
00368   }
00369 #else
00370   n=(ssize_t) vsnprintf(string,length,format,operands);
00371 #endif
00372 #else
00373   n=(ssize_t) vsprintf(string,format,operands);
00374 #endif
00375   if (n < 0)
00376     string[length-1]='\0';
00377   return(n);
00378 }
00379 
00380 MagickExport ssize_t FormatLocaleString(char *restrict string,
00381   const size_t length,const char *restrict format,...)
00382 {
00383   ssize_t
00384     n;
00385 
00386   va_list
00387     operands;
00388 
00389   va_start(operands,format);
00390   n=FormatLocaleStringList(string,length,format,operands);
00391   va_end(operands);
00392   return(n);
00393 }
00394 
00395 /*
00396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00397 %                                                                             %
00398 %                                                                             %
00399 %                                                                             %
00400 +   G e t L o c a l e I n f o _                                               %
00401 %                                                                             %
00402 %                                                                             %
00403 %                                                                             %
00404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00405 %
00406 %  GetLocaleInfo_() searches the locale list for the specified tag and if
00407 %  found returns attributes for that element.
00408 %
00409 %  The format of the GetLocaleInfo method is:
00410 %
00411 %      const LocaleInfo *GetLocaleInfo_(const char *tag,
00412 %        ExceptionInfo *exception)
00413 %
00414 %  A description of each parameter follows:
00415 %
00416 %    o tag: the locale tag.
00417 %
00418 %    o exception: return any errors or warnings in this structure.
00419 %
00420 */
00421 MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
00422   ExceptionInfo *exception)
00423 {
00424   assert(exception != (ExceptionInfo *) NULL);
00425   if ((locale_list == (SplayTreeInfo *) NULL) ||
00426       (instantiate_locale == MagickFalse))
00427     if (InitializeLocaleList(exception) == MagickFalse)
00428       return((const LocaleInfo *) NULL);
00429   if ((locale_list == (SplayTreeInfo *) NULL) ||
00430       (GetNumberOfNodesInSplayTree(locale_list) == 0))
00431     return((const LocaleInfo *) NULL);
00432   if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
00433     {
00434       ResetSplayTreeIterator(locale_list);
00435       return((const LocaleInfo *) GetNextValueInSplayTree(locale_list));
00436     }
00437   return((const LocaleInfo *) GetValueFromSplayTree(locale_list,tag));
00438 }
00439 
00440 /*
00441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00442 %                                                                             %
00443 %                                                                             %
00444 %                                                                             %
00445 %   G e t L o c a l e I n f o L i s t                                         %
00446 %                                                                             %
00447 %                                                                             %
00448 %                                                                             %
00449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00450 %
00451 %  GetLocaleInfoList() returns any locale messages that match the
00452 %  specified pattern.
00453 %
00454 %  The format of the GetLocaleInfoList function is:
00455 %
00456 %      const LocaleInfo **GetLocaleInfoList(const char *pattern,
00457 %        size_t *number_messages,ExceptionInfo *exception)
00458 %
00459 %  A description of each parameter follows:
00460 %
00461 %    o pattern: Specifies a pointer to a text string containing a pattern.
00462 %
00463 %    o number_messages:  This integer returns the number of locale messages in
00464 %    the list.
00465 %
00466 %    o exception: return any errors or warnings in this structure.
00467 %
00468 */
00469 
00470 #if defined(__cplusplus) || defined(c_plusplus)
00471 extern "C" {
00472 #endif
00473 
00474 static int LocaleInfoCompare(const void *x,const void *y)
00475 {
00476   const LocaleInfo
00477     **p,
00478     **q;
00479 
00480   p=(const LocaleInfo **) x,
00481   q=(const LocaleInfo **) y;
00482   if (LocaleCompare((*p)->path,(*q)->path) == 0)
00483     return(LocaleCompare((*p)->tag,(*q)->tag));
00484   return(LocaleCompare((*p)->path,(*q)->path));
00485 }
00486 
00487 #if defined(__cplusplus) || defined(c_plusplus)
00488 }
00489 #endif
00490 
00491 MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
00492   size_t *number_messages,ExceptionInfo *exception)
00493 {
00494   const LocaleInfo
00495     **messages;
00496 
00497   register const LocaleInfo
00498     *p;
00499 
00500   register ssize_t
00501     i;
00502 
00503   /*
00504     Allocate locale list.
00505   */
00506   assert(pattern != (char *) NULL);
00507   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
00508   assert(number_messages != (size_t *) NULL);
00509   *number_messages=0;
00510   p=GetLocaleInfo_("*",exception);
00511   if (p == (const LocaleInfo *) NULL)
00512     return((const LocaleInfo **) NULL);
00513   messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
00514     GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
00515   if (messages == (const LocaleInfo **) NULL)
00516     return((const LocaleInfo **) NULL);
00517   /*
00518     Generate locale list.
00519   */
00520   LockSemaphoreInfo(locale_semaphore);
00521   ResetSplayTreeIterator(locale_list);
00522   p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
00523   for (i=0; p != (const LocaleInfo *) NULL; )
00524   {
00525     if ((p->stealth == MagickFalse) &&
00526         (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
00527       messages[i++]=p;
00528     p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
00529   }
00530   UnlockSemaphoreInfo(locale_semaphore);
00531   qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
00532   messages[i]=(LocaleInfo *) NULL;
00533   *number_messages=(size_t) i;
00534   return(messages);
00535 }
00536 
00537 /*
00538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00539 %                                                                             %
00540 %                                                                             %
00541 %                                                                             %
00542 %   G e t L o c a l e L i s t                                                 %
00543 %                                                                             %
00544 %                                                                             %
00545 %                                                                             %
00546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00547 %
00548 %  GetLocaleList() returns any locale messages that match the specified
00549 %  pattern.
00550 %
00551 %  The format of the GetLocaleList function is:
00552 %
00553 %      char **GetLocaleList(const char *pattern,size_t *number_messages,
00554 %        Exceptioninfo *exception)
00555 %
00556 %  A description of each parameter follows:
00557 %
00558 %    o pattern: Specifies a pointer to a text string containing a pattern.
00559 %
00560 %    o number_messages:  This integer returns the number of messages in the
00561 %      list.
00562 %
00563 %    o exception: return any errors or warnings in this structure.
00564 %
00565 */
00566 
00567 #if defined(__cplusplus) || defined(c_plusplus)
00568 extern "C" {
00569 #endif
00570 
00571 static int LocaleTagCompare(const void *x,const void *y)
00572 {
00573   register char
00574     **p,
00575     **q;
00576 
00577   p=(char **) x;
00578   q=(char **) y;
00579   return(LocaleCompare(*p,*q));
00580 }
00581 
00582 #if defined(__cplusplus) || defined(c_plusplus)
00583 }
00584 #endif
00585 
00586 MagickExport char **GetLocaleList(const char *pattern,
00587   size_t *number_messages,ExceptionInfo *exception)
00588 {
00589   char
00590     **messages;
00591 
00592   register const LocaleInfo
00593     *p;
00594 
00595   register ssize_t
00596     i;
00597 
00598   /*
00599     Allocate locale list.
00600   */
00601   assert(pattern != (char *) NULL);
00602   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
00603   assert(number_messages != (size_t *) NULL);
00604   *number_messages=0;
00605   p=GetLocaleInfo_("*",exception);
00606   if (p == (const LocaleInfo *) NULL)
00607     return((char **) NULL);
00608   messages=(char **) AcquireQuantumMemory((size_t)
00609     GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
00610   if (messages == (char **) NULL)
00611     return((char **) NULL);
00612   LockSemaphoreInfo(locale_semaphore);
00613   p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
00614   for (i=0; p != (const LocaleInfo *) NULL; )
00615   {
00616     if ((p->stealth == MagickFalse) &&
00617         (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
00618       messages[i++]=ConstantString(p->tag);
00619     p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
00620   }
00621   UnlockSemaphoreInfo(locale_semaphore);
00622   qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
00623   messages[i]=(char *) NULL;
00624   *number_messages=(size_t) i;
00625   return(messages);
00626 }
00627 
00628 /*
00629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00630 %                                                                             %
00631 %                                                                             %
00632 %                                                                             %
00633 %   G e t L o c a l e M e s s a g e                                           %
00634 %                                                                             %
00635 %                                                                             %
00636 %                                                                             %
00637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00638 %
00639 %  GetLocaleMessage() returns a message in the current locale that matches the
00640 %  supplied tag.
00641 %
00642 %  The format of the GetLocaleMessage method is:
00643 %
00644 %      const char *GetLocaleMessage(const char *tag)
00645 %
00646 %  A description of each parameter follows:
00647 %
00648 %    o tag: Return a message that matches this tag in the current locale.
00649 %
00650 */
00651 MagickExport const char *GetLocaleMessage(const char *tag)
00652 {
00653   char
00654     name[MaxTextExtent];
00655 
00656   const LocaleInfo
00657     *locale_info;
00658 
00659   ExceptionInfo
00660     *exception;
00661 
00662   if ((tag == (const char *) NULL) || (*tag == '\0'))
00663     return(tag);
00664   exception=AcquireExceptionInfo();
00665   (void) FormatLocaleString(name,MaxTextExtent,"%s/",tag);
00666   locale_info=GetLocaleInfo_(name,exception);
00667   exception=DestroyExceptionInfo(exception);
00668   if (locale_info != (const LocaleInfo *) NULL)
00669     return(locale_info->message);
00670   return(tag);
00671 }
00672 
00673 /*
00674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00675 %                                                                             %
00676 %                                                                             %
00677 %                                                                             %
00678 %  G e t L o c a l e O p t i o n s                                            %
00679 %                                                                             %
00680 %                                                                             %
00681 %                                                                             %
00682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00683 %
00684 %  GetLocaleOptions() returns any Magick configuration messages associated
00685 %  with the specified filename.
00686 %
00687 %  The format of the GetLocaleOptions method is:
00688 %
00689 %      LinkedListInfo *GetLocaleOptions(const char *filename,
00690 %        ExceptionInfo *exception)
00691 %
00692 %  A description of each parameter follows:
00693 %
00694 %    o filename: the locale file tag.
00695 %
00696 %    o exception: return any errors or warnings in this structure.
00697 %
00698 */
00699 MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
00700   ExceptionInfo *exception)
00701 {
00702   char
00703     path[MaxTextExtent];
00704 
00705   const char
00706     *element;
00707 
00708   LinkedListInfo
00709     *messages,
00710     *paths;
00711 
00712   StringInfo
00713     *xml;
00714 
00715   assert(filename != (const char *) NULL);
00716   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
00717   assert(exception != (ExceptionInfo *) NULL);
00718   (void) CopyMagickString(path,filename,MaxTextExtent);
00719   /*
00720     Load XML from configuration files to linked-list.
00721   */
00722   messages=NewLinkedList(0);
00723   paths=GetConfigurePaths(filename,exception);
00724   if (paths != (LinkedListInfo *) NULL)
00725     {
00726       ResetLinkedListIterator(paths);
00727       element=(const char *) GetNextValueInLinkedList(paths);
00728       while (element != (const char *) NULL)
00729       {
00730         (void) FormatLocaleString(path,MaxTextExtent,"%s%s",element,filename);
00731         (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
00732           "Searching for locale file: \"%s\"",path);
00733         xml=ConfigureFileToStringInfo(path);
00734         if (xml != (StringInfo *) NULL)
00735           (void) AppendValueToLinkedList(messages,xml);
00736         element=(const char *) GetNextValueInLinkedList(paths);
00737       }
00738       paths=DestroyLinkedList(paths,RelinquishMagickMemory);
00739     }
00740 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
00741   {
00742     char
00743       *blob;
00744 
00745     blob=(char *) NTResourceToBlob(filename);
00746     if (blob != (char *) NULL)
00747       {
00748         xml=AcquireStringInfo(0);
00749         SetStringInfoLength(xml,strlen(blob)+1);
00750         SetStringInfoDatum(xml,blob);
00751         SetStringInfoPath(xml,filename);
00752         (void) AppendValueToLinkedList(messages,xml);
00753       }
00754   }
00755 #endif
00756   ResetLinkedListIterator(messages);
00757   return(messages);
00758 }
00759 
00760 /*
00761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00762 %                                                                             %
00763 %                                                                             %
00764 %                                                                             %
00765 %   G e t L o c a l e V a l u e                                               %
00766 %                                                                             %
00767 %                                                                             %
00768 %                                                                             %
00769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00770 %
00771 %  GetLocaleValue() returns the message associated with the locale info.
00772 %
00773 %  The format of the GetLocaleValue method is:
00774 %
00775 %      const char *GetLocaleValue(const LocaleInfo *locale_info)
00776 %
00777 %  A description of each parameter follows:
00778 %
00779 %    o locale_info:  The locale info.
00780 %
00781 */
00782 MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
00783 {
00784   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00785   assert(locale_info != (LocaleInfo *) NULL);
00786   assert(locale_info->signature == MagickSignature);
00787   return(locale_info->message);
00788 }
00789 
00790 /*
00791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00792 %                                                                             %
00793 %                                                                             %
00794 %                                                                             %
00795 +   I n i t i a l i z e L o c a l e L i s t                                   %
00796 %                                                                             %
00797 %                                                                             %
00798 %                                                                             %
00799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00800 %
00801 %  InitializeLocaleList() initializes the locale list.
00802 %
00803 %  The format of the InitializeLocaleList method is:
00804 %
00805 %      MagickBooleanType InitializeLocaleList(ExceptionInfo *exception)
00806 %
00807 %  A description of each parameter follows.
00808 %
00809 %    o exception: return any errors or warnings in this structure.
00810 %
00811 */
00812 static MagickBooleanType InitializeLocaleList(ExceptionInfo *exception)
00813 {
00814   if ((locale_list == (SplayTreeInfo *) NULL) &&
00815       (instantiate_locale == MagickFalse))
00816     {
00817       if (locale_semaphore == (SemaphoreInfo *) NULL)
00818         AcquireSemaphoreInfo(&locale_semaphore);
00819       LockSemaphoreInfo(locale_semaphore);
00820       if ((locale_list == (SplayTreeInfo *) NULL) &&
00821           (instantiate_locale == MagickFalse))
00822         {
00823           char
00824             *locale;
00825 
00826           register const char
00827             *p;
00828 
00829           locale=(char *) NULL;
00830           p=setlocale(LC_CTYPE,(const char *) NULL);
00831           if (p != (const char *) NULL)
00832             locale=ConstantString(p);
00833           if (locale == (char *) NULL)
00834             locale=GetEnvironmentValue("LC_ALL");
00835           if (locale == (char *) NULL)
00836             locale=GetEnvironmentValue("LC_MESSAGES");
00837           if (locale == (char *) NULL)
00838             locale=GetEnvironmentValue("LC_CTYPE");
00839           if (locale == (char *) NULL)
00840             locale=GetEnvironmentValue("LANG");
00841           if (locale == (char *) NULL)
00842             locale=ConstantString("C");
00843           (void) LoadLocaleLists(LocaleFilename,locale,exception);
00844           locale=DestroyString(locale);
00845           instantiate_locale=MagickTrue;
00846         }
00847       UnlockSemaphoreInfo(locale_semaphore);
00848     }
00849   return(locale_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
00850 }
00851 
00852 /*
00853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00854 %                                                                             %
00855 %                                                                             %
00856 %                                                                             %
00857 +   I n t e r p r e t L o c a l e V a l u e                                   %
00858 %                                                                             %
00859 %                                                                             %
00860 %                                                                             %
00861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00862 %
00863 %  InterpretLocaleValue() interprets the string as a floating point number in
00864 %  the "C" locale and returns its value as a double. If sentinal is not a null
00865 %  pointer, the method also sets the value pointed by sentinal to point to the
00866 %  first character after the number.
00867 %
00868 %  The format of the InterpretLocaleValue method is:
00869 %
00870 %      double InterpretLocaleValue(const char *value,char **sentinal)
00871 %
00872 %  A description of each parameter follows:
00873 %
00874 %    o value: the string value.
00875 %
00876 %    o sentinal:  if sentinal is not NULL, a pointer to the character after the
00877 %      last character used in the conversion is stored in the location
00878 %      referenced by sentinal.
00879 %
00880 */
00881 MagickExport double InterpretLocaleValue(const char *restrict string,
00882   char **restrict sentinal)
00883 {
00884   char
00885     *q;
00886 
00887   double
00888     value;
00889 
00890   if ((*string == '0') && ((string[1] | 0x20)=='x'))
00891     value=(double) strtoul(string,&q,16);
00892   else
00893     {
00894 #if defined(MAGICKCORE_HAVE_STRTOD_L)
00895       locale_t
00896         locale;
00897 
00898       locale=AcquireCLocale();
00899       if (locale == (locale_t) NULL)
00900         value=strtod(string,&q);
00901       else
00902         value=strtod_l(string,&q,locale);
00903 #else
00904       value=strtod(string,&q);
00905 #endif
00906     }
00907   if (sentinal != (char **) NULL)
00908     *sentinal=q;
00909   return(value);
00910 }
00911 
00912 /*
00913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00914 %                                                                             %
00915 %                                                                             %
00916 %                                                                             %
00917 %  L i s t L o c a l e I n f o                                                %
00918 %                                                                             %
00919 %                                                                             %
00920 %                                                                             %
00921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00922 %
00923 %  ListLocaleInfo() lists the locale info to a file.
00924 %
00925 %  The format of the ListLocaleInfo method is:
00926 %
00927 %      MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
00928 %
00929 %  A description of each parameter follows.
00930 %
00931 %    o file:  An pointer to a FILE.
00932 %
00933 %    o exception: return any errors or warnings in this structure.
00934 %
00935 */
00936 MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
00937   ExceptionInfo *exception)
00938 {
00939   const char
00940     *path;
00941 
00942   const LocaleInfo
00943     **locale_info;
00944 
00945   register ssize_t
00946     i;
00947 
00948   size_t
00949     number_messages;
00950 
00951   if (file == (const FILE *) NULL)
00952     file=stdout;
00953   number_messages=0;
00954   locale_info=GetLocaleInfoList("*",&number_messages,exception);
00955   if (locale_info == (const LocaleInfo **) NULL)
00956     return(MagickFalse);
00957   path=(const char *) NULL;
00958   for (i=0; i < (ssize_t) number_messages; i++)
00959   {
00960     if (locale_info[i]->stealth != MagickFalse)
00961       continue;
00962     if ((path == (const char *) NULL) ||
00963         (LocaleCompare(path,locale_info[i]->path) != 0))
00964       {
00965         if (locale_info[i]->path != (char *) NULL)
00966           (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
00967         (void) FormatLocaleFile(file,"Tag/Message\n");
00968         (void) FormatLocaleFile(file,
00969           "-------------------------------------------------"
00970           "------------------------------\n");
00971       }
00972     path=locale_info[i]->path;
00973     (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
00974     if (locale_info[i]->message != (char *) NULL)
00975       (void) FormatLocaleFile(file,"  %s",locale_info[i]->message);
00976     (void) FormatLocaleFile(file,"\n");
00977   }
00978   (void) fflush(file);
00979   locale_info=(const LocaleInfo **)
00980     RelinquishMagickMemory((void *) locale_info);
00981   return(MagickTrue);
00982 }
00983 
00984 /*
00985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00986 %                                                                             %
00987 %                                                                             %
00988 %                                                                             %
00989 +   L o a d L o c a l e L i s t                                               %
00990 %                                                                             %
00991 %                                                                             %
00992 %                                                                             %
00993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00994 %
00995 %  LoadLocaleList() loads the locale configuration file which provides a mapping
00996 %  between locale attributes and a locale name.
00997 %
00998 %  The format of the LoadLocaleList method is:
00999 %
01000 %      MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
01001 %        const size_t depth,ExceptionInfo *exception)
01002 %
01003 %  A description of each parameter follows:
01004 %
01005 %    o xml:  The locale list in XML format.
01006 %
01007 %    o filename:  The locale list filename.
01008 %
01009 %    o depth: depth of <include /> statements.
01010 %
01011 %    o exception: return any errors or warnings in this structure.
01012 %
01013 */
01014 
01015 static void ChopLocaleComponents(char *path,const size_t components)
01016 {
01017   register char
01018     *p;
01019 
01020   ssize_t
01021     count;
01022 
01023   if (*path == '\0')
01024     return;
01025   p=path+strlen(path)-1;
01026   if (*p == '/')
01027     *p='\0';
01028   for (count=0; (count < (ssize_t) components) && (p > path); p--)
01029     if (*p == '/')
01030       {
01031         *p='\0';
01032         count++;
01033       }
01034   if (count < (ssize_t) components)
01035     *path='\0';
01036 }
01037 
01038 static void *DestroyLocaleNode(void *locale_info)
01039 {
01040   register LocaleInfo
01041     *p;
01042 
01043   p=(LocaleInfo *) locale_info;
01044   if (p->path != (char *) NULL)
01045     p->path=DestroyString(p->path);
01046   if (p->tag != (char *) NULL)
01047     p->tag=DestroyString(p->tag);
01048   if (p->message != (char *) NULL)
01049     p->message=DestroyString(p->message);
01050   return(RelinquishMagickMemory(p));
01051 }
01052 
01053 static void LocaleFatalErrorHandler(
01054   const ExceptionType magick_unused(severity),
01055   const char *reason,const char *description)
01056 {
01057   if (reason == (char *) NULL)
01058     return;
01059   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
01060   if (description != (char *) NULL)
01061     (void) FormatLocaleFile(stderr," (%s)",description);
01062   (void) FormatLocaleFile(stderr,".\n");
01063   (void) fflush(stderr);
01064   exit(1);
01065 }
01066 
01067 
01068 static MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
01069   const char *locale,const size_t depth,ExceptionInfo *exception)
01070 {
01071   char
01072     keyword[MaxTextExtent],
01073     message[MaxTextExtent],
01074     tag[MaxTextExtent],
01075     *token;
01076 
01077   const char
01078     *q;
01079 
01080   FatalErrorHandler
01081     fatal_handler;
01082 
01083   LocaleInfo
01084     *locale_info;
01085 
01086   MagickBooleanType
01087     status;
01088 
01089   register char
01090     *p;
01091 
01092   /*
01093     Read the locale configure file.
01094   */
01095   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
01096     "Loading locale configure file \"%s\" ...",filename);
01097   if (xml == (const char *) NULL)
01098     return(MagickFalse);
01099   if (locale_list == (SplayTreeInfo *) NULL)
01100     {
01101       locale_list=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
01102         DestroyLocaleNode);
01103       if (locale_list == (SplayTreeInfo *) NULL)
01104         return(MagickFalse);
01105     }
01106   status=MagickTrue;
01107   locale_info=(LocaleInfo *) NULL;
01108   *tag='\0';
01109   *message='\0';
01110   *keyword='\0';
01111   fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
01112   token=AcquireString(xml);
01113   for (q=(char *) xml; *q != '\0'; )
01114   {
01115     /*
01116       Interpret XML.
01117     */
01118     GetMagickToken(q,&q,token);
01119     if (*token == '\0')
01120       break;
01121     (void) CopyMagickString(keyword,token,MaxTextExtent);
01122     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
01123       {
01124         /*
01125           Doctype element.
01126         */
01127         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
01128         {
01129           GetMagickToken(q,&q,token);
01130           while (isspace((int) ((unsigned char) *q)) != 0)
01131             q++;
01132         }
01133         continue;
01134       }
01135     if (LocaleNCompare(keyword,"<!--",4) == 0)
01136       {
01137         /*
01138           Comment element.
01139         */
01140         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
01141         {
01142           GetMagickToken(q,&q,token);
01143           while (isspace((int) ((unsigned char) *q)) != 0)
01144             q++;
01145         }
01146         continue;
01147       }
01148     if (LocaleCompare(keyword,"<include") == 0)
01149       {
01150         /*
01151           Include element.
01152         */
01153         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
01154         {
01155           (void) CopyMagickString(keyword,token,MaxTextExtent);
01156           GetMagickToken(q,&q,token);
01157           if (*token != '=')
01158             continue;
01159           GetMagickToken(q,&q,token);
01160           if (LocaleCompare(keyword,"locale") == 0)
01161             {
01162               if (LocaleCompare(locale,token) != 0)
01163                 break;
01164               continue;
01165             }
01166           if (LocaleCompare(keyword,"file") == 0)
01167             {
01168               if (depth > 200)
01169                 (void) ThrowMagickException(exception,GetMagickModule(),
01170                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
01171               else
01172                 {
01173                   char
01174                     path[MaxTextExtent],
01175                     *xml;
01176 
01177                   *path='\0';
01178                   GetPathComponent(filename,HeadPath,path);
01179                   if (*path != '\0')
01180                     (void) ConcatenateMagickString(path,DirectorySeparator,
01181                       MaxTextExtent);
01182                   if (*token == *DirectorySeparator)
01183                     (void) CopyMagickString(path,token,MaxTextExtent);
01184                   else
01185                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
01186                   xml=FileToString(path,~0,exception);
01187                   if (xml != (char *) NULL)
01188                     {
01189                       status=LoadLocaleList(xml,path,locale,depth+1,exception);
01190                       xml=(char *) RelinquishMagickMemory(xml);
01191                     }
01192                 }
01193             }
01194         }
01195         continue;
01196       }
01197     if (LocaleCompare(keyword,"<locale") == 0)
01198       {
01199         /*
01200           Locale element.
01201         */
01202         while ((*token != '>') && (*q != '\0'))
01203         {
01204           (void) CopyMagickString(keyword,token,MaxTextExtent);
01205           GetMagickToken(q,&q,token);
01206           if (*token != '=')
01207             continue;
01208           GetMagickToken(q,&q,token);
01209         }
01210         continue;
01211       }
01212     if (LocaleCompare(keyword,"</locale>") == 0)
01213       {
01214         ChopLocaleComponents(tag,1);
01215         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
01216         continue;
01217       }
01218     if (LocaleCompare(keyword,"<localemap>") == 0)
01219       continue;
01220     if (LocaleCompare(keyword,"</localemap>") == 0)
01221       continue;
01222     if (LocaleCompare(keyword,"<message") == 0)
01223       {
01224         /*
01225           Message element.
01226         */
01227         while ((*token != '>') && (*q != '\0'))
01228         {
01229           (void) CopyMagickString(keyword,token,MaxTextExtent);
01230           GetMagickToken(q,&q,token);
01231           if (*token != '=')
01232             continue;
01233           GetMagickToken(q,&q,token);
01234           if (LocaleCompare(keyword,"name") == 0)
01235             {
01236               (void) ConcatenateMagickString(tag,token,MaxTextExtent);
01237               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
01238             }
01239         }
01240         for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
01241         while (isspace((int) ((unsigned char) *p)) != 0)
01242           p++;
01243         q--;
01244         while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
01245           q--;
01246         (void) CopyMagickString(message,p,(size_t) (q-p+2));
01247         locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
01248         if (locale_info == (LocaleInfo *) NULL)
01249           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
01250         (void) ResetMagickMemory(locale_info,0,sizeof(*locale_info));
01251         locale_info->path=ConstantString(filename);
01252         locale_info->tag=ConstantString(tag);
01253         locale_info->message=ConstantString(message);
01254         locale_info->signature=MagickSignature;
01255         status=AddValueToSplayTree(locale_list,locale_info->tag,locale_info);
01256         if (status == MagickFalse)
01257           (void) ThrowMagickException(exception,GetMagickModule(),
01258             ResourceLimitError,"MemoryAllocationFailed","`%s'",
01259             locale_info->tag);
01260         (void) ConcatenateMagickString(tag,message,MaxTextExtent);
01261         (void) ConcatenateMagickString(tag,"\n",MaxTextExtent);
01262         q++;
01263         continue;
01264       }
01265     if (LocaleCompare(keyword,"</message>") == 0)
01266       {
01267         ChopLocaleComponents(tag,2);
01268         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
01269         continue;
01270       }
01271     if (*keyword == '<')
01272       {
01273         /*
01274           Subpath element.
01275         */
01276         if (*(keyword+1) == '?')
01277           continue;
01278         if (*(keyword+1) == '/')
01279           {
01280             ChopLocaleComponents(tag,1);
01281             if (*tag != '\0')
01282               (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
01283             continue;
01284           }
01285         token[strlen(token)-1]='\0';
01286         (void) CopyMagickString(token,token+1,MaxTextExtent);
01287         (void) ConcatenateMagickString(tag,token,MaxTextExtent);
01288         (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
01289         continue;
01290       }
01291     GetMagickToken(q,(const char **) NULL,token);
01292     if (*token != '=')
01293       continue;
01294   }
01295   token=(char *) RelinquishMagickMemory(token);
01296   (void) SetFatalErrorHandler(fatal_handler);
01297   return(status);
01298 }
01299 
01300 /*
01301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01302 %                                                                             %
01303 %                                                                             %
01304 %                                                                             %
01305 %  L o a d L o c a l e L i s t s                                              %
01306 %                                                                             %
01307 %                                                                             %
01308 %                                                                             %
01309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01310 %
01311 %  LoadLocaleList() loads one or more locale configuration file which
01312 %  provides a mapping between locale attributes and a locale tag.
01313 %
01314 %  The format of the LoadLocaleLists method is:
01315 %
01316 %      MagickBooleanType LoadLocaleLists(const char *filename,
01317 %        ExceptionInfo *exception)
01318 %
01319 %  A description of each parameter follows:
01320 %
01321 %    o filename: the font file tag.
01322 %
01323 %    o locale: the actual locale.
01324 %
01325 %    o exception: return any errors or warnings in this structure.
01326 %
01327 */
01328 static MagickBooleanType LoadLocaleLists(const char *filename,
01329   const char *locale,ExceptionInfo *exception)
01330 {
01331 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
01332   return(LoadLocaleList(LocaleMap,"built-in",locale,0,exception));
01333 #else
01334   const StringInfo
01335     *option;
01336 
01337   LinkedListInfo
01338     *options;
01339 
01340   MagickStatusType
01341     status;
01342 
01343   status=MagickFalse;
01344   options=GetLocaleOptions(filename,exception);
01345   option=(const StringInfo *) GetNextValueInLinkedList(options);
01346   while (option != (const StringInfo *) NULL)
01347   {
01348     status|=LoadLocaleList((const char *) GetStringInfoDatum(option),
01349       GetStringInfoPath(option),locale,0,exception);
01350     option=(const StringInfo *) GetNextValueInLinkedList(options);
01351   }
01352   options=DestroyLocaleOptions(options);
01353   if ((locale_list == (SplayTreeInfo *) NULL) ||
01354       (GetNumberOfNodesInSplayTree(locale_list) == 0))
01355     {
01356       options=GetLocaleOptions("english.xml",exception);
01357       option=(const StringInfo *) GetNextValueInLinkedList(options);
01358       while (option != (const StringInfo *) NULL)
01359       {
01360         status|=LoadLocaleList((const char *) GetStringInfoDatum(option),
01361           GetStringInfoPath(option),locale,0,exception);
01362         option=(const StringInfo *) GetNextValueInLinkedList(options);
01363       }
01364       options=DestroyLocaleOptions(options);
01365     }
01366   if ((locale_list == (SplayTreeInfo *) NULL) ||
01367       (GetNumberOfNodesInSplayTree(locale_list) == 0))
01368     status|=LoadLocaleList(LocaleMap,"built-in",locale,0,exception);
01369   return(status != 0 ? MagickTrue : MagickFalse);
01370 #endif
01371 }
01372 
01373 /*
01374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01375 %                                                                             %
01376 %                                                                             %
01377 %                                                                             %
01378 +   L o c a l e C o m p o n e n t G e n e s i s                               %
01379 %                                                                             %
01380 %                                                                             %
01381 %                                                                             %
01382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01383 %
01384 %  LocaleComponentGenesis() instantiates the locale component.
01385 %
01386 %  The format of the LocaleComponentGenesis method is:
01387 %
01388 %      MagickBooleanType LocaleComponentGenesis(void)
01389 %
01390 */
01391 MagickPrivate MagickBooleanType LocaleComponentGenesis(void)
01392 {
01393   AcquireSemaphoreInfo(&locale_semaphore);
01394   return(MagickTrue);
01395 }
01396 
01397 /*
01398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01399 %                                                                             %
01400 %                                                                             %
01401 %                                                                             %
01402 +   L o c a l e C o m p o n e n t T e r m i n u s                             %
01403 %                                                                             %
01404 %                                                                             %
01405 %                                                                             %
01406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01407 %
01408 %  LocaleComponentTerminus() destroys the locale component.
01409 %
01410 %  The format of the LocaleComponentTerminus method is:
01411 %
01412 %      LocaleComponentTerminus(void)
01413 %
01414 */
01415 MagickPrivate void LocaleComponentTerminus(void)
01416 {
01417   if (locale_semaphore == (SemaphoreInfo *) NULL)
01418     AcquireSemaphoreInfo(&locale_semaphore);
01419   LockSemaphoreInfo(locale_semaphore);
01420 #if defined(MAGICKCORE_HAVE_STRTOD_L)
01421   DestroyCLocale();
01422 #endif
01423   instantiate_locale=MagickFalse;
01424   UnlockSemaphoreInfo(locale_semaphore);
01425   DestroySemaphoreInfo(&locale_semaphore);
01426 }