05dbf460fdd14bbd9695ea9c698165c4744aecdf
[m17n/m17n-lib.git] / src / locale.c
1 /* locale.c -- locale module.
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
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.
12
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.
17
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., 51 Franklin Street, Fifth Floor,
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nLocale
25     @brief Locale objects and API for them.
26
27     The m17n library represents locale related information as objects
28     of type #MLocale.  */
29
30 /***ja
31     @addtogroup m17nLocale
32     @brief ¥í¥±¡¼¥ë¥ª¥Ö¥¸¥§¥¯¥È¤È¤½¤ì¤Ë´Ø¤¹¤ë API.
33
34     m17n ¥é¥¤¥Ö¥é¥ê¤Ï¥í¥±¡¼¥ë´ØÏ¢¾ðÊó¤ò #MLocale ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Çɽ¸½¤¹¤ë¡£  */
35
36 /*=*/
37
38 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
39 /*** @addtogroup m17nInternal
40      @{ */
41
42 #define _GNU_SOURCE
43
44 #include <config.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <locale.h>
49 #ifdef HAVE_LANGINFO_H
50 #include <langinfo.h>
51 #endif
52 #include <time.h>
53
54 #include "m17n.h"
55 #include "m17n-misc.h"
56 #include "internal.h"
57 #include "symbol.h"
58 #include "coding.h"
59 #include "textprop.h"
60 #include "mlocale.h"
61
62 static MSymbol M_locale;
63 static MSymbol M_xfrm;
64
65
66 /** Structure of locales.  */
67
68 struct MLocale
69 {
70   M17NObject control;
71   MSymbol name;
72   MSymbol language;
73   MSymbol territory;
74   MSymbol modifier;
75   MSymbol codeset;
76   MSymbol coding;
77 };
78
79
80 /** The current locales of each category.  */
81 MLocale *mlocale__collate, *mlocale__ctype;
82 MLocale *mlocale__messages, *mlocale__time;
83
84 /* These are currently not used.  */
85 #if 0
86 MLocale *mlocale_monetary, *mlocale_numeric, ;
87 #endif
88
89 /** Parse locale name NAME and return a newly created MLocale object.  */
90
91 static MLocale *
92 make_locale (const char *name)
93 {
94   char *str;
95   int len;
96   MLocale *locale;
97   char c;
98
99   M17N_OBJECT (locale, NULL, MERROR_LOCALE);
100   locale->name = msymbol (name);
101   msymbol_put (locale->name, M_locale, (void *) locale);
102   M17N_OBJECT_UNREF (locale);
103
104   len = strlen (name) + 1;
105   str = alloca (len);
106   memcpy (str, name, len);
107
108   c = '\0';
109   while (1)
110     {
111       char c1;
112       int i;
113
114       for (i = 0; str[i]; i++)
115         if (str[i] == '_' || str[i] == '.' || str[i] == '@')
116           break;
117       c1 = str[i];
118       str[i] = '\0';
119       if (c == '\0')
120         /* The first field is for language.  */
121         locale->language = msymbol (str);
122       else if (c == '_')
123         /* The field following '_' is for territory.  */
124         locale->territory = msymbol (str);
125       else if (c == '.')
126         /* The field following '.' is for codeset.  */
127         locale->codeset = msymbol (str);
128       else
129         /* The other field is for modifier.  */
130         locale->modifier = msymbol (str);
131       if (! c1)
132         break;
133       c = c1;
134       str += i + 1;
135     }
136
137 #ifdef HAVE_NL_LANGINFO
138 #ifdef CODESET
139   /* If we can use nl_langinfo () to retrieve a codeset name, respect
140      it over the codeset name extracted from the locale name.  */
141   locale->codeset = msymbol (nl_langinfo (CODESET));
142 #endif
143 #endif
144
145   /* If the locale name specifies a codeset, get the corresponding
146      coding system.  */
147   if (locale->codeset != Mnil)
148     {
149       locale->coding = mconv_resolve_coding (locale->codeset);
150       if (locale->coding == Mnil)
151         locale->coding = Mcoding_us_ascii;
152     }
153   else
154     locale->coding = Mcoding_us_ascii;
155   return locale;
156 }
157
158
159 /** Decode the byte sequence at BUF of length SIZE bytes by the coding
160     system associated with LOCALE, and return a generated M-text.  */
161
162 static MText *
163 decode_locale (unsigned char *buf, int size, MLocale *locale)
164 {
165   return mconv_decode_buffer (locale->coding, buf, size);
166 }
167
168
169 /** Encode the M-text MT by the coding system associated with LOCALE,
170     and store the resulting bytes in the memory area at BUF of *SIZE
171     bytes.  If the area is too short, allocate a new and wider area.
172     Store the length of the generated bytes in the place pointed by
173     SIZE, and return the address of those bytes.  */
174
175 static unsigned char *
176 encode_locale (MText *mt, unsigned char *buf, int *size, MLocale *locale)
177 {
178   int nbytes = mconv_encode_buffer (locale->coding, mt, buf, *size - 1);
179
180   if (nbytes < 0)
181     {
182       buf = NULL;
183       *size *= 2;
184       do {
185         MTABLE_REALLOC (buf, *size, MERROR_LOCALE);
186         nbytes = mconv_encode_buffer (mlocale__ctype->coding, mt, buf,
187                                       *size - 1);
188       } while (nbytes < 0);
189     }
190   buf[nbytes] = '\0';
191   *size = nbytes;
192   return buf;
193 }
194
195
196 /** Structure of transformed strings.  The function mtext_coll ()
197     caches this object in an M-text as a text property.  */
198
199 typedef struct {
200   /* Common header for a managed object.  */
201   M17NObject control;
202
203   /* Locale corresponding to <str>.  */
204   MLocale *locale;
205
206   /** Result of strxfrm.  */
207   char *str;
208 } MXfrm;
209
210
211 static void
212 free_xfrm (void *object)
213 {
214   MXfrm *xfrm = (MXfrm *) object;
215
216   M17N_OBJECT_UNREF (xfrm->locale);
217   free (xfrm->str);
218 }
219
220 static char *
221 get_xfrm (MText *mt)
222 {
223   MTextProperty *prop = mtext_get_property (mt, 0, M_xfrm);
224   MXfrm *xfrm;
225   int size;
226   unsigned char *buf, *newbuf;
227   int request;
228
229   if (prop)
230     {
231       if (prop->end == mt->nchars)
232         {
233           xfrm = (MXfrm *) prop->val;
234           if (xfrm->locale == mlocale__ctype)
235             return xfrm->str;
236         }
237       mtext_detach_property (prop);
238     }
239
240   size = mt->nbytes;
241   buf = alloca (size);
242   newbuf = encode_locale (mt, buf, &size, mlocale__ctype);
243   M17N_OBJECT (xfrm, free_xfrm, MERROR_MTEXT);
244   xfrm->str = malloc (size);
245   request = strxfrm (xfrm->str, (char *) newbuf, size);
246   if (request >= size)
247     {
248       xfrm->str = realloc (xfrm->str, request);
249       strxfrm (xfrm->str, (char *) newbuf, size);
250     }
251   if (buf != newbuf)
252     free (newbuf);
253   prop = mtext_property (M_xfrm, xfrm, MTEXTPROP_VOLATILE_WEAK);
254   mtext_attach_property (mt, 0, mt->nchars, prop);
255   M17N_OBJECT_UNREF (prop);
256   return xfrm->str;
257 }
258
259 \f
260 /* Internal API */
261
262 int
263 mlocale__init ()
264 {
265   M_locale = msymbol_as_managing_key ("  locale");
266
267   Mterritory = msymbol ("territory");
268   Mcodeset = msymbol ("codeset");
269
270   mlocale__collate = mlocale_set (LC_COLLATE, NULL);
271   M17N_OBJECT_REF (mlocale__collate);
272   mlocale__ctype = mlocale_set (LC_CTYPE, NULL);
273   M17N_OBJECT_REF (mlocale__ctype);
274   mlocale__messages = mlocale_set (LC_MESSAGES, NULL);
275   M17N_OBJECT_REF (mlocale__messages);
276   mlocale__time = mlocale_set (LC_TIME, NULL);
277   M17N_OBJECT_REF (mlocale__time);
278
279   M_xfrm = msymbol_as_managing_key ("  xfrm");
280   return 0;
281 }
282
283 void
284 mlocale__fini ()
285 {
286   M17N_OBJECT_UNREF (mlocale__collate);
287   M17N_OBJECT_UNREF (mlocale__ctype);
288   M17N_OBJECT_UNREF (mlocale__messages);
289   M17N_OBJECT_UNREF (mlocale__time);
290 }
291
292 /*** @} */
293 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
294
295 \f
296 /* External API */
297 /*** @addtogroup m17nLocale */
298 /*** @{ */
299
300 /*=*/
301 /***en The symbol whose name is "territory".  */
302 /***ja  "territory" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë. */
303 MSymbol Mterritory;
304
305 /*=*/
306 /***en The symbol whose name is "modifier".  */
307 /***ja  "modifier" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë. */
308 MSymbol Mmodifier;
309
310 /*=*/
311 /***en The symbol whose name is "codeset".  */
312 /***ja  "codeset" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë. */
313 MSymbol Mcodeset;
314
315 /*=*/
316
317 /***en
318     @brief Set the current locale.
319
320     The mlocale_set () function sets or query a part of the current
321     locale.  The part is specified by $CATEGORY which must be a valid
322     first argument to <tt>setlocale ()</tt>.
323
324     If $LOCALE is not NULL, the locale of the specified part is set to
325     $LOCALE.  If $LOCALE is not supported by the system, the current
326     locale is not changed.
327
328     If $LOCALE is NULL, the current locale of the specified part is
329     queried.
330
331     @return
332     If the call is successful, mlocale_set () returns an opaque locale
333     object that corresponds to the locale.  The name of the locale can
334     be acquired by the function mlocale_get_prop ().
335     Otherwise, it returns NULL.  */
336
337 /***ja
338     @brief ¸½ºß¤Î¥í¥±¡¼¥ë¤òÀßÄꤹ¤ë.
339
340     ´Ø¿ô mlocale_set () ¤Ï¸½ºß¤Î¥í¥±¡¼¥ë¤Î°ìÉô¤òÀßÄꤷ¤¿¤êÌ䤤¹ç¤ï¤»¤¿¤ê¤¹¤ë¡£¤³¤³¤Ç°ìÉô¤È¤Ï 
341     $CATEGORY ¤Ç»ØÄꤵ¤ì¡¢<tt>setlocale ()</tt> ¤ÎÍ­¸ú¤ÊÂè°ì°ú¿ô¤È¤Ê¤ë¤â¤Î¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
342
343     $LOCALE ¤¬ NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢»ØÄꤷ¤¿Éôʬ¤Î¥í¥±¡¼¥ë¤¬$LOCALE ¤ËÀßÄꤵ¤ì¤ë¡£
344     $LOCALE ¤¬¥·¥¹¥Æ¥à¤Ë¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢ÀßÄê¤Ï¹Ô¤ï¤ì¤º¡¢¸½ºß¤Î¥í¥±¡¼¥ë¤ÏÊѤï¤é¤Ê¤¤¡£
345
346     $LOCALE ¤¬ NULL ¤Ê¤é¤Ð¡¢¸½ºß¤Î¥í¥±¡¼¥ë¤Î»ØÄꤷ¤¿Éôʬ¤òÌ䤤¹ç¤ï¤»¤ë¡£
347
348     @return 
349
350     ¸Æ¤Ó½Ð¤·¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mlocale_set () ¤Ï¥í¥±¡¼¥ë¤ËÂбþ¤¹¤ë opaque 
351     ¥í¥±¡¼¥ë¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£¥í¥±¡¼¥ë¤Î̾Á°¤Ï´Ø¿ô
352     mlocale_get_prop () ¤Ë¤è¤Ã¤ÆÆÀ¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
353     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð NULL ¤òÊÖ¤¹¡£
354      */
355
356 /***
357     @errors
358     @c MERROR_LOCALE  */
359
360 MLocale *
361 mlocale_set (int category, const char *name)
362 {
363   char *new;
364   MLocale *locale;
365
366   new = setlocale (category, name);
367   if (! new)
368     return NULL;
369
370   locale = (MLocale *) msymbol_get (msymbol (new), M_locale);
371   if (! locale)
372     locale = make_locale (new);
373   if (! locale)
374     return NULL;
375   if (name && (category == LC_ALL || category == LC_COLLATE))
376     {
377       M17N_OBJECT_REF (locale);
378       M17N_OBJECT_UNREF (mlocale__collate);
379       mlocale__collate = locale;
380     }
381   else if (name && (category == LC_ALL || category == LC_CTYPE))
382     {
383       M17N_OBJECT_REF (locale);
384       M17N_OBJECT_UNREF (mlocale__ctype);
385       mlocale__ctype = locale;
386     }
387   if (name && (category == LC_ALL || category == LC_MESSAGES))
388     {
389       M17N_OBJECT_REF (locale);
390       M17N_OBJECT_UNREF (mlocale__messages);
391       mlocale__messages = locale;
392     }
393   if (name && (category == LC_ALL || category == LC_TIME))
394     {
395       M17N_OBJECT_REF (locale);
396       M17N_OBJECT_UNREF (mlocale__time);
397       mlocale__time = locale;
398     }
399   return locale;
400 }
401
402 /*=*/
403
404 /***en
405     @brief Get the value of a locale property.
406
407     The mlocale_get_prop () function returns the value of a property
408     $KEY of local $LOCALE.  $KEY must be #Mname, #Mlanguage,
409     #Mterritory, #Mcodeset, #Mmodifier, or #Mcoding.  */ 
410
411 /***ja
412     @brief ¥í¥±¡¼¥ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÆÀ¤ë.
413
414     ´Ø¿ô mlocale_get_prop () ¤Ï¡¢¥í¥±¡¼¥ë $LOCALE ¤Î $KEY ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£
415     $KEY ¤Ï #Mname, #Mlanguage, #Mterritory, #Mcodeset, #Mmodifier, 
416     #Mcoding ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£ */ 
417
418 MSymbol
419 mlocale_get_prop (MLocale *locale, MSymbol key)
420 {
421   if (key == Mcoding)
422     return locale->coding;
423   if (key == Mname)
424     return locale->name;
425   if (key == Mlanguage)
426     return locale->language;
427   if (key == Mterritory)
428     return locale->territory;
429   if (key == Mcodeset)
430     return locale->codeset;
431   if (key == Mmodifier)
432     return locale->modifier;
433   return Mnil;
434 }
435
436 /*=*/
437 /***en
438     @brief Format date and time.
439
440     The mtext_ftime () function formats the broken-down time $TM
441     according to the format specification $FORMAT and append the
442     result to the M-text $MT.  The formating is done according to the
443     locale $LOCALE (if not NULL) or the current locale (LC_TIME).
444
445     The meaning of the arguments $TM and $FORMAT are the same as those
446     of strftime ().
447
448     @seealso
449     strftime ().
450 */
451 /***ja
452     @brief ÆüÉդȻþ´Ö¤ò¥Õ¥©¡¼¥Þ¥Ã¥È¤¹¤ë.
453
454     ´Ø¿ô mtext_ftime () ¤Ï»þ¹ï¥Ç¡¼¥¿ (broken-down time) $TM ¤ò$FORMAT 
455     ¤Ç»ØÄꤵ¤ì¤¿·Á¼°¤ËÀ¶½ñ¤·¡¢·ë²Ì¤òM-text $MT ¤ËÉղ乤롣¥Õ¥©¡¼¥Þ¥Ã¥È¤Ï 
456     NULL ¤Ç¤Ê¤±¤ì¤Ð ¥í¥±¡¼¥ë $LOCALE ¤Ë¡¢¤Þ¤¿¤Ï¸½ºß¤Î¥í¥±¡¼¥ë(LC_TIME) ¤Ë½¾¤¦¡£
457
458     °ú¿ô $TM ¤È $FORMAT ¤Î°ÕÌ£¤Ï strftime () ¤Î¾ì¹ç¤ÈƱ¤¸¡£
459
460     @seealso
461     strftime ().
462 */
463
464 int
465 mtext_ftime (MText *mt, const char *format, const struct tm *tm,
466              MLocale *locale)
467 {
468   int bufsize;
469   unsigned char *buf;
470   size_t nbytes, nchars;
471   char *current_locale = NULL;
472
473   if (locale)
474     {
475       char *str = setlocale (LC_TIME, NULL);
476       int len = strlen (str) + 1;
477
478       current_locale = alloca (len);
479       memcpy (current_locale, str, len);
480       mlocale_set (LC_TIME, msymbol_name (locale->name));
481     }
482
483   bufsize = 1024;
484   while (1)
485     {
486       MTABLE_ALLOCA (buf, bufsize, MERROR_MTEXT);
487       buf[0] = 1;
488       nbytes = strftime ((char *) buf, bufsize, format, tm);
489       if (nbytes > 0
490           || ! buf[0])
491         break;
492       bufsize *= 2;
493     }
494
495   if (nbytes > 0)
496     {
497       MText *work = decode_locale (buf, nbytes, mlocale__time);
498
499       if (work)
500         {
501           nchars = work->nchars;
502           mtext_cat (mt, work);
503           M17N_OBJECT_UNREF (work);
504         }
505       else
506         nchars = 0;
507     }
508   else
509     nchars = 0;
510
511   if (current_locale)
512     mlocale_set (LC_TIME, current_locale);
513
514   return nchars;
515 }
516           
517 /*=*/
518
519 /***en
520     @brief Get an environment variable.
521
522     The mtext_getenv () function searches the environment variable
523     list for a string that matches the string pointed to by $NAME.
524
525     If there is a match, the function decodes the value according to
526     the current locale (LC_CTYPE) into an M-text, and return that
527     M-text.
528
529     If there is no match, the function returns NULL.  */
530 /***ja
531     @brief ´Ä¶­ÊÑ¿ô¤òÆÀ¤ë.
532
533     ´Ø¿ô mtext_getenv () ¤Ï $NAME 
534     ¤Ç»Ø¤µ¤ì¤ëʸ»úÎó¤È¹çÃפ¹¤ëʸ»úÎó¤ò´Ä¶­ÊÑ¿ô¤Î¥ê¥¹¥ÈÃ椫¤éõ¤¹¡£
535
536     ¸«¤Ä¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢¤½¤ÎÃͤò¸½ºß¤Î¥í¥±¡¼¥ë(LC_CTYPE) ¤Ë½¾¤Ã¤Æ 
537     M-text ¤Ë¥Ç¥³¡¼¥É¤·¡¢¤½¤ÎM-text ¤òÊÖ¤¹¡£
538
539     ¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢NULL ¤òÊÖ¤¹¡£  */
540
541 MText *
542 mtext_getenv (const char *name)
543 {
544   char *p = getenv (name);
545
546   if (!p)
547     return NULL;
548   return decode_locale ((unsigned char *) p, strlen (p), mlocale__ctype);
549 }
550
551 /*=*/
552
553 /***en
554     @brief Change or add an environment variable.
555
556     The mtext_putenv () function changes or adds the value of
557     environment variables according to M-text $MT.  It calls the
558     function <tt>putenv</tt> with an argument generated by encoding
559     $MT according to the current locale (LC_CTYPE).
560
561     @return
562     This function returns zero on success, or -1 if an error
563     occurs.  */
564 /***ja
565     @brief ´Ä¶­ÊÑ¿ô¤òÊѹ¹¡¿Äɲ乤ë.
566
567     ´Ø¿ô mtext_putenv () ¤Ï M-text $MT 
568     ¤Ë½¾¤Ã¤Æ¡¢´Ä¶­ÊÑ¿ô¤ÎÃͤòÊѹ¹¤·¤¿¤êÄɲä·¤¿¤ê¤¹¤ë¡£¤³¤Î´Ø¿ô¤Ï¡¢¸½ºß¤Î¥í¥±¡¼¥ë
569     (LC_CTYPE) ¤Ë½¾¤Ã¤Æ$MT ¤ò¥¨¥ó¥³¡¼¥É¤·¡¢¤½¤ì¤ò°ú¿ô¤È¤·¤Æ´Ø¿ô <tt>putenv</tt> ¤ò¸Æ¤Ö¡£
570
571     @return
572     ¤³¤Î´Ø¿ô¤Ï¡¢À®¸ù¤·¤¿¾ì¹ç¤Ë¤Ï 0 ¤ò¡¢¥¨¥é¡¼¤¬µ¯¤³¤ì¤Ð -1 ¤òÊÖ¤¹¡£
573     */
574
575
576 int
577 mtext_putenv (MText *mt)
578 {
579   unsigned char buf[1024];
580   int size = 1024;
581   unsigned char *newbuf;
582   int result;
583
584   newbuf = encode_locale (mt, buf, &size, mlocale__ctype);
585   result = putenv ((char *) newbuf);
586   if (buf != newbuf)
587     free (newbuf);
588   return result;
589 }
590
591 /*=*/
592
593 /***en
594     @brief Compare two M-texts using the current locale.
595
596     The mtext_coll () function compares the two M-texts $MT1 and $MT2.
597     It returns an integer less than, equal to, or greater than zero if
598     $MT1 is found, respectively, to be less than, to match, or to be
599     greater than $MT2.  The comparison is based on texts as
600     appropriate for the current locale (LC_COLLATE).
601
602     This function makes use of information that is automatically
603     cached in the M-texts as a text property.  So, the second call of
604     this function with $MT1 or $MT2 finishes faster than the first
605     call.  */
606 /***ja
607     @brief ¸½ºß¤Î¥í¥±¡¼¥ë¤òÍѤ¤¤Æ£²¤Ä¤Î M-text ¤òÈæ³Ó¤¹¤ë.
608
609     ´Ø¿ô mtext_coll () ¤Ï£²¤Ä¤Î M-text $MT1 ¤È $MT2 
610     ¤òÈæ³Ó¤¹¤ë¡£Ìá¤êÃͤÏÉé¤ÎÀ°¿ôÃÍ, 0, Àµ¤ÎÀ°¿ôÃͤΤ¤¤º¤ì¤«¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì 
611     $MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤¤¡¢Æ±¤¸¡¢Â礭¤¤¾ì¹ç¤ËÁêÅö¤¹¤ë¡£Èæ³Ó¤Ï¸½ºß¤Î¥í¥±¡¼¥ë 
612     (LC_COLLATE) ¤Ë´ð¤Å¤¤¤Æ¹Ô¤ï¤ì¤ë¡£
613
614     ¤³¤Î´Ø¿ô¤Ï M-text 
615     ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤È¤·¤Æ¼«Æ°Åª¤Ë¥­¥ã¥Ã¥·¥å¤µ¤ì¤ë¾ðÊó¤òÍøÍѤ¹¤ë¤Î¤Ç¡¢£²ÅÙÌܰʹߤÎƱ¤¸Èæ³Ó¤Ï£±ÅÙÌܤè¤ê®¤¯¼Â¹Ô¤µ¤ì¤ë¡£  */
616
617 int
618 mtext_coll (MText *mt1, MText *mt2)
619 {
620   char *str1, *str2;
621
622   if (mt1->nchars == 0)
623     return (mt2->nchars == 0 ? 0 : -1);
624   else if (mt2->nchars == 0)
625     return 1;
626
627   str1 = get_xfrm (mt1);
628   str2 = get_xfrm (mt2);
629   return strcoll (str1, str2);
630 }
631
632 /*** @} */
633
634 /*
635   Local Variables:
636   coding: euc-japan
637   End:
638 */