blob: acd6559885978464b2addec9caf790b4c19eff23 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 2003 %
18% %
19% %
Cristyf6ff9ea2016-12-05 09:53:35 -050020% Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% %
Cristyf19d4142017-04-24 11:34:30 -040026% https://www.imagemagick.org/script/license.php %
cristy3ed852e2009-09-05 21:47:34 +000027% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/client.h"
45#include "MagickCore/configure.h"
46#include "MagickCore/exception.h"
47#include "MagickCore/exception-private.h"
dirk007e9252015-01-15 21:02:57 +000048#include "MagickCore/image-private.h"
dirkabed7e22016-01-31 17:10:21 +010049#include "MagickCore/linked-list.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/locale_.h"
cristy5ff4eaf2011-09-03 01:38:02 +000051#include "MagickCore/locale-private.h"
cristy4c08aed2011-07-01 19:47:50 +000052#include "MagickCore/log.h"
53#include "MagickCore/memory_.h"
cristyd2d11ec2012-03-28 13:53:49 +000054#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000055#include "MagickCore/semaphore.h"
56#include "MagickCore/splay-tree.h"
57#include "MagickCore/string_.h"
cristy7832dc22011-09-05 01:21:53 +000058#include "MagickCore/string-private.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/token.h"
60#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000061#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000062#include "MagickCore/xml-tree.h"
cristy3291f512014-03-16 22:16:22 +000063#include "MagickCore/xml-tree-private.h"
cristy3ed852e2009-09-05 21:47:34 +000064
65/*
66 Define declarations.
67*/
cristyc6a82902015-05-17 12:49:39 +000068#if defined(MAGICKCORE_HAVE_NEWLOCALE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
69# define MAGICKCORE_LOCALE_SUPPORT
70#endif
cristy3ed852e2009-09-05 21:47:34 +000071#define LocaleFilename "locale.xml"
72#define MaxRecursionDepth 200
73
74/*
75 Static declarations.
76*/
77static const char
78 *LocaleMap =
79 "<?xml version=\"1.0\"?>"
80 "<localemap>"
81 " <locale name=\"C\">"
82 " <Exception>"
83 " <Message name=\"\">"
84 " </Message>"
85 " </Exception>"
86 " </locale>"
87 "</localemap>";
88
89static SemaphoreInfo
90 *locale_semaphore = (SemaphoreInfo *) NULL;
91
92static SplayTreeInfo
cristy86e5ac92014-03-16 19:27:39 +000093 *locale_cache = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +000094
cristyc6a82902015-05-17 12:49:39 +000095#if defined(MAGICKCORE_LOCALE_SUPPORT)
cristya20c9042011-05-19 13:22:18 +000096static volatile locale_t
cristyb51dff52011-05-19 16:55:47 +000097 c_locale = (locale_t) NULL;
cristyc6a82902015-05-17 12:49:39 +000098#endif
cristy3ed852e2009-09-05 21:47:34 +000099
100/*
101 Forward declarations.
102*/
103static MagickBooleanType
cristy904e5912014-03-15 19:53:14 +0000104 IsLocaleTreeInstantiated(ExceptionInfo *),
cristycd2cd182014-03-18 12:10:55 +0000105 LoadLocaleCache(SplayTreeInfo *,const char *,const char *,const char *,
106 const size_t,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000107
cristyc6a82902015-05-17 12:49:39 +0000108#if defined(MAGICKCORE_LOCALE_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000109/*
110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111% %
112% %
113% %
cristyb51dff52011-05-19 16:55:47 +0000114+ A c q u i r e C L o c a l e %
cristya20c9042011-05-19 13:22:18 +0000115% %
116% %
117% %
118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119%
cristyb51dff52011-05-19 16:55:47 +0000120% AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
cristya20c9042011-05-19 13:22:18 +0000121% errno set if it cannot be acquired.
122%
cristyb51dff52011-05-19 16:55:47 +0000123% The format of the AcquireCLocale method is:
cristya20c9042011-05-19 13:22:18 +0000124%
cristyb51dff52011-05-19 16:55:47 +0000125% locale_t AcquireCLocale(void)
cristya20c9042011-05-19 13:22:18 +0000126%
127*/
cristyb51dff52011-05-19 16:55:47 +0000128static locale_t AcquireCLocale(void)
cristya20c9042011-05-19 13:22:18 +0000129{
130#if defined(MAGICKCORE_HAVE_NEWLOCALE)
cristyb51dff52011-05-19 16:55:47 +0000131 if (c_locale == (locale_t) NULL)
132 c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
Jeroen Ooms360889c2016-07-16 21:56:22 +0200133#elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
cristyb51dff52011-05-19 16:55:47 +0000134 if (c_locale == (locale_t) NULL)
135 c_locale=_create_locale(LC_ALL,"C");
cristya20c9042011-05-19 13:22:18 +0000136#endif
cristyb51dff52011-05-19 16:55:47 +0000137 return(c_locale);
138}
cristya723b6a2011-05-25 12:08:51 +0000139#endif
cristyb51dff52011-05-19 16:55:47 +0000140
cristy86e5ac92014-03-16 19:27:39 +0000141/*
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143% %
144% %
145% %
146% A c q u i r e L o c a l e S p l a y T r e e %
147% %
148% %
149% %
150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151%
152% AcquireLocaleSplayTree() caches one or more locale configurations which
153% provides a mapping between locale attributes and a locale tag.
154%
155% The format of the AcquireLocaleSplayTree method is:
156%
157% SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
158% ExceptionInfo *exception)
159%
160% A description of each parameter follows:
161%
162% o filename: the font file tag.
163%
164% o locale: the actual locale.
165%
166% o exception: return any errors or warnings in this structure.
167%
168*/
169
170static void *DestroyLocaleNode(void *locale_info)
171{
172 register LocaleInfo
173 *p;
174
175 p=(LocaleInfo *) locale_info;
176 if (p->path != (char *) NULL)
177 p->path=DestroyString(p->path);
178 if (p->tag != (char *) NULL)
179 p->tag=DestroyString(p->tag);
180 if (p->message != (char *) NULL)
181 p->message=DestroyString(p->message);
182 return(RelinquishMagickMemory(p));
183}
184
185static SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
186 const char *locale,ExceptionInfo *exception)
187{
cristy86e5ac92014-03-16 19:27:39 +0000188 MagickStatusType
189 status;
190
191 SplayTreeInfo
dirkc9f5cc82016-07-17 18:59:02 +0200192 *cache;
cristy86e5ac92014-03-16 19:27:39 +0000193
dirkc9f5cc82016-07-17 18:59:02 +0200194 cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
cristy86e5ac92014-03-16 19:27:39 +0000195 DestroyLocaleNode);
dirk004a3a82016-07-19 22:17:40 +0200196 if (cache == (SplayTreeInfo *) NULL)
cristy86e5ac92014-03-16 19:27:39 +0000197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 status=MagickTrue;
cristy191ba5c2014-03-16 21:26:40 +0000199#if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
cristy86e5ac92014-03-16 19:27:39 +0000200 {
cristy66f8c5f2014-03-17 00:12:14 +0000201 const StringInfo
202 *option;
203
204 LinkedListInfo
205 *options;
206
207 options=GetLocaleOptions(filename,exception);
cristy86e5ac92014-03-16 19:27:39 +0000208 option=(const StringInfo *) GetNextValueInLinkedList(options);
cristy66f8c5f2014-03-17 00:12:14 +0000209 while (option != (const StringInfo *) NULL)
cristy86e5ac92014-03-16 19:27:39 +0000210 {
dirkc9f5cc82016-07-17 18:59:02 +0200211 status&=LoadLocaleCache(cache,(const char *)
cristycd2cd182014-03-18 12:10:55 +0000212 GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
213 exception);
cristy86e5ac92014-03-16 19:27:39 +0000214 option=(const StringInfo *) GetNextValueInLinkedList(options);
cristy86e5ac92014-03-16 19:27:39 +0000215 }
cristy66f8c5f2014-03-17 00:12:14 +0000216 options=DestroyLocaleOptions(options);
dirkc9f5cc82016-07-17 18:59:02 +0200217 if (GetNumberOfNodesInSplayTree(cache) == 0)
cristy66f8c5f2014-03-17 00:12:14 +0000218 {
219 options=GetLocaleOptions("english.xml",exception);
220 option=(const StringInfo *) GetNextValueInLinkedList(options);
221 while (option != (const StringInfo *) NULL)
222 {
dirkc9f5cc82016-07-17 18:59:02 +0200223 status&=LoadLocaleCache(cache,(const char *)
cristycd2cd182014-03-18 12:10:55 +0000224 GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
225 exception);
cristy66f8c5f2014-03-17 00:12:14 +0000226 option=(const StringInfo *) GetNextValueInLinkedList(options);
227 }
228 options=DestroyLocaleOptions(options);
229 }
230 }
cristy191ba5c2014-03-16 21:26:40 +0000231#endif
dirkc9f5cc82016-07-17 18:59:02 +0200232 if (GetNumberOfNodesInSplayTree(cache) == 0)
233 status&=LoadLocaleCache(cache,LocaleMap,"built-in",locale,0,
cristycd2cd182014-03-18 12:10:55 +0000234 exception);
dirkc9f5cc82016-07-17 18:59:02 +0200235 return(cache);
cristy86e5ac92014-03-16 19:27:39 +0000236}
237
cristyc6a82902015-05-17 12:49:39 +0000238#if defined(MAGICKCORE_LOCALE_SUPPORT)
cristyb51dff52011-05-19 16:55:47 +0000239/*
240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241% %
242% %
243% %
244+ D e s t r o y C L o c a l e %
245% %
246% %
247% %
248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249%
250% DestroyCLocale() releases the resources allocated for a locale object
251% returned by a call to the AcquireCLocale() method.
252%
253% The format of the DestroyCLocale method is:
254%
255% void DestroyCLocale(void)
256%
257*/
258static void DestroyCLocale(void)
259{
260#if defined(MAGICKCORE_HAVE_NEWLOCALE)
261 if (c_locale != (locale_t) NULL)
262 freelocale(c_locale);
Jeroen Ooms360889c2016-07-16 21:56:22 +0200263#elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
cristyb51dff52011-05-19 16:55:47 +0000264 if (c_locale != (locale_t) NULL)
265 _free_locale(c_locale);
266#endif
267 c_locale=(locale_t) NULL;
cristya20c9042011-05-19 13:22:18 +0000268}
cristya723b6a2011-05-25 12:08:51 +0000269#endif
cristya20c9042011-05-19 13:22:18 +0000270
271/*
272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273% %
274% %
275% %
cristy3ed852e2009-09-05 21:47:34 +0000276% D e s t r o y L o c a l e O p t i o n s %
277% %
278% %
279% %
280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281%
282% DestroyLocaleOptions() releases memory associated with an locale
283% messages.
284%
285% The format of the DestroyProfiles method is:
286%
287% LinkedListInfo *DestroyLocaleOptions(Image *image)
288%
289% A description of each parameter follows:
290%
291% o image: the image.
292%
293*/
294
295static void *DestroyOptions(void *message)
296{
297 return(DestroyStringInfo((StringInfo *) message));
298}
299
300MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
301{
302 assert(messages != (LinkedListInfo *) NULL);
303 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
304 return(DestroyLinkedList(messages,DestroyOptions));
305}
306
307/*
308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309% %
310% %
311% %
cristyb51dff52011-05-19 16:55:47 +0000312+ F o r m a t L o c a l e F i l e %
cristya20c9042011-05-19 13:22:18 +0000313% %
314% %
315% %
316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317%
cristyb51dff52011-05-19 16:55:47 +0000318% FormatLocaleFile() prints formatted output of a variable argument list to a
319% file in the "C" locale.
cristya20c9042011-05-19 13:22:18 +0000320%
cristyb51dff52011-05-19 16:55:47 +0000321% The format of the FormatLocaleFile method is:
cristya20c9042011-05-19 13:22:18 +0000322%
cristyb51dff52011-05-19 16:55:47 +0000323% ssize_t FormatLocaleFile(FILE *file,const char *format,...)
324%
325% A description of each parameter follows.
326%
327% o file: the file.
328%
329% o format: A file describing the format to use to write the remaining
330% arguments.
cristya20c9042011-05-19 13:22:18 +0000331%
332*/
cristyb51dff52011-05-19 16:55:47 +0000333
cristy7832dc22011-09-05 01:21:53 +0000334MagickPrivate ssize_t FormatLocaleFileList(FILE *file,
dirk05d2ff72015-11-18 23:13:43 +0100335 const char *magick_restrict format,va_list operands)
cristya20c9042011-05-19 13:22:18 +0000336{
cristy20ec7592011-05-29 01:28:05 +0000337 ssize_t
cristyb51dff52011-05-19 16:55:47 +0000338 n;
339
cristyc6a82902015-05-17 12:49:39 +0000340#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_VFPRINTF_L)
cristyb51dff52011-05-19 16:55:47 +0000341 {
342 locale_t
343 locale;
344
345 locale=AcquireCLocale();
346 if (locale == (locale_t) NULL)
cristy20ec7592011-05-29 01:28:05 +0000347 n=(ssize_t) vfprintf(file,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000348 else
cristy26d78202011-05-21 00:59:34 +0000349#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy20ec7592011-05-29 01:28:05 +0000350 n=(ssize_t) vfprintf_l(file,format,locale,operands);
cristy26d78202011-05-21 00:59:34 +0000351#else
cristy20ec7592011-05-29 01:28:05 +0000352 n=(ssize_t) vfprintf_l(file,locale,format,operands);
cristy405905f2011-05-21 00:37:33 +0000353#endif
cristyb51dff52011-05-19 16:55:47 +0000354 }
355#else
cristyc6a82902015-05-17 12:49:39 +0000356#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
cristyb51dff52011-05-19 16:55:47 +0000357 {
358 locale_t
359 locale,
360 previous_locale;
361
362 locale=AcquireCLocale();
363 if (locale == (locale_t) NULL)
cristy20ec7592011-05-29 01:28:05 +0000364 n=(ssize_t) vfprintf(file,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000365 else
366 {
367 previous_locale=uselocale(locale);
cristy20ec7592011-05-29 01:28:05 +0000368 n=(ssize_t) vfprintf(file,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000369 uselocale(previous_locale);
370 }
371 }
372#else
cristy20ec7592011-05-29 01:28:05 +0000373 n=(ssize_t) vfprintf(file,format,operands);
cristya20c9042011-05-19 13:22:18 +0000374#endif
cristyb51dff52011-05-19 16:55:47 +0000375#endif
cristy3da0b402011-05-29 21:13:36 +0000376 return(n);
cristyb51dff52011-05-19 16:55:47 +0000377}
378
dirk05d2ff72015-11-18 23:13:43 +0100379MagickExport ssize_t FormatLocaleFile(FILE *file,
380 const char *magick_restrict format,...)
cristyb51dff52011-05-19 16:55:47 +0000381{
382 ssize_t
383 n;
384
385 va_list
386 operands;
387
388 va_start(operands,format);
cristy20ec7592011-05-29 01:28:05 +0000389 n=FormatLocaleFileList(file,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000390 va_end(operands);
391 return(n);
392}
393
394/*
395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396% %
397% %
398% %
399+ F o r m a t L o c a l e S t r i n g %
400% %
401% %
402% %
403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404%
405% FormatLocaleString() prints formatted output of a variable argument list to
406% a string buffer in the "C" locale.
407%
408% The format of the FormatLocaleString method is:
409%
410% ssize_t FormatLocaleString(char *string,const size_t length,
411% const char *format,...)
412%
413% A description of each parameter follows.
414%
415% o string: FormatLocaleString() returns the formatted string in this
416% character buffer.
417%
418% o length: the maximum length of the string.
419%
420% o format: A string describing the format to use to write the remaining
421% arguments.
422%
423*/
424
dirk05d2ff72015-11-18 23:13:43 +0100425MagickPrivate ssize_t FormatLocaleStringList(char *magick_restrict string,
426 const size_t length,const char *magick_restrict format,va_list operands)
cristyb51dff52011-05-19 16:55:47 +0000427{
cristy20ec7592011-05-29 01:28:05 +0000428 ssize_t
cristyb51dff52011-05-19 16:55:47 +0000429 n;
430
cristyc6a82902015-05-17 12:49:39 +0000431#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_VSNPRINTF_L)
cristy405905f2011-05-21 00:37:33 +0000432 {
433 locale_t
434 locale;
435
436 locale=AcquireCLocale();
437 if (locale == (locale_t) NULL)
cristy20ec7592011-05-29 01:28:05 +0000438 n=(ssize_t) vsnprintf(string,length,format,operands);
cristy405905f2011-05-21 00:37:33 +0000439 else
cristy26d78202011-05-21 00:59:34 +0000440#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy20ec7592011-05-29 01:28:05 +0000441 n=(ssize_t) vsnprintf_l(string,length,format,locale,operands);
cristy26d78202011-05-21 00:59:34 +0000442#else
cristy20ec7592011-05-29 01:28:05 +0000443 n=(ssize_t) vsnprintf_l(string,length,locale,format,operands);
cristy405905f2011-05-21 00:37:33 +0000444#endif
445 }
cristyb51dff52011-05-19 16:55:47 +0000446#elif defined(MAGICKCORE_HAVE_VSNPRINTF)
cristyc6a82902015-05-17 12:49:39 +0000447#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
cristyb51dff52011-05-19 16:55:47 +0000448 {
449 locale_t
450 locale,
451 previous_locale;
452
453 locale=AcquireCLocale();
454 if (locale == (locale_t) NULL)
cristy20ec7592011-05-29 01:28:05 +0000455 n=(ssize_t) vsnprintf(string,length,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000456 else
457 {
458 previous_locale=uselocale(locale);
cristy20ec7592011-05-29 01:28:05 +0000459 n=(ssize_t) vsnprintf(string,length,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000460 uselocale(previous_locale);
461 }
462 }
463#else
cristy20ec7592011-05-29 01:28:05 +0000464 n=(ssize_t) vsnprintf(string,length,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000465#endif
466#else
cristy20ec7592011-05-29 01:28:05 +0000467 n=(ssize_t) vsprintf(string,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000468#endif
469 if (n < 0)
470 string[length-1]='\0';
cristy20ec7592011-05-29 01:28:05 +0000471 return(n);
cristyb51dff52011-05-19 16:55:47 +0000472}
473
dirk05d2ff72015-11-18 23:13:43 +0100474MagickExport ssize_t FormatLocaleString(char *magick_restrict string,
475 const size_t length,const char *magick_restrict format,...)
cristyb51dff52011-05-19 16:55:47 +0000476{
477 ssize_t
478 n;
479
480 va_list
481 operands;
482
483 va_start(operands,format);
cristy20ec7592011-05-29 01:28:05 +0000484 n=FormatLocaleStringList(string,length,format,operands);
cristyb51dff52011-05-19 16:55:47 +0000485 va_end(operands);
486 return(n);
cristya20c9042011-05-19 13:22:18 +0000487}
488
489/*
490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491% %
492% %
493% %
cristy3ed852e2009-09-05 21:47:34 +0000494+ G e t L o c a l e I n f o _ %
495% %
496% %
497% %
498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499%
500% GetLocaleInfo_() searches the locale list for the specified tag and if
501% found returns attributes for that element.
502%
503% The format of the GetLocaleInfo method is:
504%
505% const LocaleInfo *GetLocaleInfo_(const char *tag,
506% ExceptionInfo *exception)
507%
508% A description of each parameter follows:
509%
510% o tag: the locale tag.
511%
512% o exception: return any errors or warnings in this structure.
513%
514*/
515MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
516 ExceptionInfo *exception)
517{
cristy49d4d222014-03-16 00:37:58 +0000518 const LocaleInfo
519 *locale_info;
520
cristy3ed852e2009-09-05 21:47:34 +0000521 assert(exception != (ExceptionInfo *) NULL);
cristy904e5912014-03-15 19:53:14 +0000522 if (IsLocaleTreeInstantiated(exception) == MagickFalse)
523 return((const LocaleInfo *) NULL);
cristy49d4d222014-03-16 00:37:58 +0000524 LockSemaphoreInfo(locale_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000525 if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
526 {
cristy86e5ac92014-03-16 19:27:39 +0000527 ResetSplayTreeIterator(locale_cache);
528 locale_info=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
cristy49d4d222014-03-16 00:37:58 +0000529 UnlockSemaphoreInfo(locale_semaphore);
530 return(locale_info);
cristy3ed852e2009-09-05 21:47:34 +0000531 }
cristy86e5ac92014-03-16 19:27:39 +0000532 locale_info=(const LocaleInfo *) GetValueFromSplayTree(locale_cache,tag);
cristy49d4d222014-03-16 00:37:58 +0000533 UnlockSemaphoreInfo(locale_semaphore);
534 return(locale_info);
cristy3ed852e2009-09-05 21:47:34 +0000535}
536
537/*
538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539% %
540% %
541% %
542% G e t L o c a l e I n f o L i s t %
543% %
544% %
545% %
546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547%
548% GetLocaleInfoList() returns any locale messages that match the
549% specified pattern.
550%
551% The format of the GetLocaleInfoList function is:
552%
553% const LocaleInfo **GetLocaleInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000554% size_t *number_messages,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000555%
556% A description of each parameter follows:
557%
558% o pattern: Specifies a pointer to a text string containing a pattern.
559%
560% o number_messages: This integer returns the number of locale messages in
561% the list.
562%
563% o exception: return any errors or warnings in this structure.
564%
565*/
566
567#if defined(__cplusplus) || defined(c_plusplus)
568extern "C" {
569#endif
570
571static int LocaleInfoCompare(const void *x,const void *y)
572{
573 const LocaleInfo
574 **p,
575 **q;
576
577 p=(const LocaleInfo **) x,
578 q=(const LocaleInfo **) y;
579 if (LocaleCompare((*p)->path,(*q)->path) == 0)
580 return(LocaleCompare((*p)->tag,(*q)->tag));
581 return(LocaleCompare((*p)->path,(*q)->path));
582}
583
584#if defined(__cplusplus) || defined(c_plusplus)
585}
586#endif
587
588MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000589 size_t *number_messages,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000590{
591 const LocaleInfo
592 **messages;
593
594 register const LocaleInfo
595 *p;
596
cristybb503372010-05-27 20:51:26 +0000597 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000598 i;
599
600 /*
601 Allocate locale list.
602 */
603 assert(pattern != (char *) NULL);
604 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000605 assert(number_messages != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000606 *number_messages=0;
607 p=GetLocaleInfo_("*",exception);
608 if (p == (const LocaleInfo *) NULL)
609 return((const LocaleInfo **) NULL);
610 messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
cristy86e5ac92014-03-16 19:27:39 +0000611 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
cristy3ed852e2009-09-05 21:47:34 +0000612 if (messages == (const LocaleInfo **) NULL)
613 return((const LocaleInfo **) NULL);
614 /*
615 Generate locale list.
616 */
cristyf84a1932010-01-03 18:00:18 +0000617 LockSemaphoreInfo(locale_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000618 ResetSplayTreeIterator(locale_cache);
619 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
cristy3ed852e2009-09-05 21:47:34 +0000620 for (i=0; p != (const LocaleInfo *) NULL; )
621 {
622 if ((p->stealth == MagickFalse) &&
623 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
624 messages[i++]=p;
cristy86e5ac92014-03-16 19:27:39 +0000625 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
cristy3ed852e2009-09-05 21:47:34 +0000626 }
cristyf84a1932010-01-03 18:00:18 +0000627 UnlockSemaphoreInfo(locale_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000628 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
629 messages[i]=(LocaleInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000630 *number_messages=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000631 return(messages);
632}
633
634/*
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636% %
637% %
638% %
639% G e t L o c a l e L i s t %
640% %
641% %
642% %
643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
644%
645% GetLocaleList() returns any locale messages that match the specified
646% pattern.
647%
648% The format of the GetLocaleList function is:
649%
cristybb503372010-05-27 20:51:26 +0000650% char **GetLocaleList(const char *pattern,size_t *number_messages,
cristy3ed852e2009-09-05 21:47:34 +0000651% Exceptioninfo *exception)
652%
653% A description of each parameter follows:
654%
655% o pattern: Specifies a pointer to a text string containing a pattern.
656%
657% o number_messages: This integer returns the number of messages in the
658% list.
659%
660% o exception: return any errors or warnings in this structure.
661%
662*/
663
664#if defined(__cplusplus) || defined(c_plusplus)
665extern "C" {
666#endif
667
668static int LocaleTagCompare(const void *x,const void *y)
669{
670 register char
671 **p,
672 **q;
673
674 p=(char **) x;
675 q=(char **) y;
676 return(LocaleCompare(*p,*q));
677}
678
679#if defined(__cplusplus) || defined(c_plusplus)
680}
681#endif
682
cristy5cd9a672015-04-14 21:06:50 +0000683MagickExport char **GetLocaleList(const char *pattern,size_t *number_messages,
684 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000685{
686 char
687 **messages;
688
689 register const LocaleInfo
690 *p;
691
cristybb503372010-05-27 20:51:26 +0000692 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000693 i;
694
695 /*
696 Allocate locale list.
697 */
698 assert(pattern != (char *) NULL);
699 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000700 assert(number_messages != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000701 *number_messages=0;
702 p=GetLocaleInfo_("*",exception);
703 if (p == (const LocaleInfo *) NULL)
704 return((char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000705 messages=(char **) AcquireQuantumMemory((size_t)
cristy86e5ac92014-03-16 19:27:39 +0000706 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
cristy3ed852e2009-09-05 21:47:34 +0000707 if (messages == (char **) NULL)
708 return((char **) NULL);
cristyf84a1932010-01-03 18:00:18 +0000709 LockSemaphoreInfo(locale_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000710 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
cristy3ed852e2009-09-05 21:47:34 +0000711 for (i=0; p != (const LocaleInfo *) NULL; )
712 {
713 if ((p->stealth == MagickFalse) &&
714 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
715 messages[i++]=ConstantString(p->tag);
cristy86e5ac92014-03-16 19:27:39 +0000716 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
cristy3ed852e2009-09-05 21:47:34 +0000717 }
cristyf84a1932010-01-03 18:00:18 +0000718 UnlockSemaphoreInfo(locale_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000719 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
720 messages[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000721 *number_messages=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000722 return(messages);
723}
724
725/*
726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727% %
728% %
729% %
730% G e t L o c a l e M e s s a g e %
731% %
732% %
733% %
734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
735%
736% GetLocaleMessage() returns a message in the current locale that matches the
737% supplied tag.
738%
739% The format of the GetLocaleMessage method is:
740%
741% const char *GetLocaleMessage(const char *tag)
742%
743% A description of each parameter follows:
744%
745% o tag: Return a message that matches this tag in the current locale.
746%
747*/
748MagickExport const char *GetLocaleMessage(const char *tag)
749{
750 char
cristy21967fb2015-04-15 22:26:27 +0000751 name[MagickLocaleExtent];
cristy3ed852e2009-09-05 21:47:34 +0000752
753 const LocaleInfo
754 *locale_info;
755
756 ExceptionInfo
757 *exception;
758
759 if ((tag == (const char *) NULL) || (*tag == '\0'))
760 return(tag);
761 exception=AcquireExceptionInfo();
cristy21967fb2015-04-15 22:26:27 +0000762 (void) FormatLocaleString(name,MagickLocaleExtent,"%s/",tag);
cristy3ed852e2009-09-05 21:47:34 +0000763 locale_info=GetLocaleInfo_(name,exception);
764 exception=DestroyExceptionInfo(exception);
765 if (locale_info != (const LocaleInfo *) NULL)
766 return(locale_info->message);
767 return(tag);
768}
769
770/*
771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772% %
773% %
774% %
775% G e t L o c a l e O p t i o n s %
776% %
777% %
778% %
779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780%
781% GetLocaleOptions() returns any Magick configuration messages associated
782% with the specified filename.
783%
784% The format of the GetLocaleOptions method is:
785%
786% LinkedListInfo *GetLocaleOptions(const char *filename,
787% ExceptionInfo *exception)
788%
789% A description of each parameter follows:
790%
791% o filename: the locale file tag.
792%
793% o exception: return any errors or warnings in this structure.
794%
795*/
796MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
797 ExceptionInfo *exception)
798{
799 char
cristy151b66d2015-04-15 10:50:31 +0000800 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000801
802 const char
803 *element;
804
805 LinkedListInfo
806 *messages,
807 *paths;
808
809 StringInfo
810 *xml;
811
812 assert(filename != (const char *) NULL);
813 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
814 assert(exception != (ExceptionInfo *) NULL);
cristy151b66d2015-04-15 10:50:31 +0000815 (void) CopyMagickString(path,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000816 /*
817 Load XML from configuration files to linked-list.
818 */
819 messages=NewLinkedList(0);
820 paths=GetConfigurePaths(filename,exception);
821 if (paths != (LinkedListInfo *) NULL)
822 {
823 ResetLinkedListIterator(paths);
824 element=(const char *) GetNextValueInLinkedList(paths);
825 while (element != (const char *) NULL)
826 {
cristy21967fb2015-04-15 22:26:27 +0000827 (void) FormatLocaleString(path,MagickPathExtent,"%s%s",element,
828 filename);
cristy3ed852e2009-09-05 21:47:34 +0000829 (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
830 "Searching for locale file: \"%s\"",path);
831 xml=ConfigureFileToStringInfo(path);
832 if (xml != (StringInfo *) NULL)
833 (void) AppendValueToLinkedList(messages,xml);
834 element=(const char *) GetNextValueInLinkedList(paths);
835 }
836 paths=DestroyLinkedList(paths,RelinquishMagickMemory);
837 }
cristy0157aea2010-04-24 21:12:18 +0000838#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000839 {
840 char
841 *blob;
842
843 blob=(char *) NTResourceToBlob(filename);
844 if (blob != (char *) NULL)
845 {
cristy85d6de52011-11-18 15:49:27 +0000846 xml=AcquireStringInfo(0);
847 SetStringInfoLength(xml,strlen(blob)+1);
dirkd61c7ad2014-06-13 04:56:22 +0000848 SetStringInfoDatum(xml,(const unsigned char *) blob);
cristy732d7842014-06-13 18:35:43 +0000849 blob=(char *) RelinquishMagickMemory(blob);
cristy85d6de52011-11-18 15:49:27 +0000850 SetStringInfoPath(xml,filename);
cristy3ed852e2009-09-05 21:47:34 +0000851 (void) AppendValueToLinkedList(messages,xml);
cristy3ed852e2009-09-05 21:47:34 +0000852 }
853 }
854#endif
855 ResetLinkedListIterator(messages);
856 return(messages);
857}
858
859/*
860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
861% %
862% %
863% %
864% G e t L o c a l e V a l u e %
865% %
866% %
867% %
868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
869%
870% GetLocaleValue() returns the message associated with the locale info.
871%
872% The format of the GetLocaleValue method is:
873%
874% const char *GetLocaleValue(const LocaleInfo *locale_info)
875%
876% A description of each parameter follows:
877%
878% o locale_info: The locale info.
879%
880*/
881MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
882{
883 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
884 assert(locale_info != (LocaleInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000885 assert(locale_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000886 return(locale_info->message);
887}
888
889/*
890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
891% %
892% %
893% %
cristy904e5912014-03-15 19:53:14 +0000894+ I s L o c a l e T r e e I n s t a n t i a t e d %
cristy3ed852e2009-09-05 21:47:34 +0000895% %
896% %
897% %
898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899%
cristy904e5912014-03-15 19:53:14 +0000900% IsLocaleTreeInstantiated() determines if the locale tree is instantiated.
901% If not, it instantiates the tree and returns it.
cristy3ed852e2009-09-05 21:47:34 +0000902%
cristy904e5912014-03-15 19:53:14 +0000903% The format of the IsLocaleInstantiated method is:
cristy3ed852e2009-09-05 21:47:34 +0000904%
cristy904e5912014-03-15 19:53:14 +0000905% MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000906%
907% A description of each parameter follows.
908%
909% o exception: return any errors or warnings in this structure.
910%
911*/
cristy904e5912014-03-15 19:53:14 +0000912static MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000913{
cristy86e5ac92014-03-16 19:27:39 +0000914 if (locale_cache == (SplayTreeInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000915 {
cristycd2cd182014-03-18 12:10:55 +0000916 if (locale_semaphore == (SemaphoreInfo *) NULL)
917 ActivateSemaphoreInfo(&locale_semaphore);
918 LockSemaphoreInfo(locale_semaphore);
919 if (locale_cache == (SplayTreeInfo *) NULL)
920 {
921 char
922 *locale;
cristy3ed852e2009-09-05 21:47:34 +0000923
cristycd2cd182014-03-18 12:10:55 +0000924 register const char
925 *p;
cristy3ed852e2009-09-05 21:47:34 +0000926
cristycd2cd182014-03-18 12:10:55 +0000927 locale=(char *) NULL;
928 p=setlocale(LC_CTYPE,(const char *) NULL);
929 if (p != (const char *) NULL)
930 locale=ConstantString(p);
931 if (locale == (char *) NULL)
932 locale=GetEnvironmentValue("LC_ALL");
933 if (locale == (char *) NULL)
934 locale=GetEnvironmentValue("LC_MESSAGES");
935 if (locale == (char *) NULL)
936 locale=GetEnvironmentValue("LC_CTYPE");
937 if (locale == (char *) NULL)
938 locale=GetEnvironmentValue("LANG");
939 if (locale == (char *) NULL)
940 locale=ConstantString("C");
941 locale_cache=AcquireLocaleSplayTree(LocaleFilename,locale,exception);
942 locale=DestroyString(locale);
943 }
944 UnlockSemaphoreInfo(locale_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000945 }
cristy86e5ac92014-03-16 19:27:39 +0000946 return(locale_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000947}
948
949/*
950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
951% %
952% %
953% %
cristyc1acd842011-05-19 23:05:47 +0000954+ I n t e r p r e t L o c a l e V a l u e %
955% %
956% %
957% %
958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
959%
960% InterpretLocaleValue() interprets the string as a floating point number in
961% the "C" locale and returns its value as a double. If sentinal is not a null
962% pointer, the method also sets the value pointed by sentinal to point to the
963% first character after the number.
964%
965% The format of the InterpretLocaleValue method is:
966%
967% double InterpretLocaleValue(const char *value,char **sentinal)
968%
969% A description of each parameter follows:
970%
971% o value: the string value.
972%
973% o sentinal: if sentinal is not NULL, a pointer to the character after the
974% last character used in the conversion is stored in the location
975% referenced by sentinal.
976%
977*/
dirk05d2ff72015-11-18 23:13:43 +0100978MagickExport double InterpretLocaleValue(const char *magick_restrict string,
979 char **magick_restrict sentinal)
cristyc1acd842011-05-19 23:05:47 +0000980{
cristy670aa3c2011-11-03 00:54:00 +0000981 char
982 *q;
983
cristyc1acd842011-05-19 23:05:47 +0000984 double
985 value;
986
cristy670aa3c2011-11-03 00:54:00 +0000987 if ((*string == '0') && ((string[1] | 0x20)=='x'))
988 value=(double) strtoul(string,&q,16);
989 else
990 {
cristyc6a82902015-05-17 12:49:39 +0000991#if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_STRTOD_L)
cristy670aa3c2011-11-03 00:54:00 +0000992 locale_t
993 locale;
994
995 locale=AcquireCLocale();
996 if (locale == (locale_t) NULL)
997 value=strtod(string,&q);
998 else
999 value=strtod_l(string,&q,locale);
cristyc1acd842011-05-19 23:05:47 +00001000#else
cristy670aa3c2011-11-03 00:54:00 +00001001 value=strtod(string,&q);
cristyc1acd842011-05-19 23:05:47 +00001002#endif
cristy670aa3c2011-11-03 00:54:00 +00001003 }
cristy670aa3c2011-11-03 00:54:00 +00001004 if (sentinal != (char **) NULL)
1005 *sentinal=q;
cristyc1acd842011-05-19 23:05:47 +00001006 return(value);
1007}
1008
1009/*
1010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1011% %
1012% %
1013% %
cristy3ed852e2009-09-05 21:47:34 +00001014% L i s t L o c a l e I n f o %
1015% %
1016% %
1017% %
1018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1019%
1020% ListLocaleInfo() lists the locale info to a file.
1021%
1022% The format of the ListLocaleInfo method is:
1023%
1024% MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
1025%
1026% A description of each parameter follows.
1027%
1028% o file: An pointer to a FILE.
1029%
1030% o exception: return any errors or warnings in this structure.
1031%
1032*/
1033MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
1034 ExceptionInfo *exception)
1035{
1036 const char
1037 *path;
1038
1039 const LocaleInfo
1040 **locale_info;
1041
cristybb503372010-05-27 20:51:26 +00001042 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001043 i;
1044
cristybb503372010-05-27 20:51:26 +00001045 size_t
cristy3ed852e2009-09-05 21:47:34 +00001046 number_messages;
1047
1048 if (file == (const FILE *) NULL)
1049 file=stdout;
1050 number_messages=0;
1051 locale_info=GetLocaleInfoList("*",&number_messages,exception);
1052 if (locale_info == (const LocaleInfo **) NULL)
1053 return(MagickFalse);
1054 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +00001055 for (i=0; i < (ssize_t) number_messages; i++)
cristy3ed852e2009-09-05 21:47:34 +00001056 {
1057 if (locale_info[i]->stealth != MagickFalse)
1058 continue;
1059 if ((path == (const char *) NULL) ||
1060 (LocaleCompare(path,locale_info[i]->path) != 0))
1061 {
1062 if (locale_info[i]->path != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +00001063 (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
1064 (void) FormatLocaleFile(file,"Tag/Message\n");
cristy1e604812011-05-19 18:07:50 +00001065 (void) FormatLocaleFile(file,
1066 "-------------------------------------------------"
cristy3ed852e2009-09-05 21:47:34 +00001067 "------------------------------\n");
1068 }
1069 path=locale_info[i]->path;
cristyb51dff52011-05-19 16:55:47 +00001070 (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
cristy3ed852e2009-09-05 21:47:34 +00001071 if (locale_info[i]->message != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +00001072 (void) FormatLocaleFile(file," %s",locale_info[i]->message);
1073 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +00001074 }
1075 (void) fflush(file);
1076 locale_info=(const LocaleInfo **)
1077 RelinquishMagickMemory((void *) locale_info);
1078 return(MagickTrue);
1079}
1080
1081/*
1082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083% %
1084% %
1085% %
dirkfc0f1242016-03-26 00:36:39 +01001086+ L o a d L o c a l e C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001087% %
1088% %
1089% %
1090%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091%
cristy86e5ac92014-03-16 19:27:39 +00001092% LoadLocaleCache() loads the locale configurations which provides a mapping
cristy3ed852e2009-09-05 21:47:34 +00001093% between locale attributes and a locale name.
1094%
cristy86e5ac92014-03-16 19:27:39 +00001095% The format of the LoadLocaleCache method is:
cristy3ed852e2009-09-05 21:47:34 +00001096%
dirkc9f5cc82016-07-17 18:59:02 +02001097% MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1098% const char *filename,const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001099%
1100% A description of each parameter follows:
1101%
1102% o xml: The locale list in XML format.
1103%
1104% o filename: The locale list filename.
1105%
1106% o depth: depth of <include /> statements.
1107%
1108% o exception: return any errors or warnings in this structure.
1109%
1110*/
1111
cristybb503372010-05-27 20:51:26 +00001112static void ChopLocaleComponents(char *path,const size_t components)
cristy3ed852e2009-09-05 21:47:34 +00001113{
cristy3ed852e2009-09-05 21:47:34 +00001114 register char
1115 *p;
1116
cristy9d314ff2011-03-09 01:30:28 +00001117 ssize_t
1118 count;
1119
cristy3ed852e2009-09-05 21:47:34 +00001120 if (*path == '\0')
1121 return;
1122 p=path+strlen(path)-1;
1123 if (*p == '/')
1124 *p='\0';
cristybb503372010-05-27 20:51:26 +00001125 for (count=0; (count < (ssize_t) components) && (p > path); p--)
cristy3ed852e2009-09-05 21:47:34 +00001126 if (*p == '/')
1127 {
1128 *p='\0';
1129 count++;
1130 }
cristybb503372010-05-27 20:51:26 +00001131 if (count < (ssize_t) components)
cristy3ed852e2009-09-05 21:47:34 +00001132 *path='\0';
1133}
1134
cristy2359e742009-11-24 14:50:02 +00001135static void LocaleFatalErrorHandler(
1136 const ExceptionType magick_unused(severity),
1137 const char *reason,const char *description)
1138{
dirk348c8372016-03-17 23:31:24 +01001139 magick_unreferenced(severity);
dirkd2a7a2d2016-03-17 23:07:42 +01001140
cristy2359e742009-11-24 14:50:02 +00001141 if (reason == (char *) NULL)
1142 return;
cristyb51dff52011-05-19 16:55:47 +00001143 (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
cristy2359e742009-11-24 14:50:02 +00001144 if (description != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +00001145 (void) FormatLocaleFile(stderr," (%s)",description);
1146 (void) FormatLocaleFile(stderr,".\n");
cristy2359e742009-11-24 14:50:02 +00001147 (void) fflush(stderr);
1148 exit(1);
1149}
1150
dirkc9f5cc82016-07-17 18:59:02 +02001151static MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1152 const char *filename,const char *locale,const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001153{
1154 char
cristy21967fb2015-04-15 22:26:27 +00001155 keyword[MagickLocaleExtent],
1156 message[MagickLocaleExtent],
1157 tag[MagickLocaleExtent],
cristy3ed852e2009-09-05 21:47:34 +00001158 *token;
1159
1160 const char
1161 *q;
1162
cristy909b6472009-11-24 14:45:00 +00001163 FatalErrorHandler
1164 fatal_handler;
1165
cristy3ed852e2009-09-05 21:47:34 +00001166 LocaleInfo
1167 *locale_info;
1168
cristy759ba912014-06-26 11:59:43 +00001169 MagickStatusType
cristy3ed852e2009-09-05 21:47:34 +00001170 status;
1171
1172 register char
1173 *p;
1174
dirkfc0f1242016-03-26 00:36:39 +01001175 size_t
1176 extent;
1177
cristy3ed852e2009-09-05 21:47:34 +00001178 /*
1179 Read the locale configure file.
1180 */
1181 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1182 "Loading locale configure file \"%s\" ...",filename);
1183 if (xml == (const char *) NULL)
1184 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001185 status=MagickTrue;
1186 locale_info=(LocaleInfo *) NULL;
1187 *tag='\0';
1188 *message='\0';
1189 *keyword='\0';
cristy2359e742009-11-24 14:50:02 +00001190 fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
cristy3ed852e2009-09-05 21:47:34 +00001191 token=AcquireString(xml);
dirkfc0f1242016-03-26 00:36:39 +01001192 extent=strlen(token)+MagickPathExtent;
cristy3ed852e2009-09-05 21:47:34 +00001193 for (q=(char *) xml; *q != '\0'; )
1194 {
1195 /*
1196 Interpret XML.
1197 */
Cristy8bedb4e2016-03-25 19:54:25 -04001198 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001199 if (*token == '\0')
1200 break;
cristy21967fb2015-04-15 22:26:27 +00001201 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
cristy3ed852e2009-09-05 21:47:34 +00001202 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1203 {
1204 /*
1205 Doctype element.
1206 */
1207 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1208 {
Cristy8bedb4e2016-03-25 19:54:25 -04001209 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001210 while (isspace((int) ((unsigned char) *q)) != 0)
1211 q++;
1212 }
1213 continue;
1214 }
1215 if (LocaleNCompare(keyword,"<!--",4) == 0)
1216 {
1217 /*
1218 Comment element.
1219 */
1220 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1221 {
Cristy8bedb4e2016-03-25 19:54:25 -04001222 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001223 while (isspace((int) ((unsigned char) *q)) != 0)
1224 q++;
1225 }
1226 continue;
1227 }
1228 if (LocaleCompare(keyword,"<include") == 0)
1229 {
1230 /*
1231 Include element.
1232 */
1233 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1234 {
cristy21967fb2015-04-15 22:26:27 +00001235 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
Cristy8bedb4e2016-03-25 19:54:25 -04001236 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001237 if (*token != '=')
1238 continue;
Cristy8bedb4e2016-03-25 19:54:25 -04001239 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001240 if (LocaleCompare(keyword,"locale") == 0)
1241 {
1242 if (LocaleCompare(locale,token) != 0)
1243 break;
1244 continue;
1245 }
1246 if (LocaleCompare(keyword,"file") == 0)
1247 {
1248 if (depth > 200)
1249 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00001250 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
cristy3ed852e2009-09-05 21:47:34 +00001251 else
1252 {
1253 char
cristy151b66d2015-04-15 10:50:31 +00001254 path[MagickPathExtent],
dirkb81f0ab2015-10-20 23:01:53 +02001255 *file_xml;
cristy3ed852e2009-09-05 21:47:34 +00001256
1257 *path='\0';
1258 GetPathComponent(filename,HeadPath,path);
1259 if (*path != '\0')
1260 (void) ConcatenateMagickString(path,DirectorySeparator,
cristy151b66d2015-04-15 10:50:31 +00001261 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001262 if (*token == *DirectorySeparator)
cristy151b66d2015-04-15 10:50:31 +00001263 (void) CopyMagickString(path,token,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001264 else
cristy151b66d2015-04-15 10:50:31 +00001265 (void) ConcatenateMagickString(path,token,MagickPathExtent);
dirkb81f0ab2015-10-20 23:01:53 +02001266 file_xml=FileToXML(path,~0UL);
1267 if (file_xml != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001268 {
dirkc9f5cc82016-07-17 18:59:02 +02001269 status&=LoadLocaleCache(cache,file_xml,path,locale,
cristycd2cd182014-03-18 12:10:55 +00001270 depth+1,exception);
dirkb81f0ab2015-10-20 23:01:53 +02001271 file_xml=DestroyString(file_xml);
cristy3ed852e2009-09-05 21:47:34 +00001272 }
1273 }
1274 }
1275 }
1276 continue;
1277 }
1278 if (LocaleCompare(keyword,"<locale") == 0)
1279 {
1280 /*
1281 Locale element.
1282 */
1283 while ((*token != '>') && (*q != '\0'))
1284 {
cristy21967fb2015-04-15 22:26:27 +00001285 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
Cristy8bedb4e2016-03-25 19:54:25 -04001286 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001287 if (*token != '=')
1288 continue;
Cristy8bedb4e2016-03-25 19:54:25 -04001289 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001290 }
1291 continue;
1292 }
1293 if (LocaleCompare(keyword,"</locale>") == 0)
1294 {
1295 ChopLocaleComponents(tag,1);
cristy21967fb2015-04-15 22:26:27 +00001296 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
cristy3ed852e2009-09-05 21:47:34 +00001297 continue;
1298 }
1299 if (LocaleCompare(keyword,"<localemap>") == 0)
1300 continue;
1301 if (LocaleCompare(keyword,"</localemap>") == 0)
1302 continue;
1303 if (LocaleCompare(keyword,"<message") == 0)
1304 {
1305 /*
1306 Message element.
1307 */
1308 while ((*token != '>') && (*q != '\0'))
1309 {
cristy21967fb2015-04-15 22:26:27 +00001310 (void) CopyMagickString(keyword,token,MagickLocaleExtent);
Cristy8bedb4e2016-03-25 19:54:25 -04001311 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001312 if (*token != '=')
1313 continue;
Cristy8bedb4e2016-03-25 19:54:25 -04001314 GetNextToken(q,&q,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001315 if (LocaleCompare(keyword,"name") == 0)
1316 {
cristy21967fb2015-04-15 22:26:27 +00001317 (void) ConcatenateMagickString(tag,token,MagickLocaleExtent);
1318 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
cristy3ed852e2009-09-05 21:47:34 +00001319 }
1320 }
1321 for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1322 while (isspace((int) ((unsigned char) *p)) != 0)
1323 p++;
1324 q--;
1325 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1326 q--;
cristyfb34f5c2014-02-17 01:46:28 +00001327 (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2),
cristy21967fb2015-04-15 22:26:27 +00001328 MagickLocaleExtent));
cristy73bd4a52010-10-05 11:24:23 +00001329 locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
cristy3ed852e2009-09-05 21:47:34 +00001330 if (locale_info == (LocaleInfo *) NULL)
1331 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1332 (void) ResetMagickMemory(locale_info,0,sizeof(*locale_info));
1333 locale_info->path=ConstantString(filename);
1334 locale_info->tag=ConstantString(tag);
1335 locale_info->message=ConstantString(message);
cristye1c94d92015-06-28 12:16:33 +00001336 locale_info->signature=MagickCoreSignature;
dirkc9f5cc82016-07-17 18:59:02 +02001337 status=AddValueToSplayTree(cache,locale_info->tag,locale_info);
cristy3ed852e2009-09-05 21:47:34 +00001338 if (status == MagickFalse)
1339 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00001340 ResourceLimitError,"MemoryAllocationFailed","`%s'",
cristy3ed852e2009-09-05 21:47:34 +00001341 locale_info->tag);
cristy21967fb2015-04-15 22:26:27 +00001342 (void) ConcatenateMagickString(tag,message,MagickLocaleExtent);
1343 (void) ConcatenateMagickString(tag,"\n",MagickLocaleExtent);
cristy3ed852e2009-09-05 21:47:34 +00001344 q++;
1345 continue;
1346 }
1347 if (LocaleCompare(keyword,"</message>") == 0)
1348 {
1349 ChopLocaleComponents(tag,2);
cristy21967fb2015-04-15 22:26:27 +00001350 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
cristy3ed852e2009-09-05 21:47:34 +00001351 continue;
1352 }
1353 if (*keyword == '<')
1354 {
1355 /*
1356 Subpath element.
1357 */
1358 if (*(keyword+1) == '?')
1359 continue;
1360 if (*(keyword+1) == '/')
1361 {
1362 ChopLocaleComponents(tag,1);
1363 if (*tag != '\0')
cristy21967fb2015-04-15 22:26:27 +00001364 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
cristy3ed852e2009-09-05 21:47:34 +00001365 continue;
1366 }
1367 token[strlen(token)-1]='\0';
cristy21967fb2015-04-15 22:26:27 +00001368 (void) CopyMagickString(token,token+1,MagickLocaleExtent);
1369 (void) ConcatenateMagickString(tag,token,MagickLocaleExtent);
1370 (void) ConcatenateMagickString(tag,"/",MagickLocaleExtent);
cristy3ed852e2009-09-05 21:47:34 +00001371 continue;
1372 }
Cristy8bedb4e2016-03-25 19:54:25 -04001373 GetNextToken(q,(const char **) NULL,extent,token);
cristy3ed852e2009-09-05 21:47:34 +00001374 if (*token != '=')
1375 continue;
1376 }
1377 token=(char *) RelinquishMagickMemory(token);
cristy909b6472009-11-24 14:45:00 +00001378 (void) SetFatalErrorHandler(fatal_handler);
cristy759ba912014-06-26 11:59:43 +00001379 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001380}
1381
1382/*
1383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1384% %
1385% %
1386% %
Cristy8ba074d2015-10-19 14:36:08 -04001387% L o c a l e C o m p a r e %
1388% %
1389% %
1390% %
1391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392%
1393% LocaleCompare() performs a case-insensitive comparison of two strings
1394% byte-by-byte, according to the ordering of the current locale encoding.
1395% LocaleCompare returns an integer greater than, equal to, or less than 0,
1396% if the string pointed to by p is greater than, equal to, or less than the
1397% string pointed to by q respectively. The sign of a non-zero return value
1398% is determined by the sign of the difference between the values of the first
1399% pair of bytes that differ in the strings being compared.
1400%
1401% The format of the LocaleCompare method is:
1402%
1403% int LocaleCompare(const char *p,const char *q)
1404%
1405% A description of each parameter follows:
1406%
1407% o p: A pointer to a character string.
1408%
1409% o q: A pointer to a character string to compare to p.
1410%
1411*/
1412MagickExport int LocaleCompare(const char *p,const char *q)
1413{
1414 if ((p == (char *) NULL) && (q == (char *) NULL))
1415 return(0);
1416 if (p == (char *) NULL)
1417 return(-1);
1418 if (q == (char *) NULL)
1419 return(1);
1420#if defined(MAGICKCORE_HAVE_STRCASECMP)
1421 return(strcasecmp(p,q));
1422#else
1423 {
1424 register int
1425 c,
1426 d;
1427
1428 for ( ; ; )
1429 {
1430 c=(int) *((unsigned char *) p);
1431 d=(int) *((unsigned char *) q);
1432 if ((c == 0) || (AsciiMap[c] != AsciiMap[d]))
1433 break;
1434 p++;
1435 q++;
1436 }
1437 return(AsciiMap[c]-(int) AsciiMap[d]);
1438 }
1439#endif
1440}
1441
1442/*
1443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1444% %
1445% %
1446% %
1447% L o c a l e L o w e r %
1448% %
1449% %
1450% %
1451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1452%
1453% LocaleLower() transforms all of the characters in the supplied
1454% null-terminated string, changing all uppercase letters to lowercase.
1455%
1456% The format of the LocaleLower method is:
1457%
1458% void LocaleLower(char *string)
1459%
1460% A description of each parameter follows:
1461%
1462% o string: A pointer to the string to convert to lower-case Locale.
1463%
1464*/
1465MagickExport void LocaleLower(char *string)
1466{
1467 register char
1468 *q;
1469
1470 assert(string != (char *) NULL);
1471 for (q=string; *q != '\0'; q++)
1472 *q=(char) tolower((int) *q);
1473}
1474
1475/*
1476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477% %
1478% %
1479% %
1480% L o c a l e N C o m p a r e %
1481% %
1482% %
1483% %
1484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1485%
1486% LocaleNCompare() performs a case-insensitive comparison of two strings
1487% byte-by-byte, according to the ordering of the current locale encoding.
1488%
1489% LocaleNCompare returns an integer greater than, equal to, or less than 0,
1490% if the string pointed to by p is greater than, equal to, or less than the
1491% string pointed to by q respectively. The sign of a non-zero return value
1492% is determined by the sign of the difference between the values of the first
1493% pair of bytes that differ in the strings being compared.
1494%
1495% The LocaleNCompare method makes the same comparison as LocaleCompare but
1496% looks at a maximum of n bytes. Bytes following a null byte are not
1497% compared.
1498%
1499% The format of the LocaleNCompare method is:
1500%
1501% int LocaleNCompare(const char *p,const char *q,const size_t n)
1502%
1503% A description of each parameter follows:
1504%
1505% o p: A pointer to a character string.
1506%
1507% o q: A pointer to a character string to compare to p.
1508%
1509% o length: the number of characters to compare in strings p and q.
1510%
1511*/
1512MagickExport int LocaleNCompare(const char *p,const char *q,const size_t length)
1513{
1514 if ((p == (char *) NULL) && (q == (char *) NULL))
1515 return(0);
1516 if (p == (char *) NULL)
1517 return(-1);
1518 if (q == (char *) NULL)
1519 return(1);
1520#if defined(MAGICKCORE_HAVE_STRNCASECMP)
1521 return(strncasecmp(p,q,length));
1522#else
1523 {
1524 register int
1525 c,
1526 d;
1527
1528 register size_t
1529 i;
1530
1531 for (i=length; i != 0; i--)
1532 {
1533 c=(int) *((unsigned char *) p);
1534 d=(int) *((unsigned char *) q);
1535 if (AsciiMap[c] != AsciiMap[d])
1536 return(AsciiMap[c]-(int) AsciiMap[d]);
1537 if (c == 0)
1538 return(0);
1539 p++;
1540 q++;
1541 }
1542 return(0);
1543 }
1544#endif
1545}
1546
1547/*
1548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549% %
1550% %
1551% %
1552% L o c a l e U p p e r %
1553% %
1554% %
1555% %
1556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1557%
1558% LocaleUpper() transforms all of the characters in the supplied
1559% null-terminated string, changing all lowercase letters to uppercase.
1560%
1561% The format of the LocaleUpper method is:
1562%
1563% void LocaleUpper(char *string)
1564%
1565% A description of each parameter follows:
1566%
1567% o string: A pointer to the string to convert to upper-case Locale.
1568%
1569*/
1570MagickExport void LocaleUpper(char *string)
1571{
1572 register char
1573 *q;
1574
1575 assert(string != (char *) NULL);
1576 for (q=string; *q != '\0'; q++)
1577 *q=(char) toupper((int) *q);
1578}
1579
1580/*
1581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582% %
1583% %
1584% %
cristyf34a1452009-10-24 22:29:27 +00001585+ L o c a l e C o m p o n e n t G e n e s i s %
1586% %
1587% %
1588% %
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590%
1591% LocaleComponentGenesis() instantiates the locale component.
1592%
1593% The format of the LocaleComponentGenesis method is:
1594%
1595% MagickBooleanType LocaleComponentGenesis(void)
1596%
1597*/
cristy5ff4eaf2011-09-03 01:38:02 +00001598MagickPrivate MagickBooleanType LocaleComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +00001599{
cristy7c977062014-04-04 14:05:53 +00001600 if (locale_semaphore == (SemaphoreInfo *) NULL)
1601 locale_semaphore=AcquireSemaphoreInfo();
cristyf34a1452009-10-24 22:29:27 +00001602 return(MagickTrue);
1603}
1604
1605/*
1606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607% %
1608% %
1609% %
1610+ L o c a l e C o m p o n e n t T e r m i n u s %
1611% %
1612% %
1613% %
1614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615%
1616% LocaleComponentTerminus() destroys the locale component.
1617%
1618% The format of the LocaleComponentTerminus method is:
1619%
1620% LocaleComponentTerminus(void)
1621%
1622*/
cristy5ff4eaf2011-09-03 01:38:02 +00001623MagickPrivate void LocaleComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +00001624{
cristy18b17442009-10-25 18:36:48 +00001625 if (locale_semaphore == (SemaphoreInfo *) NULL)
cristy04b11db2014-02-16 15:10:39 +00001626 ActivateSemaphoreInfo(&locale_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001627 LockSemaphoreInfo(locale_semaphore);
cristy86e5ac92014-03-16 19:27:39 +00001628 if (locale_cache != (SplayTreeInfo *) NULL)
1629 locale_cache=DestroySplayTree(locale_cache);
cristyc6a82902015-05-17 12:49:39 +00001630#if defined(MAGICKCORE_LOCALE_SUPPORT)
cristyb51dff52011-05-19 16:55:47 +00001631 DestroyCLocale();
cristya723b6a2011-05-25 12:08:51 +00001632#endif
cristyf84a1932010-01-03 18:00:18 +00001633 UnlockSemaphoreInfo(locale_semaphore);
cristy3d162a92014-02-16 14:05:06 +00001634 RelinquishSemaphoreInfo(&locale_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001635}