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