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