1 /* locale.c -- locale module.
2 Copyright (C) 2003, 2004
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
8 The m17n library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public License
10 as published by the Free Software Foundation; either version 2.1 of
11 the License, or (at your option) any later version.
13 The m17n library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with the m17n library; if not, write to the Free
20 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 @addtogroup m17nLocale
25 @brief Locale objects and API for them
27 The m17n library represents locale related information as objects
31 @addtogroup m17nLocale
32 @brief ¥í¥±¡¼¥ë¥ª¥Ö¥¸¥§¥¯¥È¤È¤½¤ì¤Ë´Ø¤¹¤ë API
34 m17n ¥é¥¤¥Ö¥é¥ê¤Ï¥í¥±¡¼¥ë´ØÏ¢¾ðÊó¤ò #MLocale ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç
39 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
40 /*** @addtogroup m17nInternal
50 #ifdef HAVE_LANGINFO_H
56 #include "m17n-misc.h"
63 static MSymbol M_locale;
64 static MSymbol M_xfrm;
67 /** Structure of locales. */
81 /** The current locales of each category. */
82 MLocale *mlocale__collate, *mlocale__ctype;
83 MLocale *mlocale__messages, *mlocale__time;
85 /* These are currently not used. */
87 MLocale *mlocale_monetary, *mlocale_numeric, ;
90 /** Parse locale name NAME and return a newly created MLocale object.
91 If the locale is not supported by the system, return NULL. */
94 make_locale (const char *name)
96 char *current, *new, *str;
101 str = setlocale (LC_CTYPE, NULL);
102 len = strlen (str) + 1;
103 current = alloca (len);
104 memcpy (current, str, len);
106 if (! (new = setlocale (LC_CTYPE, name)))
110 M17N_OBJECT (locale, NULL, MERROR_LOCALE);
111 locale->name = msymbol (new);
112 msymbol_put (locale->name, M_locale, (void *) locale);
113 M17N_OBJECT_UNREF (locale);
115 len = strlen (new) + 1;
117 memcpy (str, new, len);
125 for (i = 0; str[i]; i++)
126 if (str[i] == '_' || str[i] == '.' || str[i] == '@')
131 /* The first field is for language. */
132 locale->language = msymbol (name);
134 /* The field following '_' is for territory. */
135 locale->territory = msymbol (name);
137 /* The field following '.' is for codeset. */
138 locale->codeset = msymbol (name);
140 /* The other field is for modifier. */
141 locale->modifier = msymbol (name);
148 #ifdef HAVE_NL_LANGINFO
150 /* If we can use nl_langinfo () to retrieve a codeset name, respect
151 it over the codeset name extracted from the locale name. */
152 locale->codeset = msymbol (nl_langinfo (CODESET));
156 /* If the locale name specifies a codeset, get the corresponding
158 if (locale->codeset != Mnil)
160 locale->coding = mconv_resolve_coding (locale->codeset);
161 if (locale->coding == Mnil)
162 locale->coding = Mcoding_us_ascii;
165 locale->coding = Mcoding_us_ascii;
167 setlocale (LC_CTYPE, current);
172 /** Decode the byte sequence at BUF of length SIZE bytes by the coding
173 system associated with LOCALE, and return a generated M-text. */
176 decode_locale (unsigned char *buf, int size, MLocale *locale)
178 return mconv_decode_buffer (locale->coding, buf, size);
182 /** Encode the M-text MT by the coding system associated with LOCALE,
183 and store the resulting bytes in the memory area at BUF of *SIZE
184 bytes. If the area is too short, allocate a new and wider area.
185 Store the length of the generated bytes in the place pointed by
186 SIZE, and return the address of those bytes. */
188 static unsigned char *
189 encode_locale (MText *mt, unsigned char *buf, int *size, MLocale *locale)
191 int nbytes = mconv_encode_buffer (locale->coding, mt, buf, *size - 1);
198 MTABLE_REALLOC (buf, *size, MERROR_LOCALE);
199 nbytes = mconv_encode_buffer (mlocale__ctype->coding, mt, buf,
201 } while (nbytes < 0);
209 /** Structure of transformed strings. The function mtext_coll ()
210 caches this object in an M-text as a text property. */
213 /* Common header for a managed object. */
216 /* Locale corresponding to <str>. */
219 /** Result of strxfrm. */
225 free_xfrm (void *object)
227 MXfrm *xfrm = (MXfrm *) object;
229 M17N_OBJECT_UNREF (xfrm->locale);
236 MTextProperty *prop = mtext_get_property (mt, 0, M_xfrm);
239 unsigned char *buf, *newbuf;
244 if (prop->end == mt->nchars)
246 xfrm = (MXfrm *) prop->val;
247 if (xfrm->locale == mlocale__ctype)
250 mtext_detach_property (prop);
255 newbuf = encode_locale (mt, buf, &size, mlocale__ctype);
256 M17N_OBJECT (xfrm, free_xfrm, MERROR_MTEXT);
257 xfrm->str = malloc (size);
258 request = strxfrm (xfrm->str, (char *) newbuf, size);
261 xfrm->str = realloc (xfrm->str, request);
262 strxfrm (xfrm->str, (char *) newbuf, size);
266 prop = mtext_property (M_xfrm, xfrm, MTEXTPROP_VOLATILE_WEAK);
267 mtext_attach_property (mt, 0, mt->nchars, prop);
268 M17N_OBJECT_UNREF (prop);
278 M_locale = msymbol_as_managing_key (" locale");
280 Mlanguage = msymbol ("language");
281 Mterritory = msymbol ("territory");
282 Mcodeset = msymbol ("codeset");
284 mlocale__collate = mlocale_set (LC_COLLATE, NULL);
285 M17N_OBJECT_REF (mlocale__collate);
286 mlocale__ctype = mlocale_set (LC_CTYPE, NULL);
287 M17N_OBJECT_REF (mlocale__ctype);
288 mlocale__messages = mlocale_set (LC_MESSAGES, NULL);
289 M17N_OBJECT_REF (mlocale__messages);
290 mlocale__time = mlocale_set (LC_TIME, NULL);
291 M17N_OBJECT_REF (mlocale__time);
293 M_xfrm = msymbol_as_managing_key (" xfrm");
300 M17N_OBJECT_UNREF (mlocale__collate);
301 M17N_OBJECT_UNREF (mlocale__ctype);
302 M17N_OBJECT_UNREF (mlocale__messages);
303 M17N_OBJECT_UNREF (mlocale__time);
307 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
311 /*** @addtogroup m17nLocale */
315 /***en The symbol whose name is "language". */
316 /***ja ¥·¥ó¥Ü¥ë "language" */
320 /***en The symbol whose name is "territory". */
321 /***ja ¥·¥ó¥Ü¥ë "territory" */
325 /***en The symbol whose name is "modifier". */
326 /***ja ¥·¥ó¥Ü¥ë "modifier" */
330 /***en The symbol whose name is "codeset". */
331 /***ja ¥·¥ó¥Ü¥ë "codeset" */
337 @brief Set the current locale.
339 The mlocale_set () function sets or query a part of the current
340 locale. The part is specified by $CATEGORY which must be a valid
341 first argument to setlocale ().
343 If $LOCALE is not NULL, the locale of the specified part is set to
344 $LOCALE. If $LOCALE is not supported by the system, the current
345 locale is not changed.
347 If $LOCALE is NULL, the current locale of the specified part is
351 If the call is successful, mlocale_set () returns an opaque locale
352 object that corresponds to the locale. The name of the locale can
353 be acquired by the function mlocale_get_prop ().
355 Otherwise, it returns NULL. */
358 @brief ¸½ºß¤Î¥í¥±¡¼¥ë¤òÀßÄꤹ¤ë.
360 ´Ø¿ô mlocale_set () ¤Ï $LOCALE_NAME ¤ò¸½ºß¤Î¥í¥±¡¼¥ë¤È¤¹¤ë¡£¤³¤Î´Ø
361 ¿ô¤Ï¥·¥¹¥Æ¥à´Ø¿ô <tt>setlocale ()</tt> ¤ò¸Æ¤Ó¡¢³°ÉôÊÑ¿ô @c
362 mlocale_current ¤òÀßÄꤹ¤ë¡£
365 ¥·¥¹¥Æ¥à¤¬ $LOCALE_NAME ¤ò¥µ¥Ý¡¼¥È¤¹¤ë¤Ê¤é¤Ð mlocale_set () ¤Ï 0
366 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
374 mlocale_set (int category, const char *name)
379 new = setlocale (category, name);
383 locale = (MLocale *) msymbol_get (msymbol (new), M_locale);
385 locale = make_locale (new);
388 if (name && (category == LC_ALL || category == LC_COLLATE))
390 M17N_OBJECT_REF (locale);
391 M17N_OBJECT_UNREF (mlocale__collate);
392 mlocale__collate = locale;
394 else if (name && (category == LC_ALL || category == LC_CTYPE))
396 M17N_OBJECT_REF (locale);
397 M17N_OBJECT_UNREF (mlocale__ctype);
398 mlocale__ctype = locale;
400 if (name && (category == LC_ALL || category == LC_MESSAGES))
402 M17N_OBJECT_REF (locale);
403 M17N_OBJECT_UNREF (mlocale__messages);
404 mlocale__messages = locale;
406 if (name && (category == LC_ALL || category == LC_TIME))
408 M17N_OBJECT_REF (locale);
409 M17N_OBJECT_UNREF (mlocale__time);
410 mlocale__time = locale;
418 @brief Get the value of a locale property.
420 The mlocale_get_prop () function returns the value of a property
421 $KEY of local $LOCALE. $KEY must be #Mname, #Mlanguage,
422 #Mterritory, #Mcodeset, #Mmodifier, or #Mcoding. */
425 @brief ¥í¥±¡¼¥ë¤Î¥×¥í¥Ñ¥Æ¥£ÃͤòÆÀ¤ë
427 ´Ø¿ô mlocale_get_prop () ¤Ï¡¢¥í¥±¡¼¥ë $LOCALE ¤Î $KEY ¥×¥í¥Ñ¥Æ¥£¤Î
428 ÃͤòÊÖ¤¹¡£ $KEY ¤Ï #Mname ¡¢ #Mlanguage ¡¢ #Mterritory ¡¢
429 #Mcodeset ¡¢ #Mmodifier ¤â¤·¤¯¤Ï #Mcoding ¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê
433 mlocale_get_prop (MLocale *locale, MSymbol key)
436 return locale->coding;
439 if (key == Mlanguage)
440 return locale->language;
441 if (key == Mterritory)
442 return locale->territory;
444 return locale->codeset;
445 if (key == Mmodifier)
446 return locale->modifier;
452 @brief Format date and time
454 The mtext_ftime () function formats the broken-down time $TM
455 according to the format specification $FORMAT and append the
456 result to the M-text $MT. The formating is done according to the
457 locale $LOCALE (if not NULL) or the current locale (LC_TIME).
459 The meaning of the arguments $TM and $FORMAT are the same as those
468 mtext_ftime (MText *mt, const char *format, const struct tm *tm,
473 size_t nbytes, nchars;
474 char *current_locale = NULL;
478 char *str = setlocale (LC_TIME, NULL);
479 int len = strlen (str) + 1;
481 current_locale = alloca (len);
482 memcpy (current_locale, str, len);
483 mlocale_set (LC_TIME, msymbol_name (locale->name));
489 MTABLE_ALLOCA (buf, bufsize, MERROR_MTEXT);
491 nbytes = strftime ((char *) buf, bufsize, format, tm);
500 MText *work = decode_locale (buf, nbytes, mlocale__time);
504 nchars = work->nchars;
505 mtext_cat (mt, work);
506 M17N_OBJECT_UNREF (work);
515 mlocale_set (LC_TIME, current_locale);
523 @brief Get an environment variable
525 The mtext_getenv () function searches the environment list for a
526 string that matches the string pointed to by $NAME.
528 If there is a match, the function decodes the value according to
529 the current locale (LC_CTYPE) into an M-text, and return that
532 If there is no match, the function returns NULL. */
535 mtext_getenv (const char *name)
537 char *p = getenv (name);
541 return decode_locale ((unsigned char *) p, strlen (p), mlocale__ctype);
547 @brief Change or add an environment variable.
549 The mtext_putenv () function adds or changed the value of
550 environment variables according to M-text $MT. It simply calls
551 the function putenv with an argument generated by encoding $MT
552 according to the current locale (LC_CTYPE).
555 This function returns zero on success, or -1 if an error
559 mtext_putenv (MText *mt)
561 unsigned char buf[1024];
563 unsigned char *newbuf;
566 newbuf = encode_locale (mt, buf, &size, mlocale__ctype);
567 result = putenv ((char *) newbuf);
576 @brief Compare two M-texts using the current locale.
578 The mtext_coll () function compares the two M-texts $MT1 and $MT2.
579 It returns an integer less than, equal to, or greater than zero if
580 $MT1 is found, respectively, to be less than, to match, or to be
581 greater than $MT2. The comparison is based on texts as
582 appropriate for the current locale (LC_COLLATE).
584 This function makes use of information that is automatically
585 cached in the M-texts as a text property. So, the second call of
586 this function with $MT1 or $MT2 finishes faster than the first
590 mtext_coll (MText *mt1, MText *mt2)
594 if (mt1->nchars == 0)
595 return (mt2->nchars == 0 ? 0 : -1);
596 else if (mt2->nchars == 0)
599 str1 = get_xfrm (mt1);
600 str2 = get_xfrm (mt2);
601 return strcoll (str1, str2);