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