Include word-thai.h.
[m17n/m17n-lib.git] / src / mtext.c
1 /* mtext.c -- M-text module.
2    Copyright (C) 2003, 2004, 2005
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., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nMtext
25     @brief M-text objects and API for them.
26
27     In the m17n library, text is represented as an object called @e
28     M-text rather than as a C-string (<tt>char *</tt> or <tt>unsigned
29     char *</tt>).  An M-text is a sequence of characters whose length
30     is equals to or more than 0, and can be coined from various
31     character sources, e.g. C-strings, files, character codes, etc.
32
33     M-texts are more useful than C-strings in the following points.
34
35     @li M-texts can handle mixture of characters of various scripts,
36     including all Unicode characters and more.  This is an
37     indispensable facility when handling multilingual text.
38
39     @li Each character in an M-text can have properties called @e text
40     @e properties. Text properties store various kinds of information
41     attached to parts of an M-text to provide application programs
42     with a unified view of those information.  As rich information can
43     be stored in M-texts in the form of text properties, functions in
44     application programs can be simple.
45
46     In addition, the library provides many functions to manipulate an
47     M-text just the same way as a C-string.  */
48
49 /***ja
50     @addtogroup m17nMtext
51
52     @brief M-text ¥ª¥Ö¥¸¥§¥¯¥È¤È¤½¤ì¤Ë´Ø¤¹¤ë API.
53
54     m17n ¥é¥¤¥Ö¥é¥ê¤Ï¡¢ C-string¡Ê<tt>char *</tt> ¤ä <tt>unsigned
55     char *</tt>¡Ë¤Ç¤Ï¤Ê¤¯ @e M-text ¤È¸Æ¤Ö¥ª¥Ö¥¸¥§¥¯¥È¤Ç¥Æ¥­¥¹¥È¤òɽ¸½¤¹¤ë¡£
56     M-text ¤ÏŤµ 0 °Ê¾å¤Îʸ»úÎó¤Ç¤¢¤ê¡¢¼ï¡¹¤Îʸ»ú¥½¡¼¥¹¡Ê¤¿¤È¤¨¤Ð 
57     C-string¡¢¥Õ¥¡¥¤¥ë¡¢Ê¸»ú¥³¡¼¥ÉÅù¡Ë¤«¤éºîÀ®¤Ç¤­¤ë¡£
58
59     M-text ¤Ë¤Ï¡¢C-string ¤Ë¤Ê¤¤°Ê²¼¤ÎÆÃħ¤¬¤¢¤ë¡£     
60
61     @li M-text ¤ÏÈó¾ï¤Ë¿¤¯¤Î¼ïÎà¤Îʸ»ú¤ò¡¢Æ±»þ¤Ë¡¢º®ºß¤µ¤»¤Æ¡¢Æ±Åù¤Ë°·¤¦¤³¤È¤¬¤Ç¤­¤ë¡£
62     Unicode ¤ÎÁ´¤Æ¤Îʸ»ú¤Ï¤â¤Á¤í¤ó¡¢¤è¤ê¿¤¯¤Îʸ»ú¤Þ¤Ç¤â°·¤¦¤³¤È¤¬¤Ç¤­¤ë¡£
63     ¤³¤ì¤Ï¿¸À¸ì¥Æ¥­¥¹¥È¤ò°·¤¦¾å¤Ç¤Ïɬ¿Ü¤Îµ¡Ç½¤Ç¤¢¤ë¡£
64
65     @li M-text Æâ¤Î³Æʸ»ú¤Ï¡¢@e ¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ 
66     ¤È¸Æ¤Ð¤ì¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢
67     ¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ë¤è¤Ã¤Æ¡¢¥Æ¥­¥¹¥È¤Î³ÆÉô°Ì¤Ë´Ø¤¹¤ëÍÍ¡¹¤Ê¾ðÊó¤ò
68     M-text Æâ¤ËÊÝ»ý¤¹¤ë¤³¤È¤¬²Äǽ¤Ë¤Ê¤ë¡£
69     ¤½¤Î¤¿¤á¡¢¤½¤ì¤é¤Î¾ðÊó¤ò¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥àÆâ¤ÇÅý°ìŪ¤Ë°·¤¦¤³¤È¤¬²Äǽ¤Ë¤Ê¤ë¡£
70     ¤Þ¤¿¡¢M-text 
71     ¼«ÂΤ¬Ë­É٤ʾðÊó¤ò»ý¤Ä¤¿¤á¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥àÃæ¤Î³Æ´Ø¿ô¤ò´ÊÁDz½¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
72
73     ¤µ¤é¤Ëm17n ¥é¥¤¥Ö¥é¥ê¤Ï¡¢ C-string 
74     ¤òÁàºî¤¹¤ë¤¿¤á¤ËÄ󶡤µ¤ì¤ë¼ï¡¹¤Î´Ø¿ô¤ÈƱÅù¤Î¤â¤Î¤ò M-text 
75     ¤òÁàºî¤¹¤ë¤¿¤á¤Ë¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¡£  */
76
77 /*=*/
78
79 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
80 /*** @addtogroup m17nInternal
81      @{ */
82
83 #include <config.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <locale.h>
88
89 #include "m17n.h"
90 #include "m17n-misc.h"
91 #include "internal.h"
92 #include "textprop.h"
93 #include "character.h"
94 #include "mtext.h"
95 #include "plist.h"
96 #include "word-thai.h"
97
98 static M17NObjectArray mtext_table;
99
100 static MSymbol M_charbag;
101
102 /** Increment character position CHAR_POS and unit position UNIT_POS
103     so that they point to the next character in M-text MT.  No range
104     check for CHAR_POS and UNIT_POS.  */
105
106 #define INC_POSITION(mt, char_pos, unit_pos)                    \
107   do {                                                          \
108     int c;                                                      \
109                                                                 \
110     if ((mt)->format <= MTEXT_FORMAT_UTF_8)                     \
111       {                                                         \
112         c = (mt)->data[(unit_pos)];                             \
113         (unit_pos) += CHAR_UNITS_BY_HEAD_UTF8 (c);              \
114       }                                                         \
115     else if ((mt)->format <= MTEXT_FORMAT_UTF_16BE)             \
116       {                                                         \
117         c = ((unsigned short *) ((mt)->data))[(unit_pos)];      \
118                                                                 \
119         if ((mt)->format != MTEXT_FORMAT_UTF_16)                \
120           c = SWAP_16 (c);                                      \
121         (unit_pos) += CHAR_UNITS_BY_HEAD_UTF16 (c);             \
122       }                                                         \
123     else                                                        \
124       (unit_pos)++;                                             \
125     (char_pos)++;                                               \
126   } while (0)
127
128
129 /** Decrement character position CHAR_POS and unit position UNIT_POS
130     so that they point to the previous character in M-text MT.  No
131     range check for CHAR_POS and UNIT_POS.  */
132
133 #define DEC_POSITION(mt, char_pos, unit_pos)                            \
134   do {                                                                  \
135     if ((mt)->format <= MTEXT_FORMAT_UTF_8)                             \
136       {                                                                 \
137         unsigned char *p1 = (mt)->data + (unit_pos);                    \
138         unsigned char *p0 = p1 - 1;                                     \
139                                                                         \
140         while (! CHAR_HEAD_P (p0)) p0--;                                \
141         (unit_pos) -= (p1 - p0);                                        \
142       }                                                                 \
143     else if ((mt)->format <= MTEXT_FORMAT_UTF_16BE)                     \
144       {                                                                 \
145         int c = ((unsigned short *) ((mt)->data))[(unit_pos) - 1];      \
146                                                                         \
147         if ((mt)->format != MTEXT_FORMAT_UTF_16)                        \
148           c = SWAP_16 (c);                                              \
149         (unit_pos) -= 2 - (c < 0xD800 || c >= 0xE000);                  \
150       }                                                                 \
151     else                                                                \
152       (unit_pos)--;                                                     \
153     (char_pos)--;                                                       \
154   } while (0)
155
156
157 /* Compoare sub-texts in MT1 (range FROM1 and TO1) and MT2 (range
158    FROM2 to TO2). */
159
160 static int
161 compare (MText *mt1, int from1, int to1, MText *mt2, int from2, int to2)
162 {
163   if (mt1->format == mt2->format
164       && (mt1->format <= MTEXT_FORMAT_UTF_8))
165     {
166       unsigned char *p1, *pend1, *p2, *pend2;
167       int unit_bytes = UNIT_BYTES (mt1->format);
168       int nbytes;
169       int result;
170
171       p1 = mt1->data + mtext__char_to_byte (mt1, from1) * unit_bytes;
172       pend1 = mt1->data + mtext__char_to_byte (mt1, to1) * unit_bytes;
173
174       p2 = mt2->data + mtext__char_to_byte (mt2, from2) * unit_bytes;
175       pend2 = mt2->data + mtext__char_to_byte (mt2, to2) * unit_bytes;
176
177       if (pend1 - p1 < pend2 - p2)
178         nbytes = pend1 - p1;
179       else
180         nbytes = pend2 - p2;
181       result = memcmp (p1, p2, nbytes);
182       if (result)
183         return result;
184       return ((pend1 - p1) - (pend2 - p2));
185     }
186   for (; from1 < to1 && from2 < to2; from1++, from2++)
187     {
188       int c1 = mtext_ref_char (mt1, from1);
189       int c2 = mtext_ref_char (mt2, from2);
190
191       if (c1 != c2)
192         return (c1 > c2 ? 1 : -1);
193     }
194   return (from2 == to2 ? (from1 < to1) : -1);
195 }
196
197
198 /* Return how many units are required in UTF-8 to represent characters
199    between FROM and TO of MT.  */
200
201 static int
202 count_by_utf_8 (MText *mt, int from, int to)
203 {
204   int n, c;
205
206   for (n = 0; from < to; from++)
207     {
208       c = mtext_ref_char (mt, from);
209       n += CHAR_UNITS_UTF8 (c);
210     }
211   return n;
212 }
213
214
215 /* Return how many units are required in UTF-16 to represent
216    characters between FROM and TO of MT.  */
217
218 static int
219 count_by_utf_16 (MText *mt, int from, int to)
220 {
221   int n, c;
222
223   for (n = 0; from < to; from++)
224     {
225       c = mtext_ref_char (mt, from);
226       n += CHAR_UNITS_UTF16 (c);
227     }
228   return n;
229 }
230
231
232 /* Insert text between FROM and TO of MT2 at POS of MT1.  */
233
234 static MText *
235 insert (MText *mt1, int pos, MText *mt2, int from, int to)
236 {
237   int pos_unit = POS_CHAR_TO_BYTE (mt1, pos);
238   int from_unit = POS_CHAR_TO_BYTE (mt2, from);
239   int new_units = POS_CHAR_TO_BYTE (mt2, to) - from_unit;
240   int unit_bytes;
241
242   if (mt1->nchars == 0)
243     mt1->format = mt2->format;
244   else if (mt1->format != mt2->format)
245     {
246       /* Be sure to make mt1->format sufficient to contain all
247          characters in mt2.  */
248       if (mt1->format == MTEXT_FORMAT_UTF_8
249           || mt1->format == MTEXT_FORMAT_UTF_32
250           || (mt1->format == MTEXT_FORMAT_UTF_16
251               && mt2->format <= MTEXT_FORMAT_UTF_16BE
252               && mt2->format != MTEXT_FORMAT_UTF_8))
253         ;
254       else if (mt1->format == MTEXT_FORMAT_US_ASCII)
255         {
256           if (mt2->format == MTEXT_FORMAT_UTF_8)
257             mt1->format = MTEXT_FORMAT_UTF_8;
258           else if (mt2->format == MTEXT_FORMAT_UTF_16
259                    || mt2->format == MTEXT_FORMAT_UTF_32)
260             mtext__adjust_format (mt1, mt2->format);
261           else
262             mtext__adjust_format (mt1, MTEXT_FORMAT_UTF_8);
263         }
264       else
265         {
266           mtext__adjust_format (mt1, MTEXT_FORMAT_UTF_8);
267           pos_unit = POS_CHAR_TO_BYTE (mt1, pos);
268         }
269     }
270
271   unit_bytes = UNIT_BYTES (mt1->format);
272
273   if (mt1->format == mt2->format)
274     {
275       int pos_byte = pos_unit * unit_bytes;
276       int total_bytes = (mt1->nbytes + new_units) * unit_bytes;
277       int new_bytes = new_units * unit_bytes;
278
279       if (total_bytes + unit_bytes > mt1->allocated)
280         {
281           mt1->allocated = total_bytes + unit_bytes;
282           MTABLE_REALLOC (mt1->data, mt1->allocated, MERROR_MTEXT);
283         }
284       if (pos < mt1->nchars)
285         memmove (mt1->data + pos_byte + new_bytes, mt1->data + pos_byte,
286                  (mt1->nbytes - pos_unit + 1) * unit_bytes);
287       memcpy (mt1->data + pos_byte, mt2->data + from_unit * unit_bytes,
288               new_bytes);
289     }
290   else if (mt1->format == MTEXT_FORMAT_UTF_8)
291     {
292       unsigned char *p;
293       int total_bytes, i, c;
294
295       new_units = count_by_utf_8 (mt2, from, to);
296       total_bytes = mt1->nbytes + new_units;
297
298       if (total_bytes + 1 > mt1->allocated)
299         {
300           mt1->allocated = total_bytes + 1;
301           MTABLE_REALLOC (mt1->data, mt1->allocated, MERROR_MTEXT);
302         }
303       p = mt1->data + pos_unit;
304       memmove (p + new_units, p, mt1->nbytes - pos_unit + 1);
305       for (i = from; i < to; i++)
306         {
307           c = mtext_ref_char (mt2, i);
308           p += CHAR_STRING_UTF8 (c, p);
309         }
310     }
311   else if (mt1->format == MTEXT_FORMAT_UTF_16)
312     {
313       unsigned short *p;
314       int total_bytes, i, c;
315
316       new_units = count_by_utf_16 (mt2, from, to);
317       total_bytes = (mt1->nbytes + new_units) * USHORT_SIZE;
318
319       if (total_bytes + USHORT_SIZE > mt1->allocated)
320         {
321           mt1->allocated = total_bytes + USHORT_SIZE;
322           MTABLE_REALLOC (mt1->data, mt1->allocated, MERROR_MTEXT);
323         }
324       p = (unsigned short *) mt1->data + pos_unit;
325       memmove (p + new_units, p,
326                (mt1->nbytes - pos_unit + 1) * USHORT_SIZE);
327       for (i = from; i < to; i++)
328         {
329           c = mtext_ref_char (mt2, i);
330           p += CHAR_STRING_UTF16 (c, p);
331         }
332     }
333   else                          /* MTEXT_FORMAT_UTF_32 */
334     {
335       unsigned int *p;
336       int total_bytes, i;
337
338       new_units = to - from;
339       total_bytes = (mt1->nbytes + new_units) * UINT_SIZE;
340
341       if (total_bytes + UINT_SIZE > mt1->allocated)
342         {
343           mt1->allocated = total_bytes + UINT_SIZE;
344           MTABLE_REALLOC (mt1->data, mt1->allocated, MERROR_MTEXT);
345         }
346       p = (unsigned *) mt1->data + pos_unit;
347       memmove (p + new_units, p,
348                (mt1->nbytes - pos_unit + 1) * UINT_SIZE);
349       for (i = from; i < to; i++)
350         *p++ = mtext_ref_char (mt2, i);
351     }
352
353   mtext__adjust_plist_for_insert
354     (mt1, pos, to - from,
355      mtext__copy_plist (mt2->plist, from, to, mt1, pos));
356   mt1->nchars += to - from;
357   mt1->nbytes += new_units;
358   if (mt1->cache_char_pos > pos)
359     {
360       mt1->cache_char_pos += to - from;
361       mt1->cache_byte_pos += new_units;
362     }
363
364   return mt1;
365 }
366
367
368 static MCharTable *
369 get_charbag (MText *mt)
370 {
371   MTextProperty *prop = mtext_get_property (mt, 0, M_charbag);
372   MCharTable *table;
373   int i;
374
375   if (prop)
376     {
377       if (prop->end == mt->nchars)
378         return ((MCharTable *) prop->val);
379       mtext_detach_property (prop);
380     }
381
382   table = mchartable (Msymbol, (void *) 0);
383   for (i = mt->nchars - 1; i >= 0; i--)
384     mchartable_set (table, mtext_ref_char (mt, i), Mt);
385   prop = mtext_property (M_charbag, table, MTEXTPROP_VOLATILE_WEAK);
386   mtext_attach_property (mt, 0, mtext_nchars (mt), prop);
387   M17N_OBJECT_UNREF (prop);
388   return table;
389 }
390
391
392 /* span () : Number of consecutive chars starting at POS in MT1 that
393    are included (if NOT is Mnil) or not included (if NOT is Mt) in
394    MT2.  */
395
396 static int
397 span (MText *mt1, MText *mt2, int pos, MSymbol not)
398 {
399   int nchars = mtext_nchars (mt1);
400   MCharTable *table = get_charbag (mt2);
401   int i;
402
403   for (i = pos; i < nchars; i++)
404     if ((MSymbol) mchartable_lookup (table, mtext_ref_char (mt1, i)) == not)
405       break;
406   return (i - pos);
407 }
408
409
410 static int
411 count_utf_8_chars (const void *data, int nitems)
412 {
413   unsigned char *p = (unsigned char *) data;
414   unsigned char *pend = p + nitems;
415   int nchars = 0;
416
417   while (p < pend)
418     {
419       int i, n;
420
421       for (; p < pend && *p < 128; nchars++, p++);
422       if (p == pend)
423         return nchars;
424       if (! CHAR_HEAD_P_UTF8 (p))
425         return -1;
426       n = CHAR_UNITS_BY_HEAD_UTF8 (*p);
427       if (p + n > pend)
428         return -1;
429       for (i = 1; i < n; i++)
430         if (CHAR_HEAD_P_UTF8 (p + i))
431           return -1;
432       p += n;
433       nchars++;
434     }
435   return nchars;
436 }
437
438 static int
439 count_utf_16_chars (const void *data, int nitems, int swap)
440 {
441   unsigned short *p = (unsigned short *) data;
442   unsigned short *pend = p + nitems;
443   int nchars = 0;
444   int prev_surrogate = 0;
445
446   for (; p < pend; p++)
447     {
448       int c = *p;
449
450       if (swap)
451         c = SWAP_16 (c);
452       if (prev_surrogate)
453         {
454           if (c < 0xDC00 || c >= 0xE000)
455             /* Invalid surrogate */
456             nchars++;
457         }
458       else
459         {
460           if (c >= 0xD800 && c < 0xDC00)
461             prev_surrogate = 1;
462           nchars++;
463         }
464     }
465   if (prev_surrogate)
466     nchars++;
467   return nchars;
468 }
469
470
471 static int
472 find_char_forward (MText *mt, int from, int to, int c)
473 {
474   int from_byte = POS_CHAR_TO_BYTE (mt, from);
475
476   if (mt->format <= MTEXT_FORMAT_UTF_8)
477     {
478       unsigned char *p = mt->data + from_byte;
479
480       while (from < to && STRING_CHAR_ADVANCE_UTF8 (p) != c) from++;
481     }
482   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
483     {
484       unsigned short *p = (unsigned short *) (mt->data) + from_byte;
485
486       if (mt->format == MTEXT_FORMAT_UTF_16)
487         while (from < to && STRING_CHAR_ADVANCE_UTF16 (p) != c) from++;
488       else if (c < 0x10000)
489         {
490           c = SWAP_16 (c);
491           while (from < to && *p != c)
492             {
493               from++;
494               p += ((*p & 0xFF) < 0xD8 || (*p & 0xFF) >= 0xE0) ? 1 : 2;
495             }
496         }
497       else if (c < 0x110000)
498         {
499           int c1 = (c >> 10) + 0xD800;
500           int c2 = (c & 0x3FF) + 0xDC00;
501
502           c1 = SWAP_16 (c1);
503           c2 = SWAP_16 (c2);
504           while (from < to && (*p != c1 || p[1] != c2))
505             {
506               from++;
507               p += ((*p & 0xFF) < 0xD8 || (*p & 0xFF) >= 0xE0) ? 1 : 2;
508             }
509         }
510       else
511         from = to;
512     }
513   else
514     {
515       unsigned *p = (unsigned *) (mt->data) + from_byte;
516       unsigned c1 = c;
517
518       if (mt->format != MTEXT_FORMAT_UTF_32)
519         c1 = SWAP_32 (c1);
520       while (from < to && *p++ != c1) from++;
521     }
522
523   return (from < to ? from : -1);
524 }
525
526
527 static int
528 find_char_backward (MText *mt, int from, int to, int c)
529 {
530   int to_byte = POS_CHAR_TO_BYTE (mt, to);
531
532   if (mt->format <= MTEXT_FORMAT_UTF_8)
533     {
534       unsigned char *p = mt->data + to_byte;
535
536       while (from < to)
537         {
538           for (p--; ! CHAR_HEAD_P (p); p--);
539           if (c == STRING_CHAR (p))
540             break;
541           to--;
542         }
543     }
544   else if (mt->format <= MTEXT_FORMAT_UTF_16LE)
545     {
546       unsigned short *p = (unsigned short *) (mt->data) + to_byte;
547
548       if (mt->format == MTEXT_FORMAT_UTF_16)
549         {
550           while (from < to)
551             {
552               p--;
553               if (*p >= 0xDC00 && *p < 0xE000)
554                 p--;
555               if (c == STRING_CHAR_UTF16 (p))
556                 break;
557               to--;
558             }
559         }
560       else if (c < 0x10000)
561         {
562           c = SWAP_16 (c);
563           while (from < to && p[-1] != c)
564             {
565               to--;
566               p -= ((p[-1] & 0xFF) < 0xD8 || (p[-1] & 0xFF) >= 0xE0) ? 1 : 2;
567             }
568         }
569       else if (c < 0x110000)
570         {
571           int c1 = (c >> 10) + 0xD800;
572           int c2 = (c & 0x3FF) + 0xDC00;
573
574           c1 = SWAP_16 (c1);
575           c2 = SWAP_16 (c2);
576           while (from < to && (p[-1] != c2 || p[-2] != c1))
577             {
578               to--;
579               p -= ((p[-1] & 0xFF) < 0xD8 || (p[-1] & 0xFF) >= 0xE0) ? 1 : 2;
580             }
581         }
582     }
583   else
584     {
585       unsigned *p = (unsigned *) (mt->data) + to_byte;
586       unsigned c1 = c;
587
588       if (mt->format != MTEXT_FORMAT_UTF_32)
589         c1 = SWAP_32 (c1);
590       while (from < to && p[-1] != c1) to--, p--;
591     }
592
593   return (from < to ? to - 1 : -1);
594 }
595
596
597 static void
598 free_mtext (void *object)
599 {
600   MText *mt = (MText *) object;
601
602   if (mt->plist)
603     mtext__free_plist (mt);
604   if (mt->data && mt->allocated >= 0)
605     free (mt->data);
606   M17N_OBJECT_UNREGISTER (mtext_table, mt);
607   free (object);
608 }
609
610 /** Structure for an iterator used in case-fold comparison.  */
611
612 struct casecmp_iterator {
613   MText *mt;
614   int pos;
615   MText *folded;
616   unsigned char *foldedp;
617   int folded_len;
618 };
619
620 static int
621 next_char_from_it (struct casecmp_iterator *it)
622 {
623   int c, c1;
624
625   if (it->folded)
626     {
627       c = STRING_CHAR_AND_BYTES (it->foldedp, it->folded_len);
628       return c;
629     }
630
631   c = mtext_ref_char (it->mt, it->pos);
632   c1 = (int) mchar_get_prop (c, Msimple_case_folding);
633   if (c1 == 0xFFFF)
634     {
635       it->folded
636         = (MText *) mchar_get_prop (c, Mcomplicated_case_folding);
637       it->foldedp = it->folded->data;
638       c = STRING_CHAR_AND_BYTES (it->foldedp, it->folded_len);
639       return c;
640     }
641
642   if (c1 >= 0)
643     c = c1;
644   return c;
645 }
646
647 static void
648 advance_it (struct casecmp_iterator *it)
649 {
650   if (it->folded)
651     {
652       it->foldedp += it->folded_len;
653       if (it->foldedp == it->folded->data + it->folded->nbytes)
654         it->folded = NULL;
655     }
656   if (! it->folded)
657     {
658       it->pos++;
659     }
660 }
661
662 static int
663 case_compare (MText *mt1, int from1, int to1, MText *mt2, int from2, int to2)
664 {
665   struct casecmp_iterator it1, it2;
666
667   it1.mt = mt1, it1.pos = from1, it1.folded = NULL;
668   it2.mt = mt2, it2.pos = from2, it2.folded = NULL;
669
670   while (it1.pos < to1 && it2.pos < to2)
671     {
672       int c1 = next_char_from_it (&it1);
673       int c2 = next_char_from_it (&it2);
674
675       if (c1 != c2)
676         return (c1 > c2 ? 1 : -1);
677       advance_it (&it1);
678       advance_it (&it2);
679     }
680   return (it2.pos == to2 ? (it1.pos < to1) : -1);
681 }
682
683 \f
684 /* Internal API */
685
686 MCharTable *wordseg_func_table;
687
688 int
689 mtext__init ()
690 {
691   M_charbag = msymbol_as_managing_key ("  charbag");
692   mtext_table.count = 0;
693   wordseg_func_table = mchartable (Mnil, NULL);
694   mtext__word_thai_init ();
695   return 0;
696 }
697
698
699 void
700 mtext__fini (void)
701 {
702   mtext__word_thai_fini ();
703   M17N_OBJECT_UNREF (wordseg_func_table);
704   wordseg_func_table = NULL;
705   mdebug__report_object ("M-text", &mtext_table);
706 }
707
708
709 int
710 mtext__char_to_byte (MText *mt, int pos)
711 {
712   int char_pos, byte_pos;
713   int forward;
714
715   if (pos < mt->cache_char_pos)
716     {
717       if (mt->cache_char_pos == mt->cache_byte_pos)
718         return pos;
719       if (pos < mt->cache_char_pos - pos)
720         {
721           char_pos = byte_pos = 0;
722           forward = 1;
723         }
724       else
725         {
726           char_pos = mt->cache_char_pos;
727           byte_pos = mt->cache_byte_pos;
728           forward = 0;
729         }
730     }
731   else
732     {
733       if (mt->nchars - mt->cache_char_pos == mt->nbytes - mt->cache_byte_pos)
734         return (mt->cache_byte_pos + (pos - mt->cache_char_pos));
735       if (pos - mt->cache_char_pos < mt->nchars - pos)
736         {
737           char_pos = mt->cache_char_pos;
738           byte_pos = mt->cache_byte_pos;
739           forward = 1;
740         }
741       else
742         {
743           char_pos = mt->nchars;
744           byte_pos = mt->nbytes;
745           forward = 0;
746         }
747     }
748   if (forward)
749     while (char_pos < pos)
750       INC_POSITION (mt, char_pos, byte_pos);
751   else
752     while (char_pos > pos)
753       DEC_POSITION (mt, char_pos, byte_pos);
754   mt->cache_char_pos = char_pos;
755   mt->cache_byte_pos = byte_pos;
756   return byte_pos;
757 }
758
759 /* mtext__byte_to_char () */
760
761 int
762 mtext__byte_to_char (MText *mt, int pos_byte)
763 {
764   int char_pos, byte_pos;
765   int forward;
766
767   if (pos_byte < mt->cache_byte_pos)
768     {
769       if (mt->cache_char_pos == mt->cache_byte_pos)
770         return pos_byte;
771       if (pos_byte < mt->cache_byte_pos - pos_byte)
772         {
773           char_pos = byte_pos = 0;
774           forward = 1;
775         }
776       else
777         {
778           char_pos = mt->cache_char_pos;
779           byte_pos = mt->cache_byte_pos;
780           forward = 0;
781         }
782     }
783   else
784     {
785       if (mt->nchars - mt->cache_char_pos == mt->nbytes - mt->cache_byte_pos)
786         return (mt->cache_char_pos + (pos_byte - mt->cache_byte_pos));
787       if (pos_byte - mt->cache_byte_pos < mt->nbytes - pos_byte)
788         {
789           char_pos = mt->cache_char_pos;
790           byte_pos = mt->cache_byte_pos;
791           forward = 1;
792         }
793       else
794         {
795           char_pos = mt->nchars;
796           byte_pos = mt->nbytes;
797           forward = 0;
798         }
799     }
800   if (forward)
801     while (byte_pos < pos_byte)
802       INC_POSITION (mt, char_pos, byte_pos);
803   else
804     while (byte_pos > pos_byte)
805       DEC_POSITION (mt, char_pos, byte_pos);
806   mt->cache_char_pos = char_pos;
807   mt->cache_byte_pos = byte_pos;
808   return char_pos;
809 }
810
811 /* Estimated extra bytes that malloc will use for its own purpose on
812    each memory allocation.  */
813 #define MALLOC_OVERHEAD 4
814 #define MALLOC_MININUM_BYTES 12
815
816 void
817 mtext__enlarge (MText *mt, int nbytes)
818 {
819   nbytes += MAX_UTF8_CHAR_BYTES;
820   if (mt->allocated >= nbytes)
821     return;
822   if (nbytes < MALLOC_MININUM_BYTES)
823     nbytes = MALLOC_MININUM_BYTES;
824   while (mt->allocated < nbytes)
825     mt->allocated = mt->allocated * 2 + MALLOC_OVERHEAD;
826   MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
827 }
828
829 int
830 mtext__takein (MText *mt, int nchars, int nbytes)
831 {
832   if (mt->plist)
833     mtext__adjust_plist_for_insert (mt, mt->nchars, nchars, NULL);
834   mt->nchars += nchars;
835   mt->nbytes += nbytes;
836   mt->data[mt->nbytes] = 0;
837   return 0;
838 }
839
840
841 int
842 mtext__cat_data (MText *mt, unsigned char *p, int nbytes,
843                  enum MTextFormat format)
844 {
845   int nchars = -1;
846
847   if (mt->format > MTEXT_FORMAT_UTF_8)
848     MERROR (MERROR_MTEXT, -1);
849   if (format == MTEXT_FORMAT_US_ASCII)
850     nchars = nbytes;
851   else if (format == MTEXT_FORMAT_UTF_8)
852     nchars = count_utf_8_chars (p, nbytes);
853   if (nchars < 0)
854     MERROR (MERROR_MTEXT, -1);
855   mtext__enlarge (mt, mtext_nbytes (mt) + nbytes + 1);
856   memcpy (MTEXT_DATA (mt) + mtext_nbytes (mt), p, nbytes);
857   mtext__takein (mt, nchars, nbytes);
858   return nchars;
859 }
860
861 MText *
862 mtext__from_data (const void *data, int nitems, enum MTextFormat format,
863                   int need_copy)
864 {
865   MText *mt;
866   int nchars, nbytes, unit_bytes;
867
868   if (format == MTEXT_FORMAT_US_ASCII)
869     {
870       const char *p = (char *) data, *pend = p + nitems;
871
872       while (p < pend)
873         if (*p++ < 0)
874           MERROR (MERROR_MTEXT, NULL);
875       nchars = nbytes = nitems;
876       unit_bytes = 1;
877     }
878   else if (format == MTEXT_FORMAT_UTF_8)
879     {
880       if ((nchars = count_utf_8_chars (data, nitems)) < 0)
881         MERROR (MERROR_MTEXT, NULL);
882       nbytes = nitems;
883       unit_bytes = 1;
884     }
885   else if (format <= MTEXT_FORMAT_UTF_16BE)
886     {
887       if ((nchars = count_utf_16_chars (data, nitems,
888                                         format != MTEXT_FORMAT_UTF_16)) < 0)
889         MERROR (MERROR_MTEXT, NULL);
890       nbytes = USHORT_SIZE * nitems;
891       unit_bytes = USHORT_SIZE;
892     }
893   else                          /* MTEXT_FORMAT_UTF_32XX */
894     {
895       nchars = nitems;
896       nbytes = UINT_SIZE * nitems;
897       unit_bytes = UINT_SIZE;
898     }
899
900   mt = mtext ();
901   mt->format = format;
902   mt->allocated = need_copy ? nbytes + unit_bytes : -1;
903   mt->nchars = nchars;
904   mt->nbytes = nitems;
905   if (need_copy)
906     {
907       MTABLE_MALLOC (mt->data, mt->allocated, MERROR_MTEXT);
908       memcpy (mt->data, data, nbytes);
909       mt->data[nbytes] = 0;
910     }
911   else
912     mt->data = (unsigned char *) data;
913   return mt;
914 }
915
916
917 void
918 mtext__adjust_format (MText *mt, enum MTextFormat format)
919 {
920   int i, c;
921
922   if (mt->nchars > 0)
923     switch (format)
924       {
925       case MTEXT_FORMAT_US_ASCII:
926         {
927           unsigned char *p = mt->data;
928
929           for (i = 0; i < mt->nchars; i++)
930             *p++ = mtext_ref_char (mt, i);
931           mt->nbytes = mt->nchars;
932           mt->cache_byte_pos = mt->cache_char_pos;
933           break;
934         }
935
936       case MTEXT_FORMAT_UTF_8:
937         {
938           unsigned char *p0, *p1;
939
940           i = count_by_utf_8 (mt, 0, mt->nchars) + 1;
941           MTABLE_MALLOC (p0, i, MERROR_MTEXT);
942           mt->allocated = i;
943           for (i = 0, p1 = p0; i < mt->nchars; i++)
944             {
945               c = mtext_ref_char (mt, i);
946               p1 += CHAR_STRING_UTF8 (c, p1);
947             }
948           *p1 = '\0';
949           free (mt->data);
950           mt->data = p0;
951           mt->nbytes = p1 - p0;
952           mt->cache_char_pos = mt->cache_byte_pos = 0;
953           break;
954         }
955
956       default:
957         if (format == MTEXT_FORMAT_UTF_16)
958           {
959             unsigned short *p0, *p1;
960
961             i = (count_by_utf_16 (mt, 0, mt->nchars) + 1) * USHORT_SIZE;
962             MTABLE_MALLOC (p0, i, MERROR_MTEXT);
963             mt->allocated = i;
964             for (i = 0, p1 = p0; i < mt->nchars; i++)
965               {
966                 c = mtext_ref_char (mt, i);
967                 p1 += CHAR_STRING_UTF16 (c, p1);
968               }
969             *p1 = 0;
970             free (mt->data);
971             mt->data = (unsigned char *) p0;
972             mt->nbytes = p1 - p0;
973             mt->cache_char_pos = mt->cache_byte_pos = 0;
974             break;
975           }
976         else
977           {
978             unsigned int *p;
979
980             mt->allocated = (mt->nchars + 1) * UINT_SIZE;
981             MTABLE_MALLOC (p, mt->allocated, MERROR_MTEXT);
982             for (i = 0; i < mt->nchars; i++)
983               p[i] = mtext_ref_char (mt, i);
984             p[i] = 0;
985             free (mt->data);
986             mt->data = (unsigned char *) p;
987             mt->nbytes = mt->nchars;
988             mt->cache_byte_pos = mt->cache_char_pos;
989           }
990       }
991   mt->format = format;
992 }
993
994
995 /* Find the position of a character at the beginning of a line of
996    M-Text MT searching backward from POS.  */
997
998 int
999 mtext__bol (MText *mt, int pos)
1000 {
1001   int byte_pos;
1002
1003   if (pos == 0)
1004     return pos;
1005   byte_pos = POS_CHAR_TO_BYTE (mt, pos);
1006   if (mt->format <= MTEXT_FORMAT_UTF_8)
1007     {
1008       unsigned char *p = mt->data + byte_pos;
1009
1010       if (p[-1] == '\n')
1011         return pos;
1012       p--;
1013       while (p > mt->data && p[-1] != '\n')
1014         p--;
1015       if (p == mt->data)
1016         return 0;
1017       byte_pos = p - mt->data;
1018       return POS_BYTE_TO_CHAR (mt, byte_pos);
1019     }
1020   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1021     {
1022       unsigned short *p = ((unsigned short *) (mt->data)) + byte_pos;
1023       unsigned short newline = (mt->format == MTEXT_FORMAT_UTF_16
1024                                 ? 0x0A00 : 0x000A);
1025
1026       if (p[-1] == newline)
1027         return pos;
1028       p--;
1029       while (p > (unsigned short *) (mt->data) && p[-1] != newline)
1030         p--;
1031       if (p == (unsigned short *) (mt->data))
1032         return 0;
1033       byte_pos = p - (unsigned short *) (mt->data);
1034       return POS_BYTE_TO_CHAR (mt, byte_pos);;
1035     }
1036   else
1037     {
1038       unsigned *p = ((unsigned *) (mt->data)) + byte_pos;
1039       unsigned newline = (mt->format == MTEXT_FORMAT_UTF_32
1040                           ? 0x0A000000 : 0x0000000A);
1041
1042       if (p[-1] == newline)
1043         return pos;
1044       p--, pos--;
1045       while (p > (unsigned *) (mt->data) && p[-1] != newline)
1046         p--, pos--;
1047       return pos;
1048     }
1049 }
1050
1051
1052 /* Find the position of a character at the end of a line of M-Text MT
1053    searching forward from POS.  */
1054
1055 int
1056 mtext__eol (MText *mt, int pos)
1057 {
1058   int byte_pos;
1059
1060   if (pos == mt->nchars)
1061     return pos;
1062   byte_pos = POS_CHAR_TO_BYTE (mt, pos);
1063   if (mt->format <= MTEXT_FORMAT_UTF_8)
1064     {
1065       unsigned char *p = mt->data + byte_pos;
1066       unsigned char *endp;
1067
1068       if (*p == '\n')
1069         return pos + 1;
1070       p++;
1071       endp = mt->data + mt->nbytes;
1072       while (p < endp && *p != '\n')
1073         p++;
1074       if (p == endp)
1075         return mt->nchars;
1076       byte_pos = p + 1 - mt->data;
1077       return POS_BYTE_TO_CHAR (mt, byte_pos);
1078     }
1079   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1080     {
1081       unsigned short *p = ((unsigned short *) (mt->data)) + byte_pos;
1082       unsigned short *endp;
1083       unsigned short newline = (mt->format == MTEXT_FORMAT_UTF_16
1084                                 ? 0x0A00 : 0x000A);
1085
1086       if (*p == newline)
1087         return pos + 1;
1088       p++;
1089       endp = (unsigned short *) (mt->data) + mt->nbytes;
1090       while (p < endp && *p != newline)
1091         p++;
1092       if (p == endp)
1093         return mt->nchars;
1094       byte_pos = p + 1 - (unsigned short *) (mt->data);
1095       return POS_BYTE_TO_CHAR (mt, byte_pos);
1096     }
1097   else
1098     {
1099       unsigned *p = ((unsigned *) (mt->data)) + byte_pos;
1100       unsigned *endp;
1101       unsigned newline = (mt->format == MTEXT_FORMAT_UTF_32
1102                           ? 0x0A000000 : 0x0000000A);
1103
1104       if (*p == newline)
1105         return pos + 1;
1106       p++, pos++;
1107       endp = (unsigned *) (mt->data) + mt->nbytes;
1108       while (p < endp && *p != newline)
1109         p++, pos++;
1110       return pos;
1111     }
1112 }
1113
1114 typedef int (*MTextWordsegFunc) (MText *mt, int pos, int *from, int *to);
1115
1116 int
1117 mtext__word_segment (MText *mt, int pos, int *from, int *to)
1118 {
1119   int c = mtext_ref_char (mt, pos);
1120   MTextWordsegFunc func = (MTextWordsegFunc) mchartable_lookup (wordseg_func_table, c);
1121
1122   if (func)
1123     return (func) (mt, pos, from, to);
1124   *from = *to = pos;
1125   return -1;
1126 }
1127
1128
1129 /*** @} */
1130 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1131
1132 \f
1133 /* External API */
1134
1135 #ifdef WORDS_BIGENDIAN
1136 const int MTEXT_FORMAT_UTF_16 = MTEXT_FORMAT_UTF_16BE;
1137 #else
1138 const int MTEXT_FORMAT_UTF_16 = MTEXT_FORMAT_UTF_16LE;
1139 #endif
1140
1141 #ifdef WORDS_BIGENDIAN
1142 const int MTEXT_FORMAT_UTF_32 = MTEXT_FORMAT_UTF_32BE;
1143 #else
1144 const int MTEXT_FORMAT_UTF_32 = MTEXT_FORMAT_UTF_32LE;
1145 #endif
1146
1147 /*** @addtogroup m17nMtext */
1148 /*** @{ */
1149 /*=*/
1150
1151 /***en
1152     @brief Allocate a new M-text.
1153
1154     The mtext () function allocates a new M-text of length 0 and
1155     returns a pointer to it.  The allocated M-text will not be freed
1156     unless the user explicitly does so with the m17n_object_free ()
1157     function.  */
1158
1159 /***ja
1160     @brief ¿·¤·¤¤M-text¤ò³ä¤êÅö¤Æ¤ë.
1161
1162     ´Ø¿ô mtext () ¤Ï¡¢Ä¹¤µ 0 ¤Î¿·¤·¤¤ M-text 
1163     ¤ò³ä¤êÅö¤Æ¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£³ä¤êÅö¤Æ¤é¤ì¤¿ M-text ¤Ï¡¢´Ø¿ô
1164     m17n_object_free () ¤Ë¤è¤Ã¤Æ¥æ¡¼¥¶¤¬ÌÀ¼¨Åª¤Ë¹Ô¤Ê¤ï¤Ê¤¤¸Â¤ê¡¢²òÊü¤µ¤ì¤Ê¤¤¡£
1165
1166     @latexonly \IPAlabel{mtext} @endlatexonly  */
1167
1168 /***
1169     @seealso
1170     m17n_object_free ()  */
1171
1172 MText *
1173 mtext ()
1174 {
1175   MText *mt;
1176
1177   M17N_OBJECT (mt, free_mtext, MERROR_MTEXT);
1178   mt->format = MTEXT_FORMAT_UTF_8;
1179   M17N_OBJECT_REGISTER (mtext_table, mt);
1180   return mt;
1181 }
1182
1183 /***en
1184     @brief Allocate a new M-text with specified data.
1185
1186     The mtext_from_data () function allocates a new M-text whose
1187     character sequence is specified by array $DATA of $NITEMS
1188     elements.  $FORMAT specifies the format of $DATA.
1189
1190     When $FORMAT is either #MTEXT_FORMAT_US_ASCII or
1191     #MTEXT_FORMAT_UTF_8, the contents of $DATA must be of the type @c
1192     unsigned @c char, and $NITEMS counts by byte.
1193
1194     When $FORMAT is either #MTEXT_FORMAT_UTF_16LE or
1195     #MTEXT_FORMAT_UTF_16BE, the contents of $DATA must be of the type
1196     @c unsigned @c short, and $NITEMS counts by unsigned short.
1197
1198     When $FORMAT is either #MTEXT_FORMAT_UTF_32LE or
1199     #MTEXT_FORMAT_UTF_32BE, the contents of $DATA must be of the type
1200     @c unsigned, and $NITEMS counts by unsigned.
1201
1202     The character sequence of the M-text is not modifiable.  
1203     The contents of $DATA must not be modified while the M-text is alive.
1204
1205     The allocated M-text will not be freed unless the user explicitly
1206     does so with the m17n_object_unref () function.  Even in that case,
1207     $DATA is not freed.
1208
1209     @return
1210     If the operation was successful, mtext_from_data () returns a
1211     pointer to the allocated M-text.  Otherwise it returns @c NULL and
1212     assigns an error code to the external variable #merror_code.  */
1213 /***ja
1214     @brief »ØÄê¤Î¥Ç¡¼¥¿¤ò¸µ¤Ë¿·¤·¤¤ M-text ¤ò³ä¤êÅö¤Æ¤ë.
1215
1216     ´Ø¿ô mtext_from_data () ¤Ï¡¢Í×ÁÇ¿ô $NITEMS ¤ÎÇÛÎó $DATA 
1217     ¤Ç»ØÄꤵ¤ì¤¿Ê¸»úÎó¤ò»ý¤Ä¿·¤·¤¤ M-text ¤ò³ä¤êÅö¤Æ¤ë¡£$FORMAT ¤Ï $DATA
1218     ¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤ò¼¨¤¹¡£
1219
1220     $FORMAT ¤¬ #MTEXT_FORMAT_US_ASCII ¤« #MTEXT_FORMAT_UTF_8 ¤Ê¤é¤Ð¡¢
1221     $DATA ¤ÎÆâÍƤϠ@c unsigned @c char ·¿¤Ç¤¢¤ê¡¢$NITEMS 
1222     ¤Ï¥Ð¥¤¥Èñ°Ì¤Çɽ¤µ¤ì¤Æ¤¤¤ë¡£
1223
1224     $FORMAT ¤¬ #MTEXT_FORMAT_UTF_16LE ¤« #MTEXT_FORMAT_UTF_16BE ¤Ê¤é¤Ð¡¢
1225     $DATA ¤ÎÆâÍƤϠ@c unsigned @c short ·¿¤Ç¤¢¤ê¡¢$NITEMS ¤Ï unsigned
1226     short Ã±°Ì¤Ç¤¢¤ë¡£
1227
1228     $FORMAT ¤¬ #MTEXT_FORMAT_UTF_32LE ¤« #MTEXT_FORMAT_UTF_32BE ¤Ê¤é¤Ð¡¢
1229     $DATA ¤ÎÆâÍƤÏ@c unsigned ·¿¤Ç¤¢¤ê¡¢$NITEMS ¤Ï unsigned Ã±°Ì¤Ç¤¢¤ë¡£
1230
1231     ³ä¤êÅö¤Æ¤é¤ì¤¿ M-text ¤Îʸ»úÎó¤ÏÊѹ¹¤Ç¤­¤Ê¤¤¡£$DATA ¤ÎÆâÍƤϠ
1232     M-text ¤¬Í­¸ú¤Ê´Ö¤ÏÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1233
1234     ³ä¤êÅö¤Æ¤é¤ì¤¿ M-text ¤Ï¡¢´Ø¿ô m17n_object_unref () 
1235     ¤Ë¤è¤Ã¤Æ¥æ¡¼¥¶¤¬ÌÀ¼¨Åª¤Ë¹Ô¤Ê¤ï¤Ê¤¤¸Â¤ê¡¢²òÊü¤µ¤ì¤Ê¤¤¡£¤½¤Î¾ì¹ç¤Ç¤â $DATA ¤Ï²òÊü¤µ¤ì¤Ê¤¤¡£
1236
1237     @return 
1238     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_from_data () ¤Ï³ä¤êÅö¤Æ¤é¤ì¤¿M-text 
1239     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·³°ÉôÊÑ¿ô #merror_code 
1240     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1241
1242 /***
1243     @errors
1244     @c MERROR_MTEXT  */
1245
1246 MText *
1247 mtext_from_data (const void *data, int nitems, enum MTextFormat format)
1248 {
1249   if (nitems < 0
1250       || format < MTEXT_FORMAT_US_ASCII || format >= MTEXT_FORMAT_MAX)
1251     MERROR (MERROR_MTEXT, NULL);
1252   return mtext__from_data (data, nitems, format, 0);
1253 }
1254
1255 /*=*/
1256
1257 /***en
1258     @brief Number of characters in M-text.
1259
1260     The mtext_len () function returns the number of characters in
1261     M-text $MT.  */
1262
1263 /***ja
1264     @brief M-text Ãæ¤Îʸ»ú¤Î¿ô.
1265
1266     ´Ø¿ô mtext_len () ¤Ï M-text $MT Ãæ¤Îʸ»ú¤Î¿ô¤òÊÖ¤¹¡£
1267
1268     @latexonly \IPAlabel{mtext_len} @endlatexonly  */
1269
1270 int
1271 mtext_len (MText *mt)
1272 {
1273   return (mt->nchars);
1274 }
1275
1276 /*=*/
1277
1278 /***en
1279     @brief Return the character at the specified position in an M-text.
1280
1281     The mtext_ref_char () function returns the character at $POS in
1282     M-text $MT.  If an error is detected, it returns -1 and assigns an
1283     error code to the external variable #merror_code.  */
1284
1285 /***ja
1286     @brief M-text Ãæ¤Î»ØÄꤵ¤ì¤¿°ÌÃÖ¤Îʸ»ú¤òÊÖ¤¹.
1287
1288     ´Ø¿ô mtext_ref_char () ¤Ï¡¢M-text $MT ¤Î°ÌÃÖ $POS 
1289     ¤Îʸ»ú¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code
1290     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1291
1292     @latexonly \IPAlabel{mtext_ref_char} @endlatexonly  */
1293
1294 /***
1295     @errors
1296     @c MERROR_RANGE  */
1297
1298 int
1299 mtext_ref_char (MText *mt, int pos)
1300 {
1301   int c;
1302
1303   M_CHECK_POS (mt, pos, -1);
1304   if (mt->format <= MTEXT_FORMAT_UTF_8)
1305     {
1306       unsigned char *p = mt->data + POS_CHAR_TO_BYTE (mt, pos);
1307
1308       c = STRING_CHAR_UTF8 (p);
1309     }
1310   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1311     {
1312       unsigned short *p
1313         = (unsigned short *) (mt->data) + POS_CHAR_TO_BYTE (mt, pos);
1314       unsigned short p1[2];
1315
1316       if (mt->format != MTEXT_FORMAT_UTF_16)
1317         {
1318           p1[0] = SWAP_16 (*p);
1319           if (p1[0] >= 0xD800 || p1[0] < 0xDC00)
1320             p1[1] = SWAP_16 (p[1]);
1321           p = p1;
1322         }
1323       c = STRING_CHAR_UTF16 (p);
1324     }
1325   else
1326     {
1327       c = ((unsigned *) (mt->data))[pos];
1328       if (mt->format != MTEXT_FORMAT_UTF_32)
1329         c = SWAP_32 (c);
1330     }
1331   return c;
1332 }
1333
1334 /*=*/
1335
1336 /***en
1337     @brief Store a character into an M-text.
1338
1339     The mtext_set_char () function sets character $C, which has no
1340     text properties, at $POS in M-text $MT.
1341
1342     @return
1343     If the operation was successful, mtext_set_char () returns 0.
1344     Otherwise it returns -1 and assigns an error code to the external
1345     variable #merror_code.  */
1346
1347 /***ja
1348     @brief M-text ¤Ë°ìʸ»ú¤òÀßÄꤹ¤ë.
1349
1350     ´Ø¿ô mtext_set_char () ¤Ï¡¢¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£Ìµ¤·¤Îʸ»ú $C ¤ò 
1351     M-text $MT ¤Î°ÌÃÖ $POS ¤ËÀßÄꤹ¤ë¡£
1352
1353     @return
1354     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mtext_set_char () ¤Ï 0 ¤òÊÖ¤¹¡£¼ºÇÔ¤¹¤ì¤Ð -1 
1355     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1356
1357     @latexonly \IPAlabel{mtext_set_char} @endlatexonly  */
1358
1359 /***
1360     @errors
1361     @c MERROR_RANGE */
1362
1363 int
1364 mtext_set_char (MText *mt, int pos, int c)
1365 {
1366   int pos_unit;
1367   int old_units, new_units;
1368   int delta;
1369   unsigned char *p;
1370   int unit_bytes;
1371
1372   M_CHECK_POS (mt, pos, -1);
1373   M_CHECK_READONLY (mt, -1);
1374
1375   mtext__adjust_plist_for_change (mt, pos, pos + 1);
1376
1377   if (mt->format <= MTEXT_FORMAT_UTF_8)
1378     {
1379       if (c >= 0x80)
1380         mt->format = MTEXT_FORMAT_UTF_8;
1381     }
1382   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1383     {
1384       if (c >= 0x110000)
1385         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
1386       else if (mt->format != MTEXT_FORMAT_UTF_16)
1387         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_16);
1388     }
1389   else if (mt->format != MTEXT_FORMAT_UTF_32)
1390     mtext__adjust_format (mt, MTEXT_FORMAT_UTF_32);
1391
1392   unit_bytes = UNIT_BYTES (mt->format);
1393   pos_unit = POS_CHAR_TO_BYTE (mt, pos);
1394   p = mt->data + pos_unit * unit_bytes;
1395   old_units = CHAR_UNITS_AT (mt, p);
1396   new_units = CHAR_UNITS (c, mt->format);
1397   delta = new_units - old_units;
1398
1399   if (delta)
1400     {
1401       if (mt->cache_char_pos > pos)
1402         mt->cache_byte_pos += delta;
1403
1404       if ((mt->nbytes + delta + 1) * unit_bytes > mt->allocated)
1405         {
1406           mt->allocated = (mt->nbytes + delta + 1) * unit_bytes;
1407           MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
1408         }
1409
1410       memmove (mt->data + (pos_unit + new_units) * unit_bytes, 
1411                mt->data + (pos_unit + old_units) * unit_bytes,
1412                (mt->nbytes - pos_unit - old_units + 1) * unit_bytes);
1413       mt->nbytes += delta;
1414       mt->data[mt->nbytes * unit_bytes] = 0;
1415     }
1416   switch (mt->format)
1417     {
1418     case MTEXT_FORMAT_US_ASCII:
1419       mt->data[pos_unit] = c;
1420       break;
1421     case MTEXT_FORMAT_UTF_8:
1422       {
1423         unsigned char *p = mt->data + pos_unit;
1424         CHAR_STRING_UTF8 (c, p);
1425         break;
1426       }
1427     default:
1428       if (mt->format == MTEXT_FORMAT_UTF_16)
1429         {
1430           unsigned short *p = (unsigned short *) mt->data + pos_unit;
1431
1432           CHAR_STRING_UTF16 (c, p);
1433         }
1434       else
1435         ((unsigned *) mt->data)[pos_unit] = c;
1436     }
1437   return 0;
1438 }
1439
1440 /*=*/
1441
1442 /***en
1443     @brief  Append a character to an M-text.
1444
1445     The mtext_cat_char () function appends character $C, which has no
1446     text properties, to the end of M-text $MT.
1447
1448     @return
1449     This function returns a pointer to the resulting M-text $MT.  If
1450     $C is an invalid character, it returns @c NULL.  */
1451
1452 /***ja
1453     @brief M-text ¤Ë°ìʸ»úÄɲ乤ë.
1454
1455     ´Ø¿ô mtext_cat_char () ¤Ï¡¢¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£Ìµ¤·¤Îʸ»ú $C ¤ò 
1456     M-text $MT ¤ÎËöÈø¤ËÄɲ乤롣
1457
1458     @return
1459     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$C 
1460     ¤¬Àµ¤·¤¤Ê¸»ú¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï @c NULL ¤òÊÖ¤¹¡£  */
1461
1462 /***
1463     @seealso
1464     mtext_cat (), mtext_ncat ()  */
1465
1466 MText *
1467 mtext_cat_char (MText *mt, int c)
1468 {
1469   int nunits;
1470   int unit_bytes = UNIT_BYTES (mt->format);
1471
1472   M_CHECK_READONLY (mt, NULL);
1473   if (c < 0 || c > MCHAR_MAX)
1474     return NULL;
1475   mtext__adjust_plist_for_insert (mt, mt->nchars, 1, NULL);
1476
1477   if (c >= 0x80
1478       && (mt->format == MTEXT_FORMAT_US_ASCII
1479           || (c >= 0x10000
1480               && (mt->format == MTEXT_FORMAT_UTF_16LE
1481                   || mt->format == MTEXT_FORMAT_UTF_16BE))))
1482
1483     {
1484       mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
1485       unit_bytes = 1;
1486     }
1487   else if (mt->format >= MTEXT_FORMAT_UTF_32LE)
1488     {
1489       if (mt->format != MTEXT_FORMAT_UTF_32)
1490         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_32);
1491     }
1492   else if (mt->format >= MTEXT_FORMAT_UTF_16LE)
1493     {
1494       if (mt->format != MTEXT_FORMAT_UTF_16)
1495         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_16);
1496     }
1497
1498   nunits = CHAR_UNITS (c, mt->format);
1499   if ((mt->nbytes + nunits + 1) * unit_bytes > mt->allocated)
1500     {
1501       mt->allocated = (mt->nbytes + nunits + 1) * unit_bytes;
1502       MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
1503     }
1504   
1505   if (mt->format <= MTEXT_FORMAT_UTF_8)
1506     {
1507       unsigned char *p = mt->data + mt->nbytes;
1508       p += CHAR_STRING_UTF8 (c, p);
1509       *p = 0;
1510     }
1511   else if (mt->format == MTEXT_FORMAT_UTF_16)
1512     {
1513       unsigned short *p = (unsigned short *) mt->data + mt->nbytes;
1514       p += CHAR_STRING_UTF16 (c, p);
1515       *p = 0;
1516     }
1517   else
1518     {
1519       unsigned *p = (unsigned *) mt->data + mt->nbytes;
1520       *p++ = c;
1521       *p = 0;
1522     }
1523
1524   mt->nchars++;
1525   mt->nbytes += nunits;
1526   return mt;
1527 }
1528
1529 /*=*/
1530
1531 /***en
1532     @brief  Create a copy of an M-text.
1533
1534     The mtext_dup () function creates a copy of M-text $MT while
1535     inheriting all the text properties of $MT.
1536
1537     @return
1538     This function returns a pointer to the created copy.  */
1539
1540 /***ja
1541     @brief M-text ¤Î¥³¥Ô¡¼¤òºî¤ë.
1542
1543     ´Ø¿ô mtext_dup () ¤Ï¡¢M-text $MT ¤Î¥³¥Ô¡¼¤òºî¤ë¡£$MT 
1544     ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£
1545
1546     @return
1547     ¤³¤Î´Ø¿ô¤Ïºî¤é¤ì¤¿¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1548
1549      @latexonly \IPAlabel{mtext_dup} @endlatexonly  */
1550
1551 /***
1552     @seealso
1553     mtext_duplicate ()  */
1554
1555 MText *
1556 mtext_dup (MText *mt)
1557 {
1558   MText *new = mtext ();
1559   int unit_bytes = UNIT_BYTES (mt->format);
1560
1561   *new = *mt;
1562   if (mt->nchars > 0)
1563     {
1564       new->allocated = (mt->nbytes + 1) * unit_bytes;
1565       MTABLE_MALLOC (new->data, new->allocated, MERROR_MTEXT);
1566       memcpy (new->data, mt->data, new->allocated);
1567       if (mt->plist)
1568         new->plist = mtext__copy_plist (mt->plist, 0, mt->nchars, new, 0);
1569     }
1570   return new;
1571 }
1572
1573 /*=*/
1574
1575 /***en
1576     @brief  Append an M-text to another.
1577
1578     The mtext_cat () function appends M-text $MT2 to the end of M-text
1579     $MT1 while inheriting all the text properties.  $MT2 itself is not
1580     modified.
1581
1582     @return
1583     This function returns a pointer to the resulting M-text $MT1.  */
1584
1585 /***ja
1586     @brief 2¸Ä¤Î M-text¤òÏ¢·ë¤¹¤ë.
1587
1588     ´Ø¿ô mtext_cat () ¤Ï¡¢ M-text $MT2 ¤ò M-text $MT1 
1589     ¤ÎËöÈø¤ËÉÕ¤±²Ã¤¨¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1590
1591     @return
1592     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1593
1594     @latexonly \IPAlabel{mtext_cat} @endlatexonly  */
1595
1596 /***
1597     @seealso
1598     mtext_ncat (), mtext_cat_char ()  */
1599
1600 MText *
1601 mtext_cat (MText *mt1, MText *mt2)
1602 {
1603   M_CHECK_READONLY (mt1, NULL);
1604
1605   if (mt2->nchars > 0)
1606     insert (mt1, mt1->nchars, mt2, 0, mt2->nchars);
1607   return mt1;
1608 }
1609
1610
1611 /*=*/
1612
1613 /***en
1614     @brief Append a part of an M-text to another.
1615
1616     The mtext_ncat () function appends the first $N characters of
1617     M-text $MT2 to the end of M-text $MT1 while inheriting all the
1618     text properties.  If the length of $MT2 is less than $N, all
1619     characters are copied.  $MT2 is not modified.  
1620
1621     @return 
1622     If the operation was successful, mtext_ncat () returns a
1623     pointer to the resulting M-text $MT1.  If an error is detected, it
1624     returns @c NULL and assigns an error code to the global variable
1625     #merror_code.  */
1626
1627 /***ja
1628     @brief M-text ¤Î°ìÉô¤òÊ̤ΠM-text ¤ËÉղ乤ë.
1629
1630     ´Ø¿ô mtext_ncat () ¤Ï¡¢M-text $MT2 ¤Î¤Ï¤¸¤á¤Î $N Ê¸»ú¤ò M-text
1631     $MT1 ¤ÎËöÈø¤ËÉÕ¤±²Ã¤¨¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT2
1632     ¤ÎŤµ¤¬ $N °Ê²¼¤Ê¤é¤Ð¡¢$MT2 ¤Î¤¹¤Ù¤Æ¤Îʸ»ú¤¬Éղ䵤ì¤ë¡£ $MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1633
1634     @return
1635     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_ncat () ¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1
1636     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô
1637     #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1638
1639     @latexonly \IPAlabel{mtext_ncat} @endlatexonly  */
1640
1641 /***
1642     @errors
1643     @c MERROR_RANGE
1644
1645     @seealso
1646     mtext_cat (), mtext_cat_char ()  */
1647
1648 MText *
1649 mtext_ncat (MText *mt1, MText *mt2, int n)
1650 {
1651   M_CHECK_READONLY (mt1, NULL);
1652   if (n < 0)
1653     MERROR (MERROR_RANGE, NULL);
1654   if (mt2->nchars > 0)
1655     insert (mt1, mt1->nchars, mt2, 0, mt2->nchars < n ? mt2->nchars : n);
1656   return mt1;
1657 }
1658
1659
1660 /*=*/
1661
1662 /***en
1663     @brief Copy an M-text to another.
1664
1665     The mtext_cpy () function copies M-text $MT2 to M-text $MT1 while
1666     inheriting all the text properties.  The old text in $MT1 is
1667     overwritten and the length of $MT1 is extended if necessary.  $MT2
1668     is not modified.
1669
1670     @return
1671     This function returns a pointer to the resulting M-text $MT1.  */
1672
1673 /***ja
1674     @brief M-text ¤òÊ̤ΠM-text ¤Ë¥³¥Ô¡¼¤¹¤ë.
1675
1676     ´Ø¿ô mtext_cpy () ¤Ï M-text $MT2 ¤ò M-text $MT1 ¤Ë¾å½ñ¤­¥³¥Ô¡¼¤¹¤ë¡£
1677     $MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT1 
1678     ¤ÎŤµ¤ÏɬÍפ˱þ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1679
1680     @return
1681     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1682
1683     @latexonly \IPAlabel{mtext_cpy} @endlatexonly  */
1684
1685 /***
1686     @seealso
1687     mtext_ncpy (), mtext_copy ()  */
1688
1689 MText *
1690 mtext_cpy (MText *mt1, MText *mt2)
1691 {
1692   M_CHECK_READONLY (mt1, NULL);
1693   mtext_del (mt1, 0, mt1->nchars);
1694   if (mt2->nchars > 0)
1695     insert (mt1, 0, mt2, 0, mt2->nchars);
1696   return mt1;
1697 }
1698
1699 /*=*/
1700
1701 /***en
1702     @brief Copy the first some characters in an M-text to another.
1703
1704     The mtext_ncpy () function copies the first $N characters of
1705     M-text $MT2 to M-text $MT1 while inheriting all the text
1706     properties.  If the length of $MT2 is less than $N, all characters
1707     of $MT2 are copied.  The old text in $MT1 is overwritten and the
1708     length of $MT1 is extended if necessary.  $MT2 is not modified.
1709
1710     @return
1711     If the operation was successful, mtext_ncpy () returns a pointer
1712     to the resulting M-text $MT1.  If an error is detected, it returns
1713     @c NULL and assigns an error code to the global variable 
1714     #merror_code.  */
1715
1716 /***ja
1717     @brief M-text ¤Ë´Þ¤Þ¤ì¤ëºÇ½é¤Î²¿Ê¸»ú¤«¤ò¥³¥Ô¡¼¤¹¤ë.
1718
1719     ´Ø¿ô mtext_ncpy () ¤Ï¡¢M-text $MT2 ¤ÎºÇ½é¤Î $N Ê¸»ú¤ò M-text $MT1 
1720     ¤Ë¾å½ñ¤­¥³¥Ô¡¼¤¹¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£¤â¤· $MT2
1721     ¤ÎŤµ¤¬ $N ¤è¤ê¤â¾®¤µ¤±¤ì¤Ð $MT2 ¤Î¤¹¤Ù¤Æ¤Îʸ»ú¤ò¥³¥Ô¡¼¤¹¤ë¡£$MT1 
1722     ¤ÎŤµ¤ÏɬÍפ˱þ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1723
1724     @return 
1725     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_ncpy () ¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 
1726     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô 
1727     #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1728
1729     @latexonly \IPAlabel{mtext_ncpy} @endlatexonly  */
1730
1731 /***
1732     @errors
1733     @c MERROR_RANGE
1734
1735     @seealso
1736     mtext_cpy (), mtext_copy ()  */
1737
1738 MText *
1739 mtext_ncpy (MText *mt1, MText *mt2, int n)
1740 {
1741   M_CHECK_READONLY (mt1, NULL);
1742   if (n < 0)
1743     MERROR (MERROR_RANGE, NULL);
1744   mtext_del (mt1, 0, mt1->nchars);
1745   if (mt2->nchars > 0)
1746     insert (mt1, 0, mt2, 0, mt2->nchars < n ? mt2->nchars : n);
1747   return mt1;
1748 }
1749
1750 /*=*/
1751
1752 /***en
1753     @brief Create a new M-text from a part of an existing M-text.
1754
1755     The mtext_duplicate () function creates a copy of sub-text of
1756     M-text $MT, starting at $FROM (inclusive) and ending at $TO
1757     (exclusive) while inheriting all the text properties of $MT.  $MT
1758     itself is not modified.
1759
1760     @return
1761     If the operation was successful, mtext_duplicate () returns a
1762     pointer to the created M-text.  If an error is detected, it returns 0
1763     and assigns an error code to the external variable #merror_code.  */
1764
1765 /***ja
1766     @brief ´û¸¤Î M-text ¤Î°ìÉô¤«¤é¿·¤·¤¤ M-text ¤ò¤Ä¤¯¤ë.
1767
1768     ´Ø¿ô mtext_duplicate () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê$FROM ¼«ÂΤâ´Þ¤à¡Ë¤«¤é
1769     $TO ¡Ê$TO ¼«ÂΤϴޤޤʤ¤¡Ë¤Þ¤Ç¤ÎÉôʬ¤Î¥³¥Ô¡¼¤òºî¤ë¡£¤³¤Î¤È¤­ $MT 
1770     ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT ¤½¤Î¤â¤Î¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1771
1772     @return
1773     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_duplicate () ¤Ïºî¤é¤ì¤¿ M-text 
1774     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô 
1775     #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1776
1777     @latexonly \IPAlabel{mtext_duplicate} @endlatexonly  */
1778
1779 /***
1780     @errors
1781     @c MERROR_RANGE
1782
1783     @seealso
1784     mtext_dup ()  */
1785
1786 MText *
1787 mtext_duplicate (MText *mt, int from, int to)
1788 {
1789   MText *new;
1790
1791   M_CHECK_RANGE_X (mt, from, to, NULL);
1792   new = mtext ();
1793   new->format = mt->format;
1794   if (from < to)
1795     insert (new, 0, mt, from, to);
1796   return new;
1797 }
1798
1799 /*=*/
1800
1801 /***en
1802     @brief Copy characters in the specified range into an M-text.
1803
1804     The mtext_copy () function copies the text between $FROM
1805     (inclusive) and $TO (exclusive) in M-text $MT2 to the region
1806     starting at $POS in M-text $MT1 while inheriting the text
1807     properties.  The old text in $MT1 is overwritten and the length of
1808     $MT1 is extended if necessary.  $MT2 is not modified.
1809
1810     @return
1811     If the operation was successful, mtext_copy () returns a pointer
1812     to the modified $MT1.  Otherwise, it returns @c NULL and assigns
1813     an error code to the external variable #merror_code.  */
1814
1815 /***ja
1816     @brief M-text ¤Ë»ØÄêÈϰϤÎʸ»ú¤ò¥³¥Ô¡¼¤¹¤ë.
1817
1818     ´Ø¿ô mtext_copy () ¤Ï¡¢ M-text $MT2 ¤Î $FROM ¡Ê$FROM ¼«ÂΤâ´Þ¤à¡Ë¤«¤é 
1819     $TO ¡Ê$TO ¼«ÂΤϴޤޤʤ¤¡Ë¤Þ¤Ç¤ÎÈϰϤΥƥ­¥¹¥È¤ò M-text $MT1 ¤Î°ÌÃÖ $POS
1820     ¤«¤é¾å½ñ¤­¥³¥Ô¡¼¤¹¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT1 
1821     ¤ÎŤµ¤ÏɬÍפ˱þ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1822
1823     @latexonly \IPAlabel{mtext_copy} @endlatexonly
1824
1825     @return
1826     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_copy () ¤ÏÊѹ¹¤µ¤ì¤¿ $MT1 
1827     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code 
1828     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1829
1830 /***
1831     @errors
1832     @c MERROR_RANGE
1833
1834     @seealso
1835     mtext_cpy (), mtext_ncpy ()  */
1836
1837 MText *
1838 mtext_copy (MText *mt1, int pos, MText *mt2, int from, int to)
1839 {
1840   M_CHECK_POS_X (mt1, pos, NULL);
1841   M_CHECK_READONLY (mt1, NULL);
1842   M_CHECK_RANGE_X (mt2, from, to, NULL);
1843   mtext_del (mt1, pos, mt1->nchars);
1844   return insert (mt1, pos, mt2, from, to);
1845 }
1846
1847 /*=*/
1848
1849
1850 /***en
1851     @brief Delete characters in the specified range destructively.
1852
1853     The mtext_del () function deletes the characters in the range
1854     $FROM (inclusive) and $TO (exclusive) from M-text $MT
1855     destructively.  As a result, the length of $MT shrinks by ($TO -
1856     $FROM) characters.
1857
1858     @return
1859     If the operation was successful, mtext_del () returns 0.
1860     Otherwise, it returns -1 and assigns an error code to the external
1861     variable #merror_code.  */
1862
1863 /***ja
1864     @brief »ØÄêÈϰϤÎʸ»ú¤òÇ˲õŪ¤Ë¼è¤ê½ü¤¯.
1865
1866     ´Ø¿ô mtext_del () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê$FROM ¼«ÂΤâ´Þ¤à¡Ë¤«¤é $TO
1867     ¡Ê$TO ¼«ÂΤϴޤޤʤ¤¡Ë¤Þ¤Ç¤Îʸ»ú¤òÇ˲õŪ¤Ë¼è¤ê½ü¤¯¡£·ë²ÌŪ¤Ë $MT ¤ÏŤµ¤¬ ($TO @c
1868     - $FROM) ¤À¤±½Ì¤à¤³¤È¤Ë¤Ê¤ë¡£
1869
1870     @return
1871     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_del () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 
1872     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1873
1874 /***
1875     @errors
1876     @c MERROR_RANGE
1877
1878     @seealso
1879     mtext_ins ()  */
1880
1881 int
1882 mtext_del (MText *mt, int from, int to)
1883 {
1884   int from_byte, to_byte;
1885   int unit_bytes = UNIT_BYTES (mt->format);
1886
1887   M_CHECK_READONLY (mt, -1);
1888   M_CHECK_RANGE (mt, from, to, -1, 0);
1889
1890   from_byte = POS_CHAR_TO_BYTE (mt, from);
1891   to_byte = POS_CHAR_TO_BYTE (mt, to);
1892
1893   if (mt->cache_char_pos >= to)
1894     {
1895       mt->cache_char_pos -= to - from;
1896       mt->cache_byte_pos -= to_byte - from_byte;
1897     }
1898   else if (mt->cache_char_pos > from)
1899     {
1900       mt->cache_char_pos -= from;
1901       mt->cache_byte_pos -= from_byte;
1902     }
1903
1904   mtext__adjust_plist_for_delete (mt, from, to - from);
1905   memmove (mt->data + from_byte * unit_bytes, 
1906            mt->data + to_byte * unit_bytes,
1907            (mt->nbytes - to_byte + 1) * unit_bytes);
1908   mt->nchars -= (to - from);
1909   mt->nbytes -= (to_byte - from_byte);
1910   mt->cache_char_pos = from;
1911   mt->cache_byte_pos = from_byte;
1912   return 0;
1913 }
1914
1915
1916 /*=*/
1917
1918 /***en
1919     @brief Insert an M-text into another M-text.
1920
1921     The mtext_ins () function inserts M-text $MT2 into M-text $MT1, at
1922     position $POS.  As a result, $MT1 is lengthen by the length of
1923     $MT2.  On insertion, all the text properties of $MT2 are
1924     inherited.  The original $MT2 is not modified.
1925
1926     @return
1927     If the operation was successful, mtext_ins () returns 0.
1928     Otherwise, it returns -1 and assigns an error code to the external
1929     variable #merror_code.  */
1930
1931 /***ja
1932     @brief M-text ¤òÊ̤ΠM-text ¤ËÁÞÆþ¤¹¤ë.
1933
1934     ´Ø¿ô mtext_ins () ¤Ï M-text $MT1 ¤Î $POS ¤Î°ÌÃ֤ˠÊ̤ΠM-text $MT2 
1935     ¤òÁÞÆþ¤¹¤ë¡£¤³¤Î·ë²Ì $MT1 ¤ÎŤµ¤Ï $MT2 ¤ÎŤµÊ¬¤À¤±Áý¤¨¤ë¡£ÁÞÆþ¤ÎºÝ¡¢$MT2
1936     ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT2 ¤½¤Î¤â¤Î¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1937
1938     @return
1939     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_ins () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 
1940     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1941
1942 /***
1943     @errors
1944     @c MERROR_RANGE
1945
1946     @seealso
1947     mtext_del ()  */
1948
1949 int
1950 mtext_ins (MText *mt1, int pos, MText *mt2)
1951 {
1952   M_CHECK_READONLY (mt1, -1);
1953   M_CHECK_POS_X (mt1, pos, -1);
1954
1955   if (mt2->nchars == 0)
1956     return 0;
1957   insert (mt1, pos, mt2, 0, mt2->nchars);
1958   return 0;
1959 }
1960
1961
1962 /*=*/
1963
1964 /***en
1965     @brief Insert a character into an M-text.
1966
1967     The mtext_ins_char () function inserts $N copies of character $C
1968     into M-text $MT at position $POS.  As a result, $MT is lengthen by
1969     $N.
1970
1971     @return
1972     If the operation was successful, mtext_ins () returns 0.
1973     Otherwise, it returns -1 and assigns an error code to the external
1974     variable #merror_code.  */
1975
1976 /***ja
1977     @brief M-text ¤Ëʸ»ú¤òÁÞÆþ¤¹¤ë.
1978
1979     ´Ø¿ô mtext_ins_char () ¤Ï M-text $MT ¤Î $POS ¤Î°ÌÃÖ¤Ëʸ»ú $C ¤Î¥³¥Ô¡¼¤ò $N
1980     ¸ÄÁÞÆþ¤¹¤ë¡£¤³¤Î·ë²Ì $MT1 ¤ÎŤµ¤Ï $N ¤À¤±Áý¤¨¤ë¡£
1981
1982     @return
1983     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_ins_char () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1
1984     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1985
1986 /***
1987     @errors
1988     @c MERROR_RANGE
1989
1990     @seealso
1991     mtext_ins, mtext_del ()  */
1992
1993 int
1994 mtext_ins_char (MText *mt, int pos, int c, int n)
1995 {
1996   int nunits;
1997   int unit_bytes = UNIT_BYTES (mt->format);
1998   int pos_unit;
1999   int i;
2000
2001   M_CHECK_READONLY (mt, -1);
2002   M_CHECK_POS_X (mt, pos, -1);
2003   if (c < 0 || c > MCHAR_MAX)
2004     MERROR (MERROR_MTEXT, -1);
2005   if (n <= 0)
2006     return 0;
2007   mtext__adjust_plist_for_insert (mt, pos, n, NULL);
2008
2009   if (c >= 0x80
2010       && (mt->format == MTEXT_FORMAT_US_ASCII
2011           || (c >= 0x10000 && (mt->format == MTEXT_FORMAT_UTF_16LE
2012                                || mt->format == MTEXT_FORMAT_UTF_16BE))))
2013     {
2014       mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
2015       unit_bytes = 1;
2016     }
2017   else if (mt->format >= MTEXT_FORMAT_UTF_32LE)
2018     {
2019       if (mt->format != MTEXT_FORMAT_UTF_32)
2020         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_32);
2021     }
2022   else if (mt->format >= MTEXT_FORMAT_UTF_16LE)
2023     {
2024       if (mt->format != MTEXT_FORMAT_UTF_16)
2025         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_16);
2026     }
2027
2028   nunits = CHAR_UNITS (c, mt->format);
2029   if ((mt->nbytes + nunits * n + 1) * unit_bytes > mt->allocated)
2030     {
2031       mt->allocated = (mt->nbytes + nunits * n + 1) * unit_bytes;
2032       MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
2033     }
2034   pos_unit = POS_CHAR_TO_BYTE (mt, pos);
2035   if (mt->cache_char_pos > pos)
2036     {
2037       mt->cache_char_pos += n;
2038       mt->cache_byte_pos += nunits + n;
2039     }
2040   memmove (mt->data + (pos_unit + nunits * n) * unit_bytes,
2041            mt->data + pos_unit * unit_bytes,
2042            (mt->nbytes - pos_unit + 1) * unit_bytes);
2043   if (mt->format <= MTEXT_FORMAT_UTF_8)
2044     {
2045       unsigned char *p = mt->data + pos_unit;
2046
2047       for (i = 0; i < n; i++)
2048         p += CHAR_STRING_UTF8 (c, p);
2049     }
2050   else if (mt->format == MTEXT_FORMAT_UTF_16)
2051     {
2052       unsigned short *p = (unsigned short *) mt->data + pos_unit;
2053
2054       for (i = 0; i < n; i++)
2055         p += CHAR_STRING_UTF16 (c, p);
2056     }
2057   else
2058     {
2059       unsigned *p = (unsigned *) mt->data + pos_unit;
2060
2061       for (i = 0; i < n; i++)
2062         *p++ = c;
2063     }
2064   mt->nchars += n;
2065   mt->nbytes += nunits * n;
2066   return 0;
2067 }
2068
2069 /*=*/
2070
2071 /***en
2072     @brief Search a character in an M-text.
2073
2074     The mtext_character () function searches M-text $MT for character
2075     $C.  If $FROM is less than $TO, the search begins at position $FROM
2076     and goes forward but does not exceed ($TO - 1).  Otherwise, the search
2077     begins at position ($FROM - 1) and goes backward but does not
2078     exceed $TO.  An invalid position specification is regarded as both
2079     $FROM and $TO being 0.
2080
2081     @return
2082     If $C is found, mtext_character () returns the position of its
2083     first occurrence.  Otherwise it returns -1 without changing the
2084     external variable #merror_code.  If an error is detected, it returns -1 and
2085     assigns an error code to the external variable #merror_code.  */
2086
2087 /***ja
2088     @brief M-text Ãæ¤Çʸ»ú¤òõ¤¹.
2089
2090     ´Ø¿ô mtext_character () ¤Ï M-text $MT Ãæ¤Çʸ»ú $C ¤òõ¤¹¡£¤â¤· 
2091     $FROM ¤¬ $TO ¤è¤ê¾®¤µ¤±¤ì¤Ð¡¢Ãµº÷¤Ï°ÌÃÖ $FROM ¤«¤éËöÈøÊý¸þ¤Ø¡¢ºÇÂç 
2092     ($TO - 1) ¤Þ¤Ç¿Ê¤à¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð°ÌÃÖ ($FROM - 1) ¤«¤éÀèƬÊý¸þ¤Ø¡¢ºÇÂç
2093     $TO ¤Þ¤Ç¿Ê¤à¡£°ÌÃ֤λØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢$FROM ¤È $TO 
2094     ¤ÎξÊý¤Ë 0 ¤¬»ØÄꤵ¤ì¤¿¤â¤Î¤È¤ß¤Ê¤¹¡£
2095
2096     @return
2097     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_character () 
2098     ¤Ï¤½¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï³°ÉôÊÑ¿ô #merror_code
2099     ¤òÊѹ¹¤»¤º¤Ë -1 ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô
2100     #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
2101
2102 /***
2103     @seealso
2104     mtext_chr(), mtext_rchr ()  */
2105
2106 int
2107 mtext_character (MText *mt, int from, int to, int c)
2108 {
2109   if (from < to)
2110     {
2111       /* We do not use M_CHECK_RANGE () because this function should
2112          not set merror_code.  */
2113       if (from < 0 || to > mt->nchars)
2114         return -1;
2115       return find_char_forward (mt, from, to, c);
2116     }
2117   else
2118     {
2119       /* ditto */
2120       if (to < 0 || from > mt->nchars)
2121         return -1;
2122       return find_char_backward (mt, to, from, c);
2123     }
2124 }
2125
2126
2127 /*=*/
2128
2129 /***en
2130     @brief Return the position of the first occurrence of a character in an M-text.
2131
2132     The mtext_chr () function searches M-text $MT for character $C.
2133     The search starts from the beginning of $MT and goes toward the end.
2134
2135     @return
2136     If $C is found, mtext_chr () returns its position; otherwise it
2137     returns -1.  */
2138
2139 /***ja
2140     @brief M-text Ãæ¤Ç»ØÄꤵ¤ì¤¿Ê¸»ú¤¬ºÇ½é¤Ë¸½¤ì¤ë°ÌÃÖ¤òÊÖ¤¹.
2141
2142     ´Ø¿ô mtext_chr () ¤Ï M-text $MT Ãæ¤Çʸ»ú $C ¤òõ¤¹¡£Ãµº÷¤Ï $MT 
2143     ¤ÎÀèƬ¤«¤éËöÈøÊý¸þ¤Ë¿Ê¤à¡£
2144
2145     @return
2146     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_chr () 
2147     ¤Ï¤½¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£
2148
2149     @latexonly \IPAlabel{mtext_chr} @endlatexonly  */
2150
2151 /***
2152     @errors
2153     @c MERROR_RANGE
2154
2155     @seealso
2156     mtext_rchr (), mtext_character ()  */
2157
2158 int
2159 mtext_chr (MText *mt, int c)
2160 {
2161   return find_char_forward (mt, 0, mt->nchars, c);
2162 }
2163
2164 /*=*/
2165
2166 /***en
2167     @brief Return the position of the last occurrence of a character in an M-text.
2168
2169     The mtext_rchr () function searches M-text $MT for character $C.
2170     The search starts from the end of $MT and goes backwardly toward the
2171     beginning.
2172
2173     @return
2174     If $C is found, mtext_rchr () returns its position; otherwise it
2175     returns -1.  */
2176
2177 /***ja
2178     @brief M-text Ãæ¤Ç»ØÄꤵ¤ì¤¿Ê¸»ú¤¬ºÇ¸å¤Ë¸½¤ì¤ë°ÌÃÖ¤òÊÖ¤¹.
2179
2180     ´Ø¿ô mtext_rchr () ¤Ï M-text $MT Ãæ¤Çʸ»ú $C ¤òõ¤¹¡£Ãµº÷¤Ï $MT 
2181     ¤ÎºÇ¸å¤«¤éÀèƬÊý¸þ¤Ø¤È¸å¸þ¤­¤Ë¿Ê¤à¡£
2182
2183     @return
2184     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_rchr () 
2185     ¤Ï¤½¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£
2186
2187     @latexonly \IPAlabel{mtext_rchr} @endlatexonly  */
2188
2189 /***
2190     @errors
2191     @c MERROR_RANGE
2192
2193     @seealso
2194     mtext_chr (), mtext_character ()  */
2195
2196 int
2197 mtext_rchr (MText *mt, int c)
2198 {
2199   return find_char_backward (mt, mt->nchars, 0, c);
2200 }
2201
2202
2203 /*=*/
2204
2205 /***en
2206     @brief Compare two M-texts character-by-character.
2207
2208     The mtext_cmp () function compares M-texts $MT1 and $MT2 character
2209     by character.
2210
2211     @return
2212     This function returns 1, 0, or -1 if $MT1 is found greater than,
2213     equal to, or less than $MT2, respectively.  Comparison is based on
2214     character codes.  */
2215
2216 /***ja
2217     @brief Æó¤Ä¤Î M-text ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë.
2218
2219     ´Ø¿ô mtext_cmp () ¤Ï¡¢ M-text $MT1 ¤È $MT2 ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë¡£
2220
2221     @return
2222     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì¤Ð
2223     1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð¤Å¤¯¡£
2224
2225     @latexonly \IPAlabel{mtext_cmp} @endlatexonly  */
2226
2227 /***
2228     @seealso
2229     mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
2230     mtext_compare (), mtext_case_compare ()  */
2231
2232 int
2233 mtext_cmp (MText *mt1, MText *mt2)
2234 {
2235   return compare (mt1, 0, mt1->nchars, mt2, 0, mt2->nchars);
2236 }
2237
2238
2239 /*=*/
2240
2241 /***en
2242     @brief Compare initial parts of two M-texts character-by-character.
2243
2244     The mtext_ncmp () function is similar to mtext_cmp (), but
2245     compares at most $N characters from the beginning.
2246
2247     @return
2248     This function returns 1, 0, or -1 if $MT1 is found greater than,
2249     equal to, or less than $MT2, respectively.  */
2250
2251 /***ja
2252     @brief Æó¤Ä¤Î M-text ¤ÎÀèƬÉôʬ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë.
2253
2254     ´Ø¿ô mtext_ncmp () ¤Ï¡¢´Ø¿ô mtext_cmp () Æ±ÍͤΠM-text 
2255     Æ±»Î¤ÎÈæ³Ó¤òÀèƬ¤«¤éºÇÂç $N Ê¸»ú¤Þ¤Ç¤Ë´Ø¤·¤Æ¹Ô¤Ê¤¦¡£
2256
2257     @return
2258     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì¤Ð 
2259     1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
2260
2261     @latexonly \IPAlabel{mtext_ncmp} @endlatexonly  */
2262
2263 /***
2264     @seealso
2265     mtext_cmp (), mtext_casecmp (), mtext_ncasecmp ()
2266     mtext_compare (), mtext_case_compare ()  */
2267
2268 int
2269 mtext_ncmp (MText *mt1, MText *mt2, int n)
2270 {
2271   if (n < 0)
2272     return 0;
2273   return compare (mt1, 0, (mt1->nchars < n ? mt1->nchars : n),
2274                   mt2, 0, (mt2->nchars < n ? mt2->nchars : n));
2275 }
2276
2277 /*=*/
2278
2279 /***en
2280     @brief Compare specified regions of two M-texts.
2281
2282     The mtext_compare () function compares two M-texts $MT1 and $MT2,
2283     character-by-character.  The compared regions are between $FROM1
2284     and $TO1 in $MT1 and $FROM2 to $TO2 in MT2.  $FROM1 and $FROM2 are
2285     inclusive, $TO1 and $TO2 are exclusive.  $FROM1 being equal to
2286     $TO1 (or $FROM2 being equal to $TO2) means an M-text of length
2287     zero.  An invalid region specification is regarded as both $FROM1
2288     and $TO1 (or $FROM2 and $TO2) being 0.
2289
2290     @return
2291     This function returns 1, 0, or -1 if $MT1 is found greater than,
2292     equal to, or less than $MT2, respectively.  Comparison is based on
2293     character codes.  */
2294
2295 /***ja
2296     @brief Æó¤Ä¤Î M-text ¤Î»ØÄꤷ¤¿ÎΰèƱ»Î¤òÈæ³Ó¤¹¤ë.
2297
2298     ´Ø¿ô mtext_compare () ¤ÏÆó¤Ä¤Î M-text $MT1 ¤È $MT2 
2299     ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë¡£Èæ³Ó¤ÎÂоݤϠ$MT1 ¤Î¤¦¤Á $FROM1 ¤«¤é $TO1 ¤Þ¤Ç¤È¡¢$MT2 
2300     ¤Î¤¦¤Á $FROM2 ¤«¤é $TO2 ¤Þ¤Ç¤Ç¤¢¤ë¡£$FROM1 ¤È $FROM2 ¤Ï´Þ¤Þ¤ì¡¢$TO1 
2301     ¤È $TO2 ¤Ï´Þ¤Þ¤ì¤Ê¤¤¡£$FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 
2302     ¡Ë¤¬Åù¤·¤¤¾ì¹ç¤ÏŤµ¥¼¥í¤Î M-text ¤ò°ÕÌ£¤¹¤ë¡£ÈÏ°Ï»ØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢
2303     $FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 ¡Ë Î¾Êý¤Ë 0 ¤¬»ØÄꤵ¤ì¤¿¤â¤Î¤È¤ß¤Ê¤¹¡£
2304
2305     @return
2306     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì¤Ð
2307     1 ¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð¤Å¤¯¡£  */
2308
2309 /***
2310     @seealso
2311     mtext_cmp (), mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
2312     mtext_case_compare ()  */
2313
2314 int
2315 mtext_compare (MText *mt1, int from1, int to1, MText *mt2, int from2, int to2)
2316 {
2317   if (from1 < 0 || from1 > to1 || to1 > mt1->nchars)
2318     from1 = to1 = 0;
2319
2320   if (from2 < 0 || from2 > to2 || to2 > mt2->nchars)
2321     from2 = to2 = 0;
2322
2323   return compare (mt1, from1, to1, mt2, from2, to2);
2324 }
2325
2326 /*=*/
2327
2328 /***en
2329     @brief Search an M-text for a set of characters.
2330
2331     The mtext_spn () function returns the length of the initial
2332     segment of M-text $MT1 that consists entirely of characters in
2333     M-text $MT2.  */
2334
2335 /***ja
2336     @brief ¤¢¤ë½¸¹ç¤Îʸ»ú¤ò M-text ¤ÎÃæ¤Çõ¤¹.
2337
2338     ´Ø¿ô mtext_spn () ¤Ï¡¢M-text $MT1 ¤ÎÀèƬ¤«¤é M-text $MT2 
2339     ¤Ë´Þ¤Þ¤ì¤ëʸ»ú¤À¤±¤Ç¤Ç¤­¤Æ¤¤¤ëÉôʬ¤ÎŤµ¤òÊÖ¤¹¡£
2340
2341     @latexonly \IPAlabel{mtext_spn} @endlatexonly  */
2342
2343 /***
2344     @seealso
2345     mtext_cspn ()  */
2346
2347 int
2348 mtext_spn (MText *mt, MText *accept)
2349 {
2350   return span (mt, accept, 0, Mnil);
2351 }
2352
2353 /*=*/
2354
2355 /***en
2356     @brief Search an M-text for the complement of a set of characters.
2357
2358     The mtext_cspn () returns the length of the initial segment of
2359     M-text $MT1 that consists entirely of characters not in M-text $MT2.  */
2360
2361 /***ja
2362     @brief ¤¢¤ë½¸¹ç¤Ë°¤µ¤Ê¤¤Ê¸»ú¤ò M-text ¤ÎÃæ¤Çõ¤¹.
2363
2364     ´Ø¿ô mtext_cspn () ¤Ï¡¢M-text $MT1 ¤ÎÀèƬÉôʬ¤Ç M-text $MT2
2365     ¤Ë´Þ¤Þ¤ì¤Ê¤¤Ê¸»ú¤À¤±¤Ç¤Ç¤­¤Æ¤¤¤ëÉôʬ¤ÎŤµ¤òÊÖ¤¹¡£
2366
2367     @latexonly \IPAlabel{mtext_cspn} @endlatexonly  */
2368
2369 /***
2370     @seealso
2371     mtext_spn ()  */
2372
2373 int
2374 mtext_cspn (MText *mt, MText *reject)
2375 {
2376   return span (mt, reject, 0, Mt);
2377 }
2378
2379 /*=*/
2380
2381 /***en
2382     @brief Search an M-text for any of a set of characters.
2383
2384     The mtext_pbrk () function locates the first occurrence in M-text
2385     $MT1 of any of the characters in M-text $MT2.
2386
2387     @return
2388     This function returns the position in $MT1 of the found character.
2389     If no such character is found, it returns -1. */
2390
2391 /***ja
2392     @brief ¤¢¤ë½¸¹ç¤Ë°¤¹Ê¸»ú¤ò M-text ¤ÎÃ椫¤éõ¤¹.
2393
2394     ´Ø¿ô mtext_pbrk () ¤Ï¡¢M-text $MT1 Ãæ¤Ç M-text $MT2 
2395     ¤Îʸ»ú¤Î¤É¤ì¤«¤¬ºÇ½é¤Ë¸½¤ì¤ë°ÌÃÖ¤òÄ´¤Ù¤ë¡£
2396
2397     @return 
2398     ¸«¤Ä¤«¤Ã¤¿Ê¸»ú¤Î¡¢$MT1 
2399     Æâ¤Ë¤ª¤±¤ë½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¤â¤·¤½¤Î¤è¤¦¤Êʸ»ú¤¬¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
2400
2401     @latexonly \IPAlabel{mtext_pbrk} @endlatexonly  */
2402
2403 int
2404 mtext_pbrk (MText *mt, MText *accept)
2405 {
2406   int nchars = mtext_nchars (mt);
2407   int len = span (mt, accept, 0, Mt);
2408
2409   return (len == nchars ? -1 : len);
2410 }
2411
2412 /*=*/
2413
2414 /***en
2415     @brief Look for a token in an M-text.
2416
2417     The mtext_tok () function searches a token that firstly occurs
2418     after position $POS in M-text $MT.  Here, a token means a
2419     substring each of which does not appear in M-text $DELIM.  Note
2420     that the type of $POS is not @c int but pointer to @c int.
2421
2422     @return
2423     If a token is found, mtext_tok () copies the corresponding part of
2424     $MT and returns a pointer to the copy.  In this case, $POS is set
2425     to the end of the found token.  If no token is found, it returns
2426     @c NULL without changing the external variable #merror_code.  If an
2427     error is detected, it returns @c NULL and assigns an error code
2428     to the external variable #merror_code. */
2429
2430 /***ja
2431     @brief M-text Ãæ¤Î¥È¡¼¥¯¥ó¤òõ¤¹.
2432
2433     ´Ø¿ô mtext_tok () ¤Ï¡¢M-text $MT ¤ÎÃæ¤Ç°ÌÃÖ $POS 
2434     °Ê¹ßºÇ½é¤Ë¸½¤ì¤ë¥È¡¼¥¯¥ó¤òõ¤¹¡£¤³¤³¤Ç¥È¡¼¥¯¥ó¤È¤Ï M-text $DELIM
2435     ¤ÎÃæ¤Ë¸½¤ï¤ì¤Ê¤¤Ê¸»ú¤À¤±¤«¤é¤Ê¤ëÉôʬʸ»úÎó¤Ç¤¢¤ë¡£$POS ¤Î·¿¤¬ @c int ¤Ç¤Ï¤Ê¤¯¤Æ @c
2436     int ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¤³¤È¤ËÃí°Õ¡£
2437
2438     @return
2439     ¤â¤·¥È¡¼¥¯¥ó¤¬¸«¤Ä¤«¤ì¤Ð mtext_tok ()¤Ï¤½¤Î¥È¡¼¥¯¥ó¤ËÁêÅö¤¹¤ëÉôʬ¤Î 
2440     $MT ¤ò¥³¥Ô¡¼¤·¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢$POS 
2441     ¤Ï¸«¤Ä¤«¤Ã¤¿¥È¡¼¥¯¥ó¤Î½ªÃ¼¤Ë¥»¥Ã¥È¤µ¤ì¤ë¡£¥È¡¼¥¯¥ó¤¬¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï³°ÉôÊÑ¿ô
2442     #merror_code ¤òÊѤ¨¤º¤Ë @c NULL ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï 
2443     @c NULL ¤òÊÖ¤·¡¢ÊÑÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2444
2445     @latexonly \IPAlabel{mtext_tok} @endlatexonly  */
2446
2447 /***
2448     @errors
2449     @c MERROR_RANGE  */
2450
2451 MText *
2452 mtext_tok (MText *mt, MText *delim, int *pos)
2453 {
2454   int nchars = mtext_nchars (mt);
2455   int pos2;
2456
2457   M_CHECK_POS (mt, *pos, NULL);
2458
2459   /*
2460     Skip delimiters starting at POS in MT.
2461     Never do *pos += span(...), or you will change *pos
2462     even though no token is found.
2463    */
2464   pos2 = *pos + span (mt, delim, *pos, Mnil);
2465
2466   if (pos2 == nchars)
2467     return NULL;
2468
2469   *pos = pos2 + span (mt, delim, pos2, Mt);
2470   return (insert (mtext (), 0, mt, pos2, *pos));
2471 }
2472
2473 /*=*/
2474
2475 /***en
2476     @brief Locate an M-text in another.
2477
2478     The mtext_text () function finds the first occurrence of M-text
2479     $MT2 in M-text $MT1 after the position $POS while ignoring
2480     difference of the text properties.
2481
2482     @return
2483     If $MT2 is found in $MT1, mtext_text () returns the position of it
2484     first occurrence.  Otherwise it returns -1.  If $MT2 is empty, it
2485     returns 0.  */
2486
2487 /***ja
2488     @brief M-text Ãæ¤ÇÊ̤ΠM-text ¤òõ¤¹.
2489
2490     ´Ø¿ô mtext_text () ¤Ï¡¢M-text $MT1 Ãæ¤Ç°ÌÃÖ $POS °Ê¹ß¤Ë¸½¤ï¤ì¤ë 
2491     M-text $MT2 ¤ÎºÇ½é¤Î°ÌÃÖ¤òÄ´¤Ù¤ë¡£¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î°ã¤¤¤Ï̵»ë¤µ¤ì¤ë¡£
2492
2493     @return
2494     $MT1 Ãæ¤Ë $MT2 ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_text() 
2495     ¤Ï¤½¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤¤¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£¤â¤· $MT2 ¤¬¶õ¤Ê¤é¤Ð 0 ¤òÊÖ¤¹¡£
2496
2497     @latexonly \IPAlabel{mtext_text} @endlatexonly  */
2498
2499 int
2500 mtext_text (MText *mt1, int pos, MText *mt2)
2501 {
2502   int from = pos;
2503   int pos_byte = POS_CHAR_TO_BYTE (mt1, pos);
2504   int c = mtext_ref_char (mt2, 0);
2505   int nbytes1 = mtext_nbytes (mt1);
2506   int nbytes2 = mtext_nbytes (mt2);
2507   int limit;
2508   int use_memcmp = (mt1->format == mt2->format
2509                     || (mt1->format < MTEXT_FORMAT_UTF_8
2510                         && mt2->format == MTEXT_FORMAT_UTF_8));
2511   int unit_bytes = UNIT_BYTES (mt1->format);
2512
2513   if (nbytes2 > pos_byte + nbytes1)
2514     return -1;
2515   pos_byte = nbytes1 - nbytes2;
2516   limit = POS_BYTE_TO_CHAR (mt1, pos_byte);
2517
2518   while (1)
2519     {
2520       if ((pos = mtext_character (mt1, from, limit, c)) < 0)
2521         return -1;
2522       pos_byte = POS_CHAR_TO_BYTE (mt1, pos);
2523       if (use_memcmp
2524           ? ! memcmp (mt1->data + pos_byte * unit_bytes, 
2525                       mt2->data, nbytes2 * unit_bytes)
2526           : ! compare (mt1, pos, mt2->nchars, mt2, 0, mt2->nchars))
2527         break;
2528       from = pos + 1;
2529     }
2530   return pos;
2531 }
2532
2533 /***en
2534     @brief Locate an M-text in a specific range of another.
2535
2536     The mtext_search () function searches for the first occurrence of
2537     M-text $MT2 in M-text $MT1 in the region $FROM and $TO while
2538     ignoring difference of the text properties.  If $FROM is less than
2539     $TO, the forward search starts from $FROM, otherwise the backward
2540     search starts from $TO.
2541
2542     @return
2543     If $MT2 is found in $MT1, mtext_search () returns the position of the
2544     first occurrence.  Otherwise it returns -1.  If $MT2 is empty, it
2545     returns 0.  */
2546
2547 /***ja
2548     @brief M-text Ãæ¤ÎÆÃÄê¤ÎÎΰè¤ÇÊ̤ΠM-text ¤òõ¤¹.
2549
2550     ´Ø¿ô mtext_search () ¤Ï¡¢M-text $MT1 Ãæ¤Î $FROM ¤«¤é $TO 
2551     ¤Þ¤Ç¤Î´Ö¤ÎÎΰè¤ÇM-text $MT2 
2552     ¤¬ºÇ½é¤Ë¸½¤ï¤ì¤ë°ÌÃÖ¤òÄ´¤Ù¤ë¡£¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î°ã¤¤¤Ï̵»ë¤µ¤ì¤ë¡£¤â¤·
2553     $FROM ¤¬ $TO ¤è¤ê¾®¤µ¤±¤ì¤Ðõº÷¤Ï°ÌÃÖ $FROM ¤«¤éËöÈøÊý¸þ¤Ø¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
2554     $TO ¤«¤éÀèƬÊý¸þ¤Ø¿Ê¤à¡£
2555
2556     @return
2557     $MT1 Ãæ¤Ë $MT2 ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_search() 
2558     ¤Ï¤½¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤¤¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£¤â¤· $MT2 ¤¬¶õ¤Ê¤é¤Ð 0 ¤òÊÖ¤¹¡£
2559     */
2560
2561 int
2562 mtext_search (MText *mt1, int from, int to, MText *mt2)
2563 {
2564   int c = mtext_ref_char (mt2, 0);
2565   int from_byte;
2566   int nbytes2 = mtext_nbytes (mt2);
2567
2568   if (mt1->format > MTEXT_FORMAT_UTF_8
2569       || mt2->format > MTEXT_FORMAT_UTF_8)
2570     MERROR (MERROR_MTEXT, -1);
2571
2572   if (from < to)
2573     {
2574       to -= mtext_nchars (mt2);
2575       if (from > to)
2576         return -1;
2577       while (1)
2578         {
2579           if ((from = find_char_forward (mt1, from, to, c)) < 0)
2580             return -1;
2581           from_byte = POS_CHAR_TO_BYTE (mt1, from);
2582           if (! memcmp (mt1->data + from_byte, mt2->data, nbytes2))
2583             break;
2584           from++;
2585         }
2586     }
2587   else if (from > to)
2588     {
2589       from -= mtext_nchars (mt2);
2590       if (from < to)
2591         return -1;
2592       while (1)
2593         {
2594           if ((from = find_char_backward (mt1, from, to, c)) < 0)
2595             return -1;
2596           from_byte = POS_CHAR_TO_BYTE (mt1, from);
2597           if (! memcmp (mt1->data + from_byte, mt2->data, nbytes2))
2598             break;
2599           from--;
2600         }
2601     }
2602
2603   return from;
2604 }
2605
2606 /*=*/
2607
2608 /***en
2609     @brief Compare two M-texts ignoring cases.
2610
2611     The mtext_casecmp () function is similar to mtext_cmp (), but
2612     ignores cases on comparison.
2613
2614     @return
2615     This function returns 1, 0, or -1 if $MT1 is found greater than,
2616     equal to, or less than $MT2, respectively.  */
2617
2618 /***ja
2619     @brief Æó¤Ä¤Î M-text ¤òÂçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤ÆÈæ³Ó¤¹¤ë.
2620
2621     ´Ø¿ô mtext_casecmp () ¤Ï¡¢´Ø¿ô mtext_cmp () Æ±ÍͤΠM-text 
2622     Æ±»Î¤ÎÈæ³Ó¤ò¡¢Âçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤Æ¹Ô¤Ê¤¦¡£
2623
2624     @return
2625     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 
2626     ¤è¤êÂ礭¤±¤ì¤Ð 1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
2627
2628     @latexonly \IPAlabel{mtext_casecmp} @endlatexonly  */
2629
2630 /***
2631     @seealso
2632     mtext_cmp (), mtext_ncmp (), mtext_ncasecmp ()
2633     mtext_compare (), mtext_case_compare ()  */
2634
2635 int
2636 mtext_casecmp (MText *mt1, MText *mt2)
2637 {
2638   return case_compare (mt1, 0, mt1->nchars, mt2, 0, mt2->nchars);
2639 }
2640
2641 /*=*/
2642
2643 /***en
2644     @brief Compare initial parts of two M-texts ignoring cases.
2645
2646     The mtext_ncasecmp () function is similar to mtext_casecmp (), but
2647     compares at most $N characters from the beginning.
2648
2649     @return
2650     This function returns 1, 0, or -1 if $MT1 is found greater than,
2651     equal to, or less than $MT2, respectively.  */
2652
2653 /***ja
2654     @brief Æó¤Ä¤Î M-text ¤ÎÀèƬÉôʬ¤òÂçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤ÆÈæ³Ó¤¹¤ë.
2655
2656     ´Ø¿ô mtext_ncasecmp () ¤Ï¡¢´Ø¿ô mtext_casecmp () Æ±ÍͤΠM-text 
2657     Æ±»Î¤ÎÈæ³Ó¤òÀèƬ¤«¤éºÇÂç $N Ê¸»ú¤Þ¤Ç¤Ë´Ø¤·¤Æ¹Ô¤Ê¤¦¡£
2658
2659     @return
2660     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 
2661     ¤è¤êÂ礭¤±¤ì¤Ð 1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
2662
2663     @latexonly \IPAlabel{mtext_ncasecmp} @endlatexonly  */
2664
2665 /***
2666     @seealso
2667     mtext_cmp (), mtext_casecmp (), mtext_casecmp ()
2668     mtext_compare (), mtext_case_compare ()  */
2669
2670 int
2671 mtext_ncasecmp (MText *mt1, MText *mt2, int n)
2672 {
2673   if (n < 0)
2674     return 0;
2675   return case_compare (mt1, 0, (mt1->nchars < n ? mt1->nchars : n),
2676                        mt2, 0, (mt2->nchars < n ? mt2->nchars : n));
2677 }
2678
2679 /*=*/
2680
2681 /***en
2682     @brief Compare specified regions of two M-texts ignoring cases. 
2683
2684     The mtext_case_compare () function compares two M-texts $MT1 and
2685     $MT2, character-by-character, ignoring cases.  The compared
2686     regions are between $FROM1 and $TO1 in $MT1 and $FROM2 to $TO2 in
2687     MT2.  $FROM1 and $FROM2 are inclusive, $TO1 and $TO2 are
2688     exclusive.  $FROM1 being equal to $TO1 (or $FROM2 being equal to
2689     $TO2) means an M-text of length zero.  An invalid region
2690     specification is regarded as both $FROM1 and $TO1 (or $FROM2 and
2691     $TO2) being 0.
2692
2693     @return
2694     This function returns 1, 0, or -1 if $MT1 is found greater than,
2695     equal to, or less than $MT2, respectively.  Comparison is based on
2696     character codes.  */
2697
2698 /***ja 
2699     @brief Æó¤Ä¤Î M-text ¤Î»ØÄꤷ¤¿Îΰè¤ò¡¢Âçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤ÆÈæ³Ó¤¹¤ë.
2700
2701     ´Ø¿ô mtext_compare () ¤ÏÆó¤Ä¤Î M-text $MT1 ¤È $MT2 
2702     ¤ò¡¢Âçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤Æʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë¡£Èæ³Ó¤ÎÂоݤϠ$MT1 
2703     ¤Î $FROM1 ¤«¤é $TO1 ¤Þ¤Ç¡¢$MT2 ¤Î $FROM2 ¤«¤é $TO2 ¤Þ¤Ç¤Ç¤¢¤ë¡£
2704     $FROM1 ¤È $FROM2 ¤Ï´Þ¤Þ¤ì¡¢$TO1 ¤È $TO2 ¤Ï´Þ¤Þ¤ì¤Ê¤¤¡£$FROM1 ¤È $TO1
2705     ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 ¡Ë¤¬Åù¤·¤¤¾ì¹ç¤ÏŤµ¥¼¥í¤Î M-text 
2706     ¤ò°ÕÌ£¤¹¤ë¡£ÈÏ°Ï»ØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢$FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï 
2707     $FROM2 ¤È $TO2 ¡ËξÊý¤Ë 0 ¤¬»ØÄꤵ¤ì¤¿¤â¤Î¤È¸«¤Ê¤¹¡£
2708
2709     @return
2710     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì¤Ð
2711     1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð¤Å¤¯¡£
2712
2713   @latexonly \IPAlabel{mtext_case_compare} @endlatexonly
2714 */
2715
2716 /***
2717     @seealso
2718     mtext_cmp (), mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
2719     mtext_compare ()  */
2720
2721 int
2722 mtext_case_compare (MText *mt1, int from1, int to1,
2723                     MText *mt2, int from2, int to2)
2724 {
2725   if (from1 < 0 || from1 > to1 || to1 > mt1->nchars)
2726     from1 = to1 = 0;
2727
2728   if (from2 < 0 || from2 > to2 || to2 > mt2->nchars)
2729     from2 = to2 = 0;
2730
2731   return case_compare (mt1, from1, to1, mt2, from2, to2);
2732 }
2733
2734 /*** @} */
2735
2736 #include <stdio.h>
2737
2738 /*** @addtogroup m17nDebug */
2739 /*=*/
2740 /*** @{  */
2741
2742 /***en
2743     @brief Dump an M-text.
2744
2745     The mdebug_dump_mtext () function prints the M-text $MT in a human
2746     readable way to the stderr.  $INDENT specifies how many columns to
2747     indent the lines but the first one.  If $FULLP is zero, this
2748     function prints only a character code sequence.  Otherwise, it
2749     prints the internal byte sequence and text properties as well.
2750
2751     @return
2752     This function returns $MT.  */
2753 /***ja
2754     @brief M-text ¤ò¥À¥ó¥×¤¹¤ë.
2755
2756     ´Ø¿ô mdebug_dump_mtext () ¤Ï M-text $MT ¤ò stderr 
2757     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
2758     $FULLP ¤¬ 0 ¤Ê¤é¤Ð¡¢Ê¸»ú¥³¡¼¥ÉÎó¤À¤±¤ò°õºþ¤¹¤ë¡£
2759     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢ÆâÉô¥Ð¥¤¥ÈÎó¤È¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤â°õºþ¤¹¤ë¡£
2760
2761     @return
2762     ¤³¤Î´Ø¿ô¤Ï $MT ¤òÊÖ¤¹¡£  */
2763
2764 MText *
2765 mdebug_dump_mtext (MText *mt, int indent, int fullp)
2766 {
2767   char *prefix = (char *) alloca (indent + 1);
2768   int i;
2769   unsigned char *p;
2770
2771   memset (prefix, 32, indent);
2772   prefix[indent] = 0;
2773
2774   fprintf (stderr,
2775            "(mtext (size %d %d %d) (cache %d %d)",
2776            mt->nchars, mt->nbytes, mt->allocated,
2777            mt->cache_char_pos, mt->cache_byte_pos);
2778   if (! fullp)
2779     {
2780       fprintf (stderr, " \"");
2781       for (i = 0; i < mt->nchars; i++)
2782         {
2783           int c = mtext_ref_char (mt, i);
2784           if (c >= ' ' && c < 127)
2785             fprintf (stderr, "%c", c);
2786           else
2787             fprintf (stderr, "\\x%02X", c);
2788         }
2789       fprintf (stderr, "\"");
2790     }
2791   else if (mt->nchars > 0)
2792     {
2793       fprintf (stderr, "\n%s (bytes \"", prefix);
2794       for (i = 0; i < mt->nbytes; i++)
2795         fprintf (stderr, "\\x%02x", mt->data[i]);
2796       fprintf (stderr, "\")\n");
2797       fprintf (stderr, "%s (chars \"", prefix);
2798       p = mt->data;
2799       for (i = 0; i < mt->nchars; i++)
2800         {
2801           int len;
2802           int c = STRING_CHAR_AND_BYTES (p, len);
2803
2804           if (c >= ' ' && c < 127 && c != '\\' && c != '\"')
2805             fputc (c, stderr);
2806           else
2807             fprintf (stderr, "\\x%X", c);
2808           p += len;
2809         }
2810       fprintf (stderr, "\")");
2811       if (mt->plist)
2812         {
2813           fprintf (stderr, "\n%s ", prefix);
2814           dump_textplist (mt->plist, indent + 1);
2815         }
2816     }
2817   fprintf (stderr, ")");
2818   return mt;
2819 }
2820
2821 /*** @} */ 
2822
2823 /*
2824   Local Variables:
2825   coding: euc-japan
2826   End:
2827 */