Copyright years udpated.
[m17n/m17n-lib.git] / src / mtext.c
1 /* mtext.c -- M-text module.
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup 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 /** Case handler (case-folding comparison and case conversion) */
615
616 /** Structure for an iterator used in case-fold comparison.  */
617
618 struct casecmp_iterator {
619   MText *mt;
620   int pos;
621   MText *folded;
622   unsigned char *foldedp;
623   int folded_len;
624 };
625
626 static int
627 next_char_from_it (struct casecmp_iterator *it)
628 {
629   int c, c1;
630
631   if (it->folded)
632     {
633       c = STRING_CHAR_AND_BYTES (it->foldedp, it->folded_len);
634       return c;
635     }
636
637   c = mtext_ref_char (it->mt, it->pos);
638   c1 = (int) mchar_get_prop (c, Msimple_case_folding);
639   if (c1 == 0xFFFF)
640     {
641       it->folded
642         = (MText *) mchar_get_prop (c, Mcomplicated_case_folding);
643       it->foldedp = it->folded->data;
644       c = STRING_CHAR_AND_BYTES (it->foldedp, it->folded_len);
645       return c;
646     }
647
648   if (c1 >= 0)
649     c = c1;
650   return c;
651 }
652
653 static void
654 advance_it (struct casecmp_iterator *it)
655 {
656   if (it->folded)
657     {
658       it->foldedp += it->folded_len;
659       if (it->foldedp == it->folded->data + it->folded->nbytes)
660         it->folded = NULL;
661     }
662   if (! it->folded)
663     {
664       it->pos++;
665     }
666 }
667
668 static int
669 case_compare (MText *mt1, int from1, int to1, MText *mt2, int from2, int to2)
670 {
671   struct casecmp_iterator it1, it2;
672
673   it1.mt = mt1, it1.pos = from1, it1.folded = NULL;
674   it2.mt = mt2, it2.pos = from2, it2.folded = NULL;
675
676   while (it1.pos < to1 && it2.pos < to2)
677     {
678       int c1 = next_char_from_it (&it1);
679       int c2 = next_char_from_it (&it2);
680
681       if (c1 != c2)
682         return (c1 > c2 ? 1 : -1);
683       advance_it (&it1);
684       advance_it (&it2);
685     }
686   return (it2.pos == to2 ? (it1.pos < to1) : -1);
687 }
688
689 static MCharTable *tricky_chars, *cased, *soft_dotted, *case_mapping;
690 static MCharTable *combining_class;
691
692 /* Languages that require special handling in case-conversion.  */
693 static MSymbol Mlt, Mtr, Maz;
694
695 static MText *gr03A3;
696 static MText *lt0049, *lt004A, *lt012E, *lt00CC, *lt00CD, *lt0128;
697 static MText *tr0130, *tr0049, *tr0069;
698
699 static int
700 init_case_conversion ()
701 {
702   Mlt = msymbol ("lt");
703   Mtr = msymbol ("tr");
704   Maz = msymbol ("az");
705
706   gr03A3 = mtext ();
707   mtext_cat_char (gr03A3, 0x03C2);
708
709   lt0049 = mtext ();
710   mtext_cat_char (lt0049, 0x0069);
711   mtext_cat_char (lt0049, 0x0307);
712
713   lt004A = mtext ();
714   mtext_cat_char (lt004A, 0x006A);
715   mtext_cat_char (lt004A, 0x0307);
716
717   lt012E = mtext ();
718   mtext_cat_char (lt012E, 0x012F);
719   mtext_cat_char (lt012E, 0x0307);
720
721   lt00CC = mtext ();
722   mtext_cat_char (lt00CC, 0x0069);
723   mtext_cat_char (lt00CC, 0x0307);
724   mtext_cat_char (lt00CC, 0x0300);
725
726   lt00CD = mtext ();
727   mtext_cat_char (lt00CD, 0x0069);
728   mtext_cat_char (lt00CD, 0x0307);
729   mtext_cat_char (lt00CD, 0x0301);
730
731   lt0128 = mtext ();
732   mtext_cat_char (lt0128, 0x0069);
733   mtext_cat_char (lt0128, 0x0307);
734   mtext_cat_char (lt0128, 0x0303);
735
736   tr0130 = mtext ();
737   mtext_cat_char (tr0130, 0x0069);
738
739   tr0049 = mtext ();
740   mtext_cat_char (tr0049, 0x0131);
741
742   tr0069 = mtext ();
743   mtext_cat_char (tr0069, 0x0130);
744
745   if (! (cased = mchar_get_prop_table (msymbol ("cased"), NULL)))
746     return -1;
747   if (! (soft_dotted = mchar_get_prop_table (msymbol ("soft-dotted"), NULL)))
748     return -1;
749   if (! (case_mapping = mchar_get_prop_table (msymbol ("case-mapping"), NULL)))
750     return -1;
751   if (! (combining_class = mchar_get_prop_table (Mcombining_class, NULL)))
752     return -1;
753
754   tricky_chars = mchartable (Mnil, 0);
755   mchartable_set (tricky_chars, 0x0049, (void *) 1);
756   mchartable_set (tricky_chars, 0x004A, (void *) 1);
757   mchartable_set (tricky_chars, 0x00CC, (void *) 1);
758   mchartable_set (tricky_chars, 0x00CD, (void *) 1);
759   mchartable_set (tricky_chars, 0x0128, (void *) 1);
760   mchartable_set (tricky_chars, 0x012E, (void *) 1);
761   mchartable_set (tricky_chars, 0x0130, (void *) 1);
762   mchartable_set (tricky_chars, 0x0307, (void *) 1);
763   mchartable_set (tricky_chars, 0x03A3, (void *) 1);
764   return 0;
765 }
766
767 #define CASE_CONV_INIT(ret)             \
768   do {                                  \
769     if (! tricky_chars                  \
770         && init_case_conversion () < 0) \
771       MERROR (MERROR_MTEXT, ret);       \
772   } while (0)
773
774 /* Replace the character at POS of MT with VAR and increment I and LEN.  */
775
776 #define REPLACE(var)                                    \
777   do {                                                  \
778     int varlen = var->nchars;                           \
779                                                         \
780     mtext_replace (mt, pos, pos + 1, var, 0, varlen);   \
781     pos += varlen;                                      \
782     end += varlen - 1;                                  \
783   } while (0)
784
785 /* Delete the character at POS of MT and decrement LEN.  */
786
787 #define DELETE                          \
788   do {                                  \
789     mtext_del (mt, pos, pos + 1);       \
790     end--;                              \
791   } while (0)
792
793 #define LOOKUP                                                          \
794   do {                                                                  \
795     MPlist *pl = (MPlist *) mchartable_lookup (case_mapping, c);        \
796                                                                         \
797     if (pl)                                                             \
798       {                                                                 \
799         /* Lowercase is the 1st element. */                             \
800         MText *lower = MPLIST_VAL ((MPlist *) MPLIST_VAL (pl));         \
801         int llen = mtext_nchars (lower);                                \
802                                                                         \
803         if (mtext_ref_char (lower, 0) != c || llen > 1)                 \
804           {                                                             \
805             mtext_replace (mt, pos, pos + 1, lower, 0, llen);           \
806             pos += llen;                                                \
807             end += llen - 1;                                            \
808           }                                                             \
809         else                                                            \
810           pos++;                                                        \
811       }                                                                 \
812     else                                                                \
813       pos++;                                                            \
814   } while (0)
815
816
817 int
818 uppercase_precheck (MText *mt, int pos, int end)
819 {
820   for (; pos < end; pos++)
821     if (mtext_ref_char (mt, pos) == 0x0307 &&
822         (MSymbol) mtext_get_prop (mt, pos, Mlanguage) == Mlt)
823       return 1;
824   return 0;
825 }
826
827 int
828 lowercase_precheck (MText *mt, int pos, int end)
829 {
830   int c;
831   MSymbol lang;
832
833   for (; pos < end; pos++)
834     {
835       c = mtext_ref_char (mt, pos);
836
837       if ((int) mchartable_lookup (tricky_chars, c) == 1)
838       {
839         if (c == 0x03A3)
840           return 1;
841
842         lang = mtext_get_prop (mt, pos, Mlanguage);
843
844         if (lang == Mlt &&
845             (c == 0x0049 || c == 0x004A || c == 0x012E))
846           return 1;
847
848         if ((lang == Mtr || lang == Maz) &&
849             (c == 0x0307 || c == 0x0049))
850           return 1;
851       }
852     }
853   return 0;
854 }
855
856 #define CASED 1
857 #define CASE_IGNORABLE 2
858
859 int
860 final_sigma (MText *mt, int pos)
861 {
862   int i, len = mtext_len (mt);
863   int c;
864
865   for (i = pos - 1; i >= 0; i--)
866     {
867       c = (int) mchartable_lookup (cased, mtext_ref_char (mt, i));
868       if (c == -1)
869         c = 0;
870       if (c & CASED)
871         break;
872       if (! (c & CASE_IGNORABLE))
873         return 0;
874     }
875
876   if (i == -1)
877     return 0;
878
879   for (i = pos + 1; i < len; i++)
880     {
881       c = (int) mchartable_lookup (cased, mtext_ref_char (mt, i));
882       if (c == -1)
883         c = 0;
884       if (c & CASED)
885         return 0;
886       if (! (c & CASE_IGNORABLE))
887         return 1;
888     }
889
890   return 1;
891 }
892
893 int
894 after_soft_dotted (MText *mt, int i)
895 {
896   int c, class;
897
898   for (i--; i >= 0; i--)
899     {
900       c = mtext_ref_char (mt, i);
901       if ((MSymbol) mchartable_lookup (soft_dotted, c) == Mt)
902         return 1;
903       class = (int) mchartable_lookup (combining_class, c);
904       if (class == 0 || class == 230)
905         return 0;
906     }
907
908   return 0;
909 }
910
911 int
912 more_above (MText *mt, int i)
913 {
914   int class, len = mtext_len (mt);
915
916   for (i++; i < len; i++)
917     {
918       class = (int) mchartable_lookup (combining_class,
919                                        mtext_ref_char (mt, i));
920       if (class == 230)
921         return 1;
922       if (class == 0)
923         return 0;
924     }
925
926   return 0;
927 }
928
929 int
930 before_dot (MText *mt, int i)
931 {
932   int c, class, len = mtext_len (mt);
933
934   for (i++; i < len; i++)
935     {
936       c = mtext_ref_char (mt, i);
937       if (c == 0x0307)
938         return 1;
939       class = (int) mchartable_lookup (combining_class, c);
940       if (class == 230 || class == 0)
941         return 0;
942     }
943
944   return 0;
945 }
946
947 int
948 after_i (MText *mt, int i)
949 {
950   int c, class;
951
952   for (i--; i >= 0; i--)
953     {
954       c = mtext_ref_char (mt, i);
955       if (c == (int) 'I')
956         return 1;
957       class = (int) mchartable_lookup (combining_class, c);
958       if (class == 230 || class == 0)
959         return 0;
960     }
961
962   return 0;
963 }
964
965 \f
966 /* Internal API */
967
968 int
969 mtext__init ()
970 {
971   M17N_OBJECT_ADD_ARRAY (mtext_table, "M-text");
972   M_charbag = msymbol_as_managing_key ("  charbag");
973   mtext_table.count = 0;
974   Mlanguage = msymbol ("language");
975   return 0;
976 }
977
978
979 void
980 mtext__fini (void)
981 {
982   mtext__wseg_fini ();
983 }
984
985
986 int
987 mtext__char_to_byte (MText *mt, int pos)
988 {
989   int char_pos, byte_pos;
990   int forward;
991
992   if (pos < mt->cache_char_pos)
993     {
994       if (mt->cache_char_pos == mt->cache_byte_pos)
995         return pos;
996       if (pos < mt->cache_char_pos - pos)
997         {
998           char_pos = byte_pos = 0;
999           forward = 1;
1000         }
1001       else
1002         {
1003           char_pos = mt->cache_char_pos;
1004           byte_pos = mt->cache_byte_pos;
1005           forward = 0;
1006         }
1007     }
1008   else
1009     {
1010       if (mt->nchars - mt->cache_char_pos == mt->nbytes - mt->cache_byte_pos)
1011         return (mt->cache_byte_pos + (pos - mt->cache_char_pos));
1012       if (pos - mt->cache_char_pos < mt->nchars - pos)
1013         {
1014           char_pos = mt->cache_char_pos;
1015           byte_pos = mt->cache_byte_pos;
1016           forward = 1;
1017         }
1018       else
1019         {
1020           char_pos = mt->nchars;
1021           byte_pos = mt->nbytes;
1022           forward = 0;
1023         }
1024     }
1025   if (forward)
1026     while (char_pos < pos)
1027       INC_POSITION (mt, char_pos, byte_pos);
1028   else
1029     while (char_pos > pos)
1030       DEC_POSITION (mt, char_pos, byte_pos);
1031   mt->cache_char_pos = char_pos;
1032   mt->cache_byte_pos = byte_pos;
1033   return byte_pos;
1034 }
1035
1036 /* mtext__byte_to_char () */
1037
1038 int
1039 mtext__byte_to_char (MText *mt, int pos_byte)
1040 {
1041   int char_pos, byte_pos;
1042   int forward;
1043
1044   if (pos_byte < mt->cache_byte_pos)
1045     {
1046       if (mt->cache_char_pos == mt->cache_byte_pos)
1047         return pos_byte;
1048       if (pos_byte < mt->cache_byte_pos - pos_byte)
1049         {
1050           char_pos = byte_pos = 0;
1051           forward = 1;
1052         }
1053       else
1054         {
1055           char_pos = mt->cache_char_pos;
1056           byte_pos = mt->cache_byte_pos;
1057           forward = 0;
1058         }
1059     }
1060   else
1061     {
1062       if (mt->nchars - mt->cache_char_pos == mt->nbytes - mt->cache_byte_pos)
1063         return (mt->cache_char_pos + (pos_byte - mt->cache_byte_pos));
1064       if (pos_byte - mt->cache_byte_pos < mt->nbytes - pos_byte)
1065         {
1066           char_pos = mt->cache_char_pos;
1067           byte_pos = mt->cache_byte_pos;
1068           forward = 1;
1069         }
1070       else
1071         {
1072           char_pos = mt->nchars;
1073           byte_pos = mt->nbytes;
1074           forward = 0;
1075         }
1076     }
1077   if (forward)
1078     while (byte_pos < pos_byte)
1079       INC_POSITION (mt, char_pos, byte_pos);
1080   else
1081     while (byte_pos > pos_byte)
1082       DEC_POSITION (mt, char_pos, byte_pos);
1083   mt->cache_char_pos = char_pos;
1084   mt->cache_byte_pos = byte_pos;
1085   return char_pos;
1086 }
1087
1088 /* Estimated extra bytes that malloc will use for its own purpose on
1089    each memory allocation.  */
1090 #define MALLOC_OVERHEAD 4
1091 #define MALLOC_MININUM_BYTES 12
1092
1093 void
1094 mtext__enlarge (MText *mt, int nbytes)
1095 {
1096   nbytes += MAX_UTF8_CHAR_BYTES;
1097   if (mt->allocated >= nbytes)
1098     return;
1099   if (nbytes < MALLOC_MININUM_BYTES)
1100     nbytes = MALLOC_MININUM_BYTES;
1101   while (mt->allocated < nbytes)
1102     mt->allocated = mt->allocated * 2 + MALLOC_OVERHEAD;
1103   MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
1104 }
1105
1106 int
1107 mtext__takein (MText *mt, int nchars, int nbytes)
1108 {
1109   if (mt->plist)
1110     mtext__adjust_plist_for_insert (mt, mt->nchars, nchars, NULL);
1111   mt->nchars += nchars;
1112   mt->nbytes += nbytes;
1113   mt->data[mt->nbytes] = 0;
1114   return 0;
1115 }
1116
1117
1118 int
1119 mtext__cat_data (MText *mt, unsigned char *p, int nbytes,
1120                  enum MTextFormat format)
1121 {
1122   int nchars = -1;
1123
1124   if (mt->format > MTEXT_FORMAT_UTF_8)
1125     MERROR (MERROR_MTEXT, -1);
1126   if (format == MTEXT_FORMAT_US_ASCII)
1127     nchars = nbytes;
1128   else if (format == MTEXT_FORMAT_UTF_8)
1129     nchars = count_utf_8_chars (p, nbytes);
1130   if (nchars < 0)
1131     MERROR (MERROR_MTEXT, -1);
1132   mtext__enlarge (mt, mtext_nbytes (mt) + nbytes + 1);
1133   memcpy (MTEXT_DATA (mt) + mtext_nbytes (mt), p, nbytes);
1134   mtext__takein (mt, nchars, nbytes);
1135   return nchars;
1136 }
1137
1138 MText *
1139 mtext__from_data (const void *data, int nitems, enum MTextFormat format,
1140                   int need_copy)
1141 {
1142   MText *mt;
1143   int nchars, nbytes, unit_bytes;
1144
1145   if (format == MTEXT_FORMAT_US_ASCII)
1146     {
1147       const char *p = (char *) data, *pend = p + nitems;
1148
1149       while (p < pend)
1150         if (*p++ < 0)
1151           MERROR (MERROR_MTEXT, NULL);
1152       nchars = nbytes = nitems;
1153       unit_bytes = 1;
1154     }
1155   else if (format == MTEXT_FORMAT_UTF_8)
1156     {
1157       if ((nchars = count_utf_8_chars (data, nitems)) < 0)
1158         MERROR (MERROR_MTEXT, NULL);
1159       nbytes = nitems;
1160       unit_bytes = 1;
1161     }
1162   else if (format <= MTEXT_FORMAT_UTF_16BE)
1163     {
1164       if ((nchars = count_utf_16_chars (data, nitems,
1165                                         format != MTEXT_FORMAT_UTF_16)) < 0)
1166         MERROR (MERROR_MTEXT, NULL);
1167       nbytes = USHORT_SIZE * nitems;
1168       unit_bytes = USHORT_SIZE;
1169     }
1170   else                          /* MTEXT_FORMAT_UTF_32XX */
1171     {
1172       nchars = nitems;
1173       nbytes = UINT_SIZE * nitems;
1174       unit_bytes = UINT_SIZE;
1175     }
1176
1177   mt = mtext ();
1178   mt->format = format;
1179   mt->coverage = FORMAT_COVERAGE (format);
1180   mt->allocated = need_copy ? nbytes + unit_bytes : -1;
1181   mt->nchars = nchars;
1182   mt->nbytes = nitems;
1183   if (need_copy)
1184     {
1185       MTABLE_MALLOC (mt->data, mt->allocated, MERROR_MTEXT);
1186       memcpy (mt->data, data, nbytes);
1187       mt->data[nbytes] = 0;
1188     }
1189   else
1190     mt->data = (unsigned char *) data;
1191   return mt;
1192 }
1193
1194
1195 void
1196 mtext__adjust_format (MText *mt, enum MTextFormat format)
1197 {
1198   int i, c;
1199
1200   if (mt->nchars > 0)
1201     switch (format)
1202       {
1203       case MTEXT_FORMAT_US_ASCII:
1204         {
1205           unsigned char *p = mt->data;
1206
1207           for (i = 0; i < mt->nchars; i++)
1208             *p++ = mtext_ref_char (mt, i);
1209           mt->nbytes = mt->nchars;
1210           mt->cache_byte_pos = mt->cache_char_pos;
1211           break;
1212         }
1213
1214       case MTEXT_FORMAT_UTF_8:
1215         {
1216           unsigned char *p0, *p1;
1217
1218           i = count_by_utf_8 (mt, 0, mt->nchars) + 1;
1219           MTABLE_MALLOC (p0, i, MERROR_MTEXT);
1220           mt->allocated = i;
1221           for (i = 0, p1 = p0; i < mt->nchars; i++)
1222             {
1223               c = mtext_ref_char (mt, i);
1224               p1 += CHAR_STRING_UTF8 (c, p1);
1225             }
1226           *p1 = '\0';
1227           free (mt->data);
1228           mt->data = p0;
1229           mt->nbytes = p1 - p0;
1230           mt->cache_char_pos = mt->cache_byte_pos = 0;
1231           break;
1232         }
1233
1234       default:
1235         if (format == MTEXT_FORMAT_UTF_16)
1236           {
1237             unsigned short *p0, *p1;
1238
1239             i = (count_by_utf_16 (mt, 0, mt->nchars) + 1) * USHORT_SIZE;
1240             MTABLE_MALLOC (p0, i, MERROR_MTEXT);
1241             mt->allocated = i;
1242             for (i = 0, p1 = p0; i < mt->nchars; i++)
1243               {
1244                 c = mtext_ref_char (mt, i);
1245                 p1 += CHAR_STRING_UTF16 (c, p1);
1246               }
1247             *p1 = 0;
1248             free (mt->data);
1249             mt->data = (unsigned char *) p0;
1250             mt->nbytes = p1 - p0;
1251             mt->cache_char_pos = mt->cache_byte_pos = 0;
1252             break;
1253           }
1254         else
1255           {
1256             unsigned int *p;
1257
1258             mt->allocated = (mt->nchars + 1) * UINT_SIZE;
1259             MTABLE_MALLOC (p, mt->allocated, MERROR_MTEXT);
1260             for (i = 0; i < mt->nchars; i++)
1261               p[i] = mtext_ref_char (mt, i);
1262             p[i] = 0;
1263             free (mt->data);
1264             mt->data = (unsigned char *) p;
1265             mt->nbytes = mt->nchars;
1266             mt->cache_byte_pos = mt->cache_char_pos;
1267           }
1268       }
1269   mt->format = format;
1270   mt->coverage = FORMAT_COVERAGE (format);
1271 }
1272
1273
1274 /* Find the position of a character at the beginning of a line of
1275    M-Text MT searching backward from POS.  */
1276
1277 int
1278 mtext__bol (MText *mt, int pos)
1279 {
1280   int byte_pos;
1281
1282   if (pos == 0)
1283     return pos;
1284   byte_pos = POS_CHAR_TO_BYTE (mt, pos);
1285   if (mt->format <= MTEXT_FORMAT_UTF_8)
1286     {
1287       unsigned char *p = mt->data + byte_pos;
1288
1289       if (p[-1] == '\n')
1290         return pos;
1291       p--;
1292       while (p > mt->data && p[-1] != '\n')
1293         p--;
1294       if (p == mt->data)
1295         return 0;
1296       byte_pos = p - mt->data;
1297       return POS_BYTE_TO_CHAR (mt, byte_pos);
1298     }
1299   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1300     {
1301       unsigned short *p = ((unsigned short *) (mt->data)) + byte_pos;
1302       unsigned short newline = (mt->format == MTEXT_FORMAT_UTF_16
1303                                 ? 0x0A00 : 0x000A);
1304
1305       if (p[-1] == newline)
1306         return pos;
1307       p--;
1308       while (p > (unsigned short *) (mt->data) && p[-1] != newline)
1309         p--;
1310       if (p == (unsigned short *) (mt->data))
1311         return 0;
1312       byte_pos = p - (unsigned short *) (mt->data);
1313       return POS_BYTE_TO_CHAR (mt, byte_pos);;
1314     }
1315   else
1316     {
1317       unsigned *p = ((unsigned *) (mt->data)) + byte_pos;
1318       unsigned newline = (mt->format == MTEXT_FORMAT_UTF_32
1319                           ? 0x0A000000 : 0x0000000A);
1320
1321       if (p[-1] == newline)
1322         return pos;
1323       p--, pos--;
1324       while (p > (unsigned *) (mt->data) && p[-1] != newline)
1325         p--, pos--;
1326       return pos;
1327     }
1328 }
1329
1330
1331 /* Find the position of a character at the end of a line of M-Text MT
1332    searching forward from POS.  */
1333
1334 int
1335 mtext__eol (MText *mt, int pos)
1336 {
1337   int byte_pos;
1338
1339   if (pos == mt->nchars)
1340     return pos;
1341   byte_pos = POS_CHAR_TO_BYTE (mt, pos);
1342   if (mt->format <= MTEXT_FORMAT_UTF_8)
1343     {
1344       unsigned char *p = mt->data + byte_pos;
1345       unsigned char *endp;
1346
1347       if (*p == '\n')
1348         return pos + 1;
1349       p++;
1350       endp = mt->data + mt->nbytes;
1351       while (p < endp && *p != '\n')
1352         p++;
1353       if (p == endp)
1354         return mt->nchars;
1355       byte_pos = p + 1 - mt->data;
1356       return POS_BYTE_TO_CHAR (mt, byte_pos);
1357     }
1358   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1359     {
1360       unsigned short *p = ((unsigned short *) (mt->data)) + byte_pos;
1361       unsigned short *endp;
1362       unsigned short newline = (mt->format == MTEXT_FORMAT_UTF_16
1363                                 ? 0x0A00 : 0x000A);
1364
1365       if (*p == newline)
1366         return pos + 1;
1367       p++;
1368       endp = (unsigned short *) (mt->data) + mt->nbytes;
1369       while (p < endp && *p != newline)
1370         p++;
1371       if (p == endp)
1372         return mt->nchars;
1373       byte_pos = p + 1 - (unsigned short *) (mt->data);
1374       return POS_BYTE_TO_CHAR (mt, byte_pos);
1375     }
1376   else
1377     {
1378       unsigned *p = ((unsigned *) (mt->data)) + byte_pos;
1379       unsigned *endp;
1380       unsigned newline = (mt->format == MTEXT_FORMAT_UTF_32
1381                           ? 0x0A000000 : 0x0000000A);
1382
1383       if (*p == newline)
1384         return pos + 1;
1385       p++, pos++;
1386       endp = (unsigned *) (mt->data) + mt->nbytes;
1387       while (p < endp && *p != newline)
1388         p++, pos++;
1389       return pos;
1390     }
1391 }
1392
1393 int
1394 mtext__lowercase (MText *mt, int pos, int end)
1395 {
1396   int opos = pos;
1397   int c;
1398   MText *orig = NULL;
1399   MSymbol lang;
1400
1401   if (lowercase_precheck (mt, pos, end))
1402     orig = mtext_dup (mt);
1403
1404   for (; pos < end; opos++)
1405     {
1406       c = mtext_ref_char (mt, pos);
1407       lang = (MSymbol) mtext_get_prop (mt, pos, Mlanguage);
1408
1409       if (c == 0x03A3 && final_sigma (orig, opos))
1410         REPLACE (gr03A3);
1411
1412       else if (lang == Mlt)
1413         {
1414           if (c == 0x00CC)
1415             REPLACE (lt00CC);
1416           else if (c == 0x00CD)
1417             REPLACE (lt00CD);
1418           else if (c == 0x0128)
1419             REPLACE (lt0128);
1420           else if (orig && more_above (orig, opos))
1421             {
1422               if (c == 0x0049)
1423                 REPLACE (lt0049);
1424               else if (c == 0x004A)
1425                 REPLACE (lt004A);
1426               else if (c == 0x012E)
1427                 REPLACE (lt012E);
1428               else
1429                 LOOKUP;
1430             }
1431           else
1432             LOOKUP;
1433         }
1434
1435       else if (lang == Mtr || lang == Maz)
1436         {
1437           if (c == 0x0130)
1438             REPLACE (tr0130);
1439           else if (c == 0x0307 && after_i (orig, opos))
1440             DELETE;
1441           else if (c == 0x0049 && ! before_dot (orig, opos))
1442             REPLACE (tr0049);
1443           else
1444             LOOKUP;
1445         }
1446
1447       else
1448         LOOKUP;
1449     }
1450
1451   if (orig)
1452     m17n_object_unref (orig);
1453
1454   return end;
1455 }
1456
1457 int
1458 mtext__titlecase (MText *mt, int pos, int end)
1459 {
1460   int opos = pos;
1461   int c;
1462   MText *orig = NULL;
1463   MSymbol lang;
1464   MPlist *pl;
1465
1466   /* Precheck for titlecase is identical to that for uppercase. */
1467   if (uppercase_precheck (mt, pos, end))
1468     orig = mtext_dup (mt);
1469
1470   for (; pos < end; opos++)
1471     {
1472       c = mtext_ref_char (mt, pos);
1473       lang = (MSymbol) mtext_get_prop (mt, pos, Mlanguage);
1474
1475       if ((lang == Mtr || lang == Maz) && c == 0x0069)
1476         REPLACE (tr0069);
1477
1478       else if (lang == Mlt && c == 0x0307 && after_soft_dotted (orig, opos))
1479         DELETE;
1480
1481       else if ((pl = (MPlist *) mchartable_lookup (case_mapping, c)))
1482         {
1483           /* Titlecase is the 2nd element. */
1484           MText *title
1485             = (MText *) mplist_value (mplist_next (mplist_value (pl)));
1486           int tlen = mtext_len (title);
1487
1488           if (mtext_ref_char (title, 0) != c || tlen > 1)
1489             {
1490               mtext_replace (mt, pos, pos + 1, title, 0, tlen);
1491               pos += tlen;
1492               end += tlen - 1;
1493             }
1494
1495           else
1496             pos++;
1497         }
1498
1499       else
1500         pos++;
1501     }
1502
1503   if (orig)
1504     m17n_object_unref (orig);
1505
1506   return end;
1507 }
1508
1509 int
1510 mtext__uppercase (MText *mt, int pos, int end)
1511 {
1512   int opos = pos;
1513   int c;
1514   MText *orig = NULL;
1515   MSymbol lang;
1516   MPlist *pl;
1517
1518   CASE_CONV_INIT (-1);
1519
1520   if (uppercase_precheck (mt, 0, end))
1521     orig = mtext_dup (mt);
1522
1523   for (; pos < end; opos++)
1524     {
1525       c = mtext_ref_char (mt, pos);
1526       lang = (MSymbol) mtext_get_prop (mt, pos, Mlanguage);
1527
1528       if (lang == Mlt && c == 0x0307 && after_soft_dotted (orig, opos))
1529         DELETE;
1530
1531       else if ((lang == Mtr || lang == Maz) && c == 0x0069)
1532         REPLACE (tr0069);
1533                
1534       else
1535         {
1536           if ((pl = (MPlist *) mchartable_lookup (case_mapping, c)) != NULL)
1537             {
1538               MText *upper;
1539               int ulen;
1540
1541               /* Uppercase is the 3rd element. */
1542               upper = (MText *) mplist_value (mplist_next (mplist_next (mplist_value (pl))));
1543               ulen = mtext_len (upper);
1544
1545               if (mtext_ref_char (upper, 0) != c || ulen > 1)
1546                 {
1547                   mtext_replace (mt, pos, pos + 1, upper, 0, ulen);
1548                   pos += ulen;
1549                   end += ulen - 1;
1550                 }
1551
1552               else
1553                 pos++;
1554             }
1555
1556           else                                           /* pl == NULL */
1557             pos++;
1558         }
1559     }
1560
1561   if (orig)
1562     m17n_object_unref (orig);
1563
1564   return end;
1565 }
1566
1567 /*** @} */
1568 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1569
1570 \f
1571 /* External API */
1572
1573 #ifdef WORDS_BIGENDIAN
1574 const enum MTextFormat MTEXT_FORMAT_UTF_16 = MTEXT_FORMAT_UTF_16BE;
1575 #else
1576 const enum MTextFormat MTEXT_FORMAT_UTF_16 = MTEXT_FORMAT_UTF_16LE;
1577 #endif
1578
1579 #ifdef WORDS_BIGENDIAN
1580 const int MTEXT_FORMAT_UTF_32 = MTEXT_FORMAT_UTF_32BE;
1581 #else
1582 const int MTEXT_FORMAT_UTF_32 = MTEXT_FORMAT_UTF_32LE;
1583 #endif
1584
1585 /*** @addtogroup m17nMtext */
1586 /*** @{ */
1587 /*=*/
1588
1589 /***en The symbol whose name is "language".  */
1590 /***ja "language" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë.  */
1591 MSymbol Mlanguage;
1592
1593 /*=*/
1594
1595 /***en
1596     @brief Allocate a new M-text.
1597
1598     The mtext () function allocates a new M-text of length 0 and
1599     returns a pointer to it.  The allocated M-text will not be freed
1600     unless the user explicitly does so with the m17n_object_unref ()
1601     function.  */
1602
1603 /***ja
1604     @brief ¿·¤·¤¤M-text¤ò³ä¤êÅö¤Æ¤ë.
1605
1606     ´Ø¿ô mtext () ¤Ï¡¢Ä¹¤µ 0 ¤Î¿·¤·¤¤ M-text 
1607     ¤ò³ä¤êÅö¤Æ¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£³ä¤êÅö¤Æ¤é¤ì¤¿ M-text ¤Ï¡¢´Ø¿ô
1608     m17n_object_unref () ¤Ë¤è¤Ã¤Æ¥æ¡¼¥¶¤¬ÌÀ¼¨Åª¤Ë¹Ô¤Ê¤ï¤Ê¤¤¸Â¤ê¡¢²òÊü¤µ¤ì¤Ê¤¤¡£
1609
1610     @latexonly \IPAlabel{mtext} @endlatexonly  */
1611
1612 /***
1613     @seealso
1614     m17n_object_unref ()  */
1615
1616 MText *
1617 mtext ()
1618 {
1619   MText *mt;
1620
1621   M17N_OBJECT (mt, free_mtext, MERROR_MTEXT);
1622   mt->format = MTEXT_FORMAT_US_ASCII;
1623   mt->coverage = MTEXT_COVERAGE_ASCII;
1624   M17N_OBJECT_REGISTER (mtext_table, mt);
1625   return mt;
1626 }
1627
1628 /***en
1629     @brief Allocate a new M-text with specified data.
1630
1631     The mtext_from_data () function allocates a new M-text whose
1632     character sequence is specified by array $DATA of $NITEMS
1633     elements.  $FORMAT specifies the format of $DATA.
1634
1635     When $FORMAT is either #MTEXT_FORMAT_US_ASCII or
1636     #MTEXT_FORMAT_UTF_8, the contents of $DATA must be of the type @c
1637     unsigned @c char, and $NITEMS counts by byte.
1638
1639     When $FORMAT is either #MTEXT_FORMAT_UTF_16LE or
1640     #MTEXT_FORMAT_UTF_16BE, the contents of $DATA must be of the type
1641     @c unsigned @c short, and $NITEMS counts by unsigned short.
1642
1643     When $FORMAT is either #MTEXT_FORMAT_UTF_32LE or
1644     #MTEXT_FORMAT_UTF_32BE, the contents of $DATA must be of the type
1645     @c unsigned, and $NITEMS counts by unsigned.
1646
1647     The character sequence of the M-text is not modifiable.  
1648     The contents of $DATA must not be modified while the M-text is alive.
1649
1650     The allocated M-text will not be freed unless the user explicitly
1651     does so with the m17n_object_unref () function.  Even in that case,
1652     $DATA is not freed.
1653
1654     @return
1655     If the operation was successful, mtext_from_data () returns a
1656     pointer to the allocated M-text.  Otherwise it returns @c NULL and
1657     assigns an error code to the external variable #merror_code.  */
1658 /***ja
1659     @brief »ØÄê¤Î¥Ç¡¼¥¿¤ò¸µ¤Ë¿·¤·¤¤ M-text ¤ò³ä¤êÅö¤Æ¤ë.
1660
1661     ´Ø¿ô mtext_from_data () ¤Ï¡¢Í×ÁÇ¿ô $NITEMS ¤ÎÇÛÎó $DATA 
1662     ¤Ç»ØÄꤵ¤ì¤¿Ê¸»úÎó¤ò»ý¤Ä¿·¤·¤¤ M-text ¤ò³ä¤êÅö¤Æ¤ë¡£$FORMAT ¤Ï $DATA
1663     ¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤ò¼¨¤¹¡£
1664
1665     $FORMAT ¤¬ #MTEXT_FORMAT_US_ASCII ¤« #MTEXT_FORMAT_UTF_8 ¤Ê¤é¤Ð¡¢
1666     $DATA ¤ÎÆâÍƤϠ@c unsigned @c char ·¿¤Ç¤¢¤ê¡¢$NITEMS 
1667     ¤Ï¥Ð¥¤¥Èñ°Ì¤Çɽ¤µ¤ì¤Æ¤¤¤ë¡£
1668
1669     $FORMAT ¤¬ #MTEXT_FORMAT_UTF_16LE ¤« #MTEXT_FORMAT_UTF_16BE ¤Ê¤é¤Ð¡¢
1670     $DATA ¤ÎÆâÍƤϠ@c unsigned @c short ·¿¤Ç¤¢¤ê¡¢$NITEMS ¤Ï unsigned
1671     short Ã±°Ì¤Ç¤¢¤ë¡£
1672
1673     $FORMAT ¤¬ #MTEXT_FORMAT_UTF_32LE ¤« #MTEXT_FORMAT_UTF_32BE ¤Ê¤é¤Ð¡¢
1674     $DATA ¤ÎÆâÍƤϠ@c unsigned ·¿¤Ç¤¢¤ê¡¢$NITEMS ¤Ï unsigned Ã±°Ì¤Ç¤¢¤ë¡£
1675
1676     ³ä¤êÅö¤Æ¤é¤ì¤¿ M-text ¤Îʸ»úÎó¤ÏÊѹ¹¤Ç¤­¤Ê¤¤¡£$DATA ¤ÎÆâÍƤϠ
1677     M-text ¤¬Í­¸ú¤Ê´Ö¤ÏÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1678
1679     ³ä¤êÅö¤Æ¤é¤ì¤¿ M-text ¤Ï¡¢´Ø¿ô m17n_object_unref () 
1680     ¤Ë¤è¤Ã¤Æ¥æ¡¼¥¶¤¬ÌÀ¼¨Åª¤Ë¹Ô¤Ê¤ï¤Ê¤¤¸Â¤ê¡¢²òÊü¤µ¤ì¤Ê¤¤¡£¤½¤Î¾ì¹ç¤Ç¤â $DATA ¤Ï²òÊü¤µ¤ì¤Ê¤¤¡£
1681
1682     @return 
1683     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_from_data () ¤Ï³ä¤êÅö¤Æ¤é¤ì¤¿M-text 
1684     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·³°ÉôÊÑ¿ô #merror_code 
1685     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1686
1687 /***
1688     @errors
1689     @c MERROR_MTEXT  */
1690
1691 MText *
1692 mtext_from_data (const void *data, int nitems, enum MTextFormat format)
1693 {
1694   if (nitems < 0
1695       || format < MTEXT_FORMAT_US_ASCII || format >= MTEXT_FORMAT_MAX)
1696     MERROR (MERROR_MTEXT, NULL);
1697   return mtext__from_data (data, nitems, format, 0);
1698 }
1699
1700 /*=*/
1701
1702 /***en
1703     @brief Get information about the text data in M-text.
1704
1705     The mtext_data () function returns a pointer to the text data of
1706     M-text $MT.  If $FMT is not NULL, the format of the text data is
1707     stored in it.  If $NUNITS is not NULL, the number of units of the
1708     text data is stored in it.
1709
1710     If $POS_IDX is not NULL and it points to a non-negative number,
1711     what it points to is a character position.  In this case, the
1712     return value is a pointer to the text data of a character at that
1713     position.
1714
1715     Otherwise, if $UNIT_IDX is not NULL, it points to a unit position.
1716     In this case, the return value is a pointer to the text data of a
1717     character containing that unit.
1718
1719     The character position and unit position of the return value are
1720     stored in $POS_IDX and $UNIT_DIX respectively if they are not
1721     NULL.
1722
1723     <ul>
1724
1725     <li> If the format of the text data is MTEXT_FORMAT_US_ASCII or
1726     MTEXT_FORMAT_UTF_8, one unit is unsigned char.
1727
1728     <li> If the format is MTEXT_FORMAT_UTF_16LE or
1729     MTEXT_FORMAT_UTF_16BE, one unit is unsigned short.
1730
1731     <li> If the format is MTEXT_FORMAT_UTF_32LE or
1732     MTEXT_FORMAT_UTF_32BE, one unit is unsigned int.
1733
1734     </ul> */
1735
1736 void *
1737 mtext_data (MText *mt, enum MTextFormat *fmt, int *nunits,
1738             int *pos_idx, int *unit_idx)
1739 {
1740   void *data;
1741   int pos = 0, unit_pos = 0;
1742
1743   if (fmt)
1744     *fmt = mt->format;
1745   data = MTEXT_DATA (mt);
1746   if (pos_idx && *pos_idx >= 0)
1747     {
1748       pos = *pos_idx;
1749       if (pos > mtext_nchars (mt))
1750         MERROR (MERROR_MTEXT, NULL);
1751       unit_pos = POS_CHAR_TO_BYTE (mt, pos);
1752     }
1753   else if (unit_idx)
1754     {
1755       unit_pos = *unit_idx;
1756
1757       if (unit_pos < 0 || unit_pos > mtext_nbytes (mt))
1758         MERROR (MERROR_MTEXT, NULL);
1759       pos = POS_BYTE_TO_CHAR (mt, unit_pos);
1760       unit_pos = POS_CHAR_TO_BYTE (mt, pos);
1761     }
1762   if (nunits)
1763     *nunits = mtext_nbytes (mt) - unit_pos;
1764   if (pos_idx)
1765     *pos_idx = pos;
1766   if (unit_idx)
1767     *unit_idx = unit_pos;
1768   if (unit_pos > 0)
1769     {
1770       if (mt->format <= MTEXT_FORMAT_UTF_8)
1771         data = (unsigned char *) data + unit_pos;
1772       else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1773         data = (unsigned short *) data + unit_pos;
1774       else
1775         data = (unsigned int *) data + unit_pos;
1776     }
1777   return data;
1778 }
1779
1780 /*=*/
1781
1782 /***en
1783     @brief Number of characters in M-text.
1784
1785     The mtext_len () function returns the number of characters in
1786     M-text $MT.  */
1787
1788 /***ja
1789     @brief M-text Ãæ¤Îʸ»ú¤Î¿ô.
1790
1791     ´Ø¿ô mtext_len () ¤Ï M-text $MT Ãæ¤Îʸ»ú¤Î¿ô¤òÊÖ¤¹¡£
1792
1793     @latexonly \IPAlabel{mtext_len} @endlatexonly  */
1794
1795 int
1796 mtext_len (MText *mt)
1797 {
1798   return (mt->nchars);
1799 }
1800
1801 /*=*/
1802
1803 /***en
1804     @brief Return the character at the specified position in an M-text.
1805
1806     The mtext_ref_char () function returns the character at $POS in
1807     M-text $MT.  If an error is detected, it returns -1 and assigns an
1808     error code to the external variable #merror_code.  */
1809
1810 /***ja
1811     @brief M-text Ãæ¤Î»ØÄꤵ¤ì¤¿°ÌÃÖ¤Îʸ»ú¤òÊÖ¤¹.
1812
1813     ´Ø¿ô mtext_ref_char () ¤Ï¡¢M-text $MT ¤Î°ÌÃÖ $POS 
1814     ¤Îʸ»ú¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code
1815     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1816
1817     @latexonly \IPAlabel{mtext_ref_char} @endlatexonly  */
1818
1819 /***
1820     @errors
1821     @c MERROR_RANGE  */
1822
1823 int
1824 mtext_ref_char (MText *mt, int pos)
1825 {
1826   int c;
1827
1828   M_CHECK_POS (mt, pos, -1);
1829   if (mt->format <= MTEXT_FORMAT_UTF_8)
1830     {
1831       unsigned char *p = mt->data + POS_CHAR_TO_BYTE (mt, pos);
1832
1833       c = STRING_CHAR_UTF8 (p);
1834     }
1835   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1836     {
1837       unsigned short *p
1838         = (unsigned short *) (mt->data) + POS_CHAR_TO_BYTE (mt, pos);
1839       unsigned short p1[2];
1840
1841       if (mt->format != MTEXT_FORMAT_UTF_16)
1842         {
1843           p1[0] = SWAP_16 (*p);
1844           if (p1[0] >= 0xD800 || p1[0] < 0xDC00)
1845             p1[1] = SWAP_16 (p[1]);
1846           p = p1;
1847         }
1848       c = STRING_CHAR_UTF16 (p);
1849     }
1850   else
1851     {
1852       c = ((unsigned *) (mt->data))[pos];
1853       if (mt->format != MTEXT_FORMAT_UTF_32)
1854         c = SWAP_32 (c);
1855     }
1856   return c;
1857 }
1858
1859 /*=*/
1860
1861 /***en
1862     @brief Store a character into an M-text.
1863
1864     The mtext_set_char () function sets character $C, which has no
1865     text properties, at $POS in M-text $MT.
1866
1867     @return
1868     If the operation was successful, mtext_set_char () returns 0.
1869     Otherwise it returns -1 and assigns an error code to the external
1870     variable #merror_code.  */
1871
1872 /***ja
1873     @brief M-text ¤Ë°ìʸ»ú¤òÀßÄꤹ¤ë.
1874
1875     ´Ø¿ô mtext_set_char () ¤Ï¡¢¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£Ìµ¤·¤Îʸ»ú $C ¤ò 
1876     M-text $MT ¤Î°ÌÃÖ $POS ¤ËÀßÄꤹ¤ë¡£
1877
1878     @return
1879     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mtext_set_char () ¤Ï 0 ¤òÊÖ¤¹¡£¼ºÇÔ¤¹¤ì¤Ð -1 
1880     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1881
1882     @latexonly \IPAlabel{mtext_set_char} @endlatexonly  */
1883
1884 /***
1885     @errors
1886     @c MERROR_RANGE */
1887
1888 int
1889 mtext_set_char (MText *mt, int pos, int c)
1890 {
1891   int pos_unit;
1892   int old_units, new_units;
1893   int delta;
1894   unsigned char *p;
1895   int unit_bytes;
1896
1897   M_CHECK_POS (mt, pos, -1);
1898   M_CHECK_READONLY (mt, -1);
1899
1900   mtext__adjust_plist_for_change (mt, pos, 1, 1);
1901
1902   if (mt->format <= MTEXT_FORMAT_UTF_8)
1903     {
1904       if (c >= 0x80)
1905         mt->format = MTEXT_FORMAT_UTF_8, mt->coverage = MTEXT_COVERAGE_FULL;
1906     }
1907   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1908     {
1909       if (c >= 0x110000)
1910         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
1911       else if (mt->format != MTEXT_FORMAT_UTF_16)
1912         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_16);
1913     }
1914   else if (mt->format != MTEXT_FORMAT_UTF_32)
1915     mtext__adjust_format (mt, MTEXT_FORMAT_UTF_32);
1916
1917   unit_bytes = UNIT_BYTES (mt->format);
1918   pos_unit = POS_CHAR_TO_BYTE (mt, pos);
1919   p = mt->data + pos_unit * unit_bytes;
1920   old_units = CHAR_UNITS_AT (mt, p);
1921   new_units = CHAR_UNITS (c, mt->format);
1922   delta = new_units - old_units;
1923
1924   if (delta)
1925     {
1926       if (mt->cache_char_pos > pos)
1927         mt->cache_byte_pos += delta;
1928
1929       if ((mt->nbytes + delta + 1) * unit_bytes > mt->allocated)
1930         {
1931           mt->allocated = (mt->nbytes + delta + 1) * unit_bytes;
1932           MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
1933         }
1934
1935       memmove (mt->data + (pos_unit + new_units) * unit_bytes, 
1936                mt->data + (pos_unit + old_units) * unit_bytes,
1937                (mt->nbytes - pos_unit - old_units + 1) * unit_bytes);
1938       mt->nbytes += delta;
1939       mt->data[mt->nbytes * unit_bytes] = 0;
1940     }
1941   switch (mt->format)
1942     {
1943     case MTEXT_FORMAT_US_ASCII:
1944       mt->data[pos_unit] = c;
1945       break;
1946     case MTEXT_FORMAT_UTF_8:
1947       {
1948         unsigned char *p = mt->data + pos_unit;
1949         CHAR_STRING_UTF8 (c, p);
1950         break;
1951       }
1952     default:
1953       if (mt->format == MTEXT_FORMAT_UTF_16)
1954         {
1955           unsigned short *p = (unsigned short *) mt->data + pos_unit;
1956
1957           CHAR_STRING_UTF16 (c, p);
1958         }
1959       else
1960         ((unsigned *) mt->data)[pos_unit] = c;
1961     }
1962   return 0;
1963 }
1964
1965 /*=*/
1966
1967 /***en
1968     @brief  Append a character to an M-text.
1969
1970     The mtext_cat_char () function appends character $C, which has no
1971     text properties, to the end of M-text $MT.
1972
1973     @return
1974     This function returns a pointer to the resulting M-text $MT.  If
1975     $C is an invalid character, it returns @c NULL.  */
1976
1977 /***ja
1978     @brief M-text ¤Ë°ìʸ»úÄɲ乤ë.
1979
1980     ´Ø¿ô mtext_cat_char () ¤Ï¡¢¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£Ìµ¤·¤Îʸ»ú $C ¤ò 
1981     M-text $MT ¤ÎËöÈø¤ËÄɲ乤롣
1982
1983     @return
1984     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$C 
1985     ¤¬Àµ¤·¤¤Ê¸»ú¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï @c NULL ¤òÊÖ¤¹¡£  */
1986
1987 /***
1988     @seealso
1989     mtext_cat (), mtext_ncat ()  */
1990
1991 MText *
1992 mtext_cat_char (MText *mt, int c)
1993 {
1994   int nunits;
1995   int unit_bytes = UNIT_BYTES (mt->format);
1996
1997   M_CHECK_READONLY (mt, NULL);
1998   if (c < 0 || c > MCHAR_MAX)
1999     return NULL;
2000   mtext__adjust_plist_for_insert (mt, mt->nchars, 1, NULL);
2001
2002   if (c >= 0x80
2003       && (mt->format == MTEXT_FORMAT_US_ASCII
2004           || (c >= 0x10000
2005               && (mt->format == MTEXT_FORMAT_UTF_16LE
2006                   || mt->format == MTEXT_FORMAT_UTF_16BE))))
2007
2008     {
2009       mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
2010       unit_bytes = 1;
2011     }
2012   else if (mt->format >= MTEXT_FORMAT_UTF_32LE)
2013     {
2014       if (mt->format != MTEXT_FORMAT_UTF_32)
2015         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_32);
2016     }
2017   else if (mt->format >= MTEXT_FORMAT_UTF_16LE)
2018     {
2019       if (mt->format != MTEXT_FORMAT_UTF_16)
2020         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_16);
2021     }
2022
2023   nunits = CHAR_UNITS (c, mt->format);
2024   if ((mt->nbytes + nunits + 1) * unit_bytes > mt->allocated)
2025     {
2026       mt->allocated = (mt->nbytes + nunits * 16 + 1) * unit_bytes;
2027       MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
2028     }
2029   
2030   if (mt->format <= MTEXT_FORMAT_UTF_8)
2031     {
2032       unsigned char *p = mt->data + mt->nbytes;
2033       p += CHAR_STRING_UTF8 (c, p);
2034       *p = 0;
2035     }
2036   else if (mt->format == MTEXT_FORMAT_UTF_16)
2037     {
2038       unsigned short *p = (unsigned short *) mt->data + mt->nbytes;
2039       p += CHAR_STRING_UTF16 (c, p);
2040       *p = 0;
2041     }
2042   else
2043     {
2044       unsigned *p = (unsigned *) mt->data + mt->nbytes;
2045       *p++ = c;
2046       *p = 0;
2047     }
2048
2049   mt->nchars++;
2050   mt->nbytes += nunits;
2051   return mt;
2052 }
2053
2054 /*=*/
2055
2056 /***en
2057     @brief  Create a copy of an M-text.
2058
2059     The mtext_dup () function creates a copy of M-text $MT while
2060     inheriting all the text properties of $MT.
2061
2062     @return
2063     This function returns a pointer to the created copy.  */
2064
2065 /***ja
2066     @brief M-text ¤Î¥³¥Ô¡¼¤òºî¤ë.
2067
2068     ´Ø¿ô mtext_dup () ¤Ï¡¢M-text $MT ¤Î¥³¥Ô¡¼¤òºî¤ë¡£$MT 
2069     ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£
2070
2071     @return
2072     ¤³¤Î´Ø¿ô¤Ïºî¤é¤ì¤¿¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
2073
2074      @latexonly \IPAlabel{mtext_dup} @endlatexonly  */
2075
2076 /***
2077     @seealso
2078     mtext_duplicate ()  */
2079
2080 MText *
2081 mtext_dup (MText *mt)
2082 {
2083   return mtext_duplicate (mt, 0, mtext_nchars (mt));
2084 }
2085
2086 /*=*/
2087
2088 /***en
2089     @brief  Append an M-text to another.
2090
2091     The mtext_cat () function appends M-text $MT2 to the end of M-text
2092     $MT1 while inheriting all the text properties.  $MT2 itself is not
2093     modified.
2094
2095     @return
2096     This function returns a pointer to the resulting M-text $MT1.  */
2097
2098 /***ja
2099     @brief 2¸Ä¤Î M-text¤òÏ¢·ë¤¹¤ë.
2100
2101     ´Ø¿ô mtext_cat () ¤Ï¡¢ M-text $MT2 ¤ò M-text $MT1 
2102     ¤ÎËöÈø¤ËÉÕ¤±²Ã¤¨¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
2103
2104     @return
2105     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
2106
2107     @latexonly \IPAlabel{mtext_cat} @endlatexonly  */
2108
2109 /***
2110     @seealso
2111     mtext_ncat (), mtext_cat_char ()  */
2112
2113 MText *
2114 mtext_cat (MText *mt1, MText *mt2)
2115 {
2116   M_CHECK_READONLY (mt1, NULL);
2117
2118   if (mt2->nchars > 0)
2119     insert (mt1, mt1->nchars, mt2, 0, mt2->nchars);
2120   return mt1;
2121 }
2122
2123
2124 /*=*/
2125
2126 /***en
2127     @brief Append a part of an M-text to another.
2128
2129     The mtext_ncat () function appends the first $N characters of
2130     M-text $MT2 to the end of M-text $MT1 while inheriting all the
2131     text properties.  If the length of $MT2 is less than $N, all
2132     characters are copied.  $MT2 is not modified.  
2133
2134     @return 
2135     If the operation was successful, mtext_ncat () returns a
2136     pointer to the resulting M-text $MT1.  If an error is detected, it
2137     returns @c NULL and assigns an error code to the global variable
2138     #merror_code.  */
2139
2140 /***ja
2141     @brief M-text ¤Î°ìÉô¤òÊ̤ΠM-text ¤ËÉղ乤ë.
2142
2143     ´Ø¿ô mtext_ncat () ¤Ï¡¢M-text $MT2 ¤Î¤Ï¤¸¤á¤Î $N Ê¸»ú¤ò M-text
2144     $MT1 ¤ÎËöÈø¤ËÉÕ¤±²Ã¤¨¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT2
2145     ¤ÎŤµ¤¬ $N °Ê²¼¤Ê¤é¤Ð¡¢$MT2 ¤Î¤¹¤Ù¤Æ¤Îʸ»ú¤¬Éղ䵤ì¤ë¡£ $MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
2146
2147     @return
2148     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_ncat () ¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1
2149     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô
2150     #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2151
2152     @latexonly \IPAlabel{mtext_ncat} @endlatexonly  */
2153
2154 /***
2155     @errors
2156     @c MERROR_RANGE
2157
2158     @seealso
2159     mtext_cat (), mtext_cat_char ()  */
2160
2161 MText *
2162 mtext_ncat (MText *mt1, MText *mt2, int n)
2163 {
2164   M_CHECK_READONLY (mt1, NULL);
2165   if (n < 0)
2166     MERROR (MERROR_RANGE, NULL);
2167   if (mt2->nchars > 0)
2168     insert (mt1, mt1->nchars, mt2, 0, mt2->nchars < n ? mt2->nchars : n);
2169   return mt1;
2170 }
2171
2172
2173 /*=*/
2174
2175 /***en
2176     @brief Copy an M-text to another.
2177
2178     The mtext_cpy () function copies M-text $MT2 to M-text $MT1 while
2179     inheriting all the text properties.  The old text in $MT1 is
2180     overwritten and the length of $MT1 is extended if necessary.  $MT2
2181     is not modified.
2182
2183     @return
2184     This function returns a pointer to the resulting M-text $MT1.  */
2185
2186 /***ja
2187     @brief M-text ¤òÊ̤ΠM-text ¤Ë¥³¥Ô¡¼¤¹¤ë.
2188
2189     ´Ø¿ô mtext_cpy () ¤Ï M-text $MT2 ¤ò M-text $MT1 ¤Ë¾å½ñ¤­¥³¥Ô¡¼¤¹¤ë¡£
2190     $MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT1 
2191     ¤ÎŤµ¤ÏɬÍפ˱þ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
2192
2193     @return
2194     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
2195
2196     @latexonly \IPAlabel{mtext_cpy} @endlatexonly  */
2197
2198 /***
2199     @seealso
2200     mtext_ncpy (), mtext_copy ()  */
2201
2202 MText *
2203 mtext_cpy (MText *mt1, MText *mt2)
2204 {
2205   M_CHECK_READONLY (mt1, NULL);
2206   mtext_del (mt1, 0, mt1->nchars);
2207   if (mt2->nchars > 0)
2208     insert (mt1, 0, mt2, 0, mt2->nchars);
2209   return mt1;
2210 }
2211
2212 /*=*/
2213
2214 /***en
2215     @brief Copy the first some characters in an M-text to another.
2216
2217     The mtext_ncpy () function copies the first $N characters of
2218     M-text $MT2 to M-text $MT1 while inheriting all the text
2219     properties.  If the length of $MT2 is less than $N, all characters
2220     of $MT2 are copied.  The old text in $MT1 is overwritten and the
2221     length of $MT1 is extended if necessary.  $MT2 is not modified.
2222
2223     @return
2224     If the operation was successful, mtext_ncpy () returns a pointer
2225     to the resulting M-text $MT1.  If an error is detected, it returns
2226     @c NULL and assigns an error code to the global variable 
2227     #merror_code.  */
2228
2229 /***ja
2230     @brief M-text ¤Ë´Þ¤Þ¤ì¤ëºÇ½é¤Î²¿Ê¸»ú¤«¤ò¥³¥Ô¡¼¤¹¤ë.
2231
2232     ´Ø¿ô mtext_ncpy () ¤Ï¡¢M-text $MT2 ¤ÎºÇ½é¤Î $N Ê¸»ú¤ò M-text $MT1 
2233     ¤Ë¾å½ñ¤­¥³¥Ô¡¼¤¹¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£¤â¤· $MT2
2234     ¤ÎŤµ¤¬ $N ¤è¤ê¤â¾®¤µ¤±¤ì¤Ð $MT2 ¤Î¤¹¤Ù¤Æ¤Îʸ»ú¤ò¥³¥Ô¡¼¤¹¤ë¡£$MT1 
2235     ¤ÎŤµ¤ÏɬÍפ˱þ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
2236
2237     @return 
2238     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_ncpy () ¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 
2239     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô 
2240     #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2241
2242     @latexonly \IPAlabel{mtext_ncpy} @endlatexonly  */
2243
2244 /***
2245     @errors
2246     @c MERROR_RANGE
2247
2248     @seealso
2249     mtext_cpy (), mtext_copy ()  */
2250
2251 MText *
2252 mtext_ncpy (MText *mt1, MText *mt2, int n)
2253 {
2254   M_CHECK_READONLY (mt1, NULL);
2255   if (n < 0)
2256     MERROR (MERROR_RANGE, NULL);
2257   mtext_del (mt1, 0, mt1->nchars);
2258   if (mt2->nchars > 0)
2259     insert (mt1, 0, mt2, 0, mt2->nchars < n ? mt2->nchars : n);
2260   return mt1;
2261 }
2262
2263 /*=*/
2264
2265 /***en
2266     @brief Create a new M-text from a part of an existing M-text.
2267
2268     The mtext_duplicate () function creates a copy of sub-text of
2269     M-text $MT, starting at $FROM (inclusive) and ending at $TO
2270     (exclusive) while inheriting all the text properties of $MT.  $MT
2271     itself is not modified.
2272
2273     @return 
2274     If the operation was successful, mtext_duplicate ()
2275     returns a pointer to the created M-text.  If an error is detected,
2276     it returns NULL and assigns an error code to the external variable
2277     #merror_code.  */
2278
2279 /***ja
2280     @brief ´û¸¤Î M-text ¤Î°ìÉô¤«¤é¿·¤·¤¤ M-text ¤ò¤Ä¤¯¤ë.
2281
2282     ´Ø¿ô mtext_duplicate () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê$FROM ¼«ÂΤâ´Þ¤à¡Ë¤«¤é
2283     $TO ¡Ê$TO ¼«ÂΤϴޤޤʤ¤¡Ë¤Þ¤Ç¤ÎÉôʬ¤Î¥³¥Ô¡¼¤òºî¤ë¡£¤³¤Î¤È¤­ $MT 
2284     ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT ¤½¤Î¤â¤Î¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
2285
2286     @return
2287     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_duplicate () ¤Ïºî¤é¤ì¤¿ M-text 
2288     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô 
2289     #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2290
2291     @latexonly \IPAlabel{mtext_duplicate} @endlatexonly  */
2292
2293 /***
2294     @errors
2295     @c MERROR_RANGE
2296
2297     @seealso
2298     mtext_dup ()  */
2299
2300 MText *
2301 mtext_duplicate (MText *mt, int from, int to)
2302 {
2303   MText *new = mtext ();
2304
2305   M_CHECK_RANGE (mt, from, to, NULL, new);
2306   new->format = mt->format;
2307   new->coverage = mt->coverage;
2308   insert (new, 0, mt, from, to);
2309   return new;
2310 }
2311
2312 /*=*/
2313
2314 /***en
2315     @brief Copy characters in the specified range into an M-text.
2316
2317     The mtext_copy () function copies the text between $FROM
2318     (inclusive) and $TO (exclusive) in M-text $MT2 to the region
2319     starting at $POS in M-text $MT1 while inheriting the text
2320     properties.  The old text in $MT1 is overwritten and the length of
2321     $MT1 is extended if necessary.  $MT2 is not modified.
2322
2323     @return
2324     If the operation was successful, mtext_copy () returns a pointer
2325     to the modified $MT1.  Otherwise, it returns @c NULL and assigns
2326     an error code to the external variable #merror_code.  */
2327
2328 /***ja
2329     @brief M-text ¤Ë»ØÄêÈϰϤÎʸ»ú¤ò¥³¥Ô¡¼¤¹¤ë.
2330
2331     ´Ø¿ô mtext_copy () ¤Ï¡¢ M-text $MT2 ¤Î $FROM ¡Ê$FROM ¼«ÂΤâ´Þ¤à¡Ë¤«¤é 
2332     $TO ¡Ê$TO ¼«ÂΤϴޤޤʤ¤¡Ë¤Þ¤Ç¤ÎÈϰϤΥƥ­¥¹¥È¤ò M-text $MT1 ¤Î°ÌÃÖ $POS
2333     ¤«¤é¾å½ñ¤­¥³¥Ô¡¼¤¹¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT1 
2334     ¤ÎŤµ¤ÏɬÍפ˱þ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
2335
2336     @latexonly \IPAlabel{mtext_copy} @endlatexonly
2337
2338     @return
2339     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_copy () ¤ÏÊѹ¹¤µ¤ì¤¿ $MT1 
2340     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code 
2341     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
2342
2343 /***
2344     @errors
2345     @c MERROR_RANGE
2346
2347     @seealso
2348     mtext_cpy (), mtext_ncpy ()  */
2349
2350 MText *
2351 mtext_copy (MText *mt1, int pos, MText *mt2, int from, int to)
2352 {
2353   M_CHECK_POS_X (mt1, pos, NULL);
2354   M_CHECK_READONLY (mt1, NULL);
2355   M_CHECK_RANGE_X (mt2, from, to, NULL);
2356   mtext_del (mt1, pos, mt1->nchars);
2357   return insert (mt1, pos, mt2, from, to);
2358 }
2359
2360 /*=*/
2361
2362
2363 /***en
2364     @brief Delete characters in the specified range destructively.
2365
2366     The mtext_del () function deletes the characters in the range
2367     $FROM (inclusive) and $TO (exclusive) from M-text $MT
2368     destructively.  As a result, the length of $MT shrinks by ($TO -
2369     $FROM) characters.
2370
2371     @return
2372     If the operation was successful, mtext_del () returns 0.
2373     Otherwise, it returns -1 and assigns an error code to the external
2374     variable #merror_code.  */
2375
2376 /***ja
2377     @brief »ØÄêÈϰϤÎʸ»ú¤òÇ˲õŪ¤Ë¼è¤ê½ü¤¯.
2378
2379     ´Ø¿ô mtext_del () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê$FROM ¼«ÂΤâ´Þ¤à¡Ë¤«¤é
2380     $TO ¡Ê$TO ¼«ÂΤϴޤޤʤ¤¡Ë¤Þ¤Ç¤Îʸ»ú¤òÇ˲õŪ¤Ë¼è¤ê½ü¤¯¡£·ë²ÌŪ¤Ë
2381     $MT ¤ÏŤµ¤¬ ($TO @c - $FROM) ¤À¤±½Ì¤à¤³¤È¤Ë¤Ê¤ë¡£
2382
2383     @return
2384     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_del () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 
2385     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
2386
2387 /***
2388     @errors
2389     @c MERROR_RANGE
2390
2391     @seealso
2392     mtext_ins ()  */
2393
2394 int
2395 mtext_del (MText *mt, int from, int to)
2396 {
2397   int from_byte, to_byte;
2398   int unit_bytes = UNIT_BYTES (mt->format);
2399
2400   M_CHECK_READONLY (mt, -1);
2401   M_CHECK_RANGE (mt, from, to, -1, 0);
2402
2403   from_byte = POS_CHAR_TO_BYTE (mt, from);
2404   to_byte = POS_CHAR_TO_BYTE (mt, to);
2405
2406   if (mt->cache_char_pos >= to)
2407     {
2408       mt->cache_char_pos -= to - from;
2409       mt->cache_byte_pos -= to_byte - from_byte;
2410     }
2411   else if (mt->cache_char_pos > from)
2412     {
2413       mt->cache_char_pos -= from;
2414       mt->cache_byte_pos -= from_byte;
2415     }
2416
2417   mtext__adjust_plist_for_delete (mt, from, to - from);
2418   memmove (mt->data + from_byte * unit_bytes, 
2419            mt->data + to_byte * unit_bytes,
2420            (mt->nbytes - to_byte + 1) * unit_bytes);
2421   mt->nchars -= (to - from);
2422   mt->nbytes -= (to_byte - from_byte);
2423   mt->cache_char_pos = from;
2424   mt->cache_byte_pos = from_byte;
2425   return 0;
2426 }
2427
2428
2429 /*=*/
2430
2431 /***en
2432     @brief Insert an M-text into another M-text.
2433
2434     The mtext_ins () function inserts M-text $MT2 into M-text $MT1, at
2435     position $POS.  As a result, $MT1 is lengthen by the length of
2436     $MT2.  On insertion, all the text properties of $MT2 are
2437     inherited.  The original $MT2 is not modified.
2438
2439     @return
2440     If the operation was successful, mtext_ins () returns 0.
2441     Otherwise, it returns -1 and assigns an error code to the external
2442     variable #merror_code.  */
2443
2444 /***ja
2445     @brief M-text ¤òÊ̤ΠM-text ¤ËÁÞÆþ¤¹¤ë.
2446
2447     ´Ø¿ô mtext_ins () ¤Ï M-text $MT1 ¤Î $POS ¤Î°ÌÃÖ¤ËÊ̤ΠM-text $MT2 
2448     ¤òÁÞÆþ¤¹¤ë¡£¤³¤Î·ë²Ì $MT1 ¤ÎŤµ¤Ï $MT2 ¤ÎŤµÊ¬¤À¤±Áý¤¨¤ë¡£ÁÞÆþ¤ÎºÝ¡¢$MT2
2449     ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT2 ¤½¤Î¤â¤Î¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
2450
2451     @return
2452     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_ins () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 
2453     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
2454
2455 /***
2456     @errors
2457     @c MERROR_RANGE , @c MERROR_MTEXT
2458
2459     @seealso
2460     mtext_del () , mtext_insert ()  */
2461
2462 int
2463 mtext_ins (MText *mt1, int pos, MText *mt2)
2464 {
2465   M_CHECK_READONLY (mt1, -1);
2466   M_CHECK_POS_X (mt1, pos, -1);
2467
2468   if (mt2->nchars == 0)
2469     return 0;
2470   insert (mt1, pos, mt2, 0, mt2->nchars);
2471   return 0;
2472 }
2473
2474 /*=*/
2475
2476 /***en
2477     @brief Insert sub-text of an M-text into another M-text.
2478
2479     The mtext_insert () function inserts sub-text of M-text $MT2
2480     between $FROM (inclusive) and $TO (exclusive) into M-text $MT1, at
2481     position $POS.  As a result, $MT1 is lengthen by ($TO - $FROM).
2482     On insertion, all the text properties of the sub-text of $MT2 are
2483     inherited.
2484
2485     @return 
2486     If the operation was successful, mtext_insert () returns
2487     0.  Otherwise, it returns -1 and assigns an error code to the
2488     external variable #merror_code.  */
2489
2490 /***ja
2491     @brief M-text ¤Î°ìÉô¤òÊ̤ΠM-text ¤ËÁÞÆþ¤¹¤ë.
2492
2493     ´Ø¿ô mtext_insert () ¤Ï M-text $MT1 Ãæ¤Î $POS ¤Î°ÌÃ֤ˡ¢Ê̤Π
2494     M-text $MT2 ¤Î $FROM ¡Ê$FROM ¼«ÂΤâ´Þ¤à¡Ë¤«¤é $TO ¡Ê$TO ¼«ÂΤϴޤÞ
2495     ¤Ê¤¤¡Ë¤Þ¤Ç¤Îʸ»ú¤òÁÞÆþ¤¹¤ë¡£·ë²ÌŪ¤Ë $MT1 ¤ÏŤµ¤¬ ($TO - $FROM) 
2496     ¤À¤±¿­¤Ó¤ë¡£ÁÞÆþ¤ÎºÝ¡¢ $MT2 Ãæ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì
2497     ¤ë¡£
2498
2499     @return
2500     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_insert () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 
2501     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
2502
2503 /***
2504     @errors
2505     @c MERROR_MTEXT , @c MERROR_RANGE
2506
2507     @seealso
2508     mtext_ins ()  */
2509
2510 int
2511 mtext_insert (MText *mt1, int pos, MText *mt2, int from, int to)
2512 {
2513   M_CHECK_READONLY (mt1, -1);
2514   M_CHECK_POS_X (mt1, pos, -1);
2515   M_CHECK_RANGE (mt2, from, to, -1, 0);
2516
2517   insert (mt1, pos, mt2, from, to);
2518   return 0;
2519 }
2520
2521 /*=*/
2522
2523 /***en
2524     @brief Insert a character into an M-text.
2525
2526     The mtext_ins_char () function inserts $N copies of character $C
2527     into M-text $MT at position $POS.  As a result, $MT is lengthen by
2528     $N.
2529
2530     @return
2531     If the operation was successful, mtext_ins () returns 0.
2532     Otherwise, it returns -1 and assigns an error code to the external
2533     variable #merror_code.  */
2534
2535 /***ja
2536     @brief M-text ¤Ëʸ»ú¤òÁÞÆþ¤¹¤ë.
2537
2538     ´Ø¿ô mtext_ins_char () ¤Ï M-text $MT ¤Î $POS ¤Î°ÌÃÖ¤Ëʸ»ú $C ¤Î¥³¥Ô¡¼¤ò $N
2539     ¸ÄÁÞÆþ¤¹¤ë¡£¤³¤Î·ë²Ì $MT1 ¤ÎŤµ¤Ï $N ¤À¤±Áý¤¨¤ë¡£
2540
2541     @return
2542     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_ins_char () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1
2543     ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
2544
2545 /***
2546     @errors
2547     @c MERROR_RANGE
2548
2549     @seealso
2550     mtext_ins, mtext_del ()  */
2551
2552 int
2553 mtext_ins_char (MText *mt, int pos, int c, int n)
2554 {
2555   int nunits;
2556   int unit_bytes = UNIT_BYTES (mt->format);
2557   int pos_unit;
2558   int i;
2559
2560   M_CHECK_READONLY (mt, -1);
2561   M_CHECK_POS_X (mt, pos, -1);
2562   if (c < 0 || c > MCHAR_MAX)
2563     MERROR (MERROR_MTEXT, -1);
2564   if (n <= 0)
2565     return 0;
2566   mtext__adjust_plist_for_insert (mt, pos, n, NULL);
2567
2568   if (c >= 0x80
2569       && (mt->format == MTEXT_FORMAT_US_ASCII
2570           || (c >= 0x10000 && (mt->format == MTEXT_FORMAT_UTF_16LE
2571                                || mt->format == MTEXT_FORMAT_UTF_16BE))))
2572     {
2573       mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
2574       unit_bytes = 1;
2575     }
2576   else if (mt->format >= MTEXT_FORMAT_UTF_32LE)
2577     {
2578       if (mt->format != MTEXT_FORMAT_UTF_32)
2579         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_32);
2580     }
2581   else if (mt->format >= MTEXT_FORMAT_UTF_16LE)
2582     {
2583       if (mt->format != MTEXT_FORMAT_UTF_16)
2584         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_16);
2585     }
2586
2587   nunits = CHAR_UNITS (c, mt->format);
2588   if ((mt->nbytes + nunits * n + 1) * unit_bytes > mt->allocated)
2589     {
2590       mt->allocated = (mt->nbytes + nunits * n + 1) * unit_bytes;
2591       MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
2592     }
2593   pos_unit = POS_CHAR_TO_BYTE (mt, pos);
2594   if (mt->cache_char_pos > pos)
2595     {
2596       mt->cache_char_pos += n;
2597       mt->cache_byte_pos += nunits * n;
2598     }
2599   memmove (mt->data + (pos_unit + nunits * n) * unit_bytes,
2600            mt->data + pos_unit * unit_bytes,
2601            (mt->nbytes - pos_unit + 1) * unit_bytes);
2602   if (mt->format <= MTEXT_FORMAT_UTF_8)
2603     {
2604       unsigned char *p = mt->data + pos_unit;
2605
2606       for (i = 0; i < n; i++)
2607         p += CHAR_STRING_UTF8 (c, p);
2608     }
2609   else if (mt->format == MTEXT_FORMAT_UTF_16)
2610     {
2611       unsigned short *p = (unsigned short *) mt->data + pos_unit;
2612
2613       for (i = 0; i < n; i++)
2614         p += CHAR_STRING_UTF16 (c, p);
2615     }
2616   else
2617     {
2618       unsigned *p = (unsigned *) mt->data + pos_unit;
2619
2620       for (i = 0; i < n; i++)
2621         *p++ = c;
2622     }
2623   mt->nchars += n;
2624   mt->nbytes += nunits * n;
2625   return 0;
2626 }
2627
2628 /*=*/
2629
2630 /***en
2631     @brief Replace sub-text of M-text with another.
2632
2633     The mtext_replace () function replaces sub-text of M-text $MT1
2634     between $FROM1 (inclusive) and $TO1 (exclusive) with the sub-text
2635     of M-text $MT2 between $FROM2 (inclusive) and $TO2 (exclusive).
2636     The new sub-text inherits text properties of the old sub-text.
2637
2638     @return 
2639     If the operation was successful, mtext_replace () returns
2640     0.  Otherwise, it returns -1 and assigns an error code to the
2641     external variable #merror_code.  */
2642
2643 /***ja
2644     @brief M-text ¤Î°ìÉô¤òÊ̤ΠM-text ¤Î°ìÉô¤ÇÃÖ´¹¤¹¤ë.
2645
2646     ´Ø¿ô mtext_replace () ¤Ï¡¢ M-text $MT1 ¤Î $FROM1 ¡Ê$FROM1 ¼«ÂΤâ´Þ
2647     ¤à¡Ë¤«¤é $TO1 ¡Ê$TO1 ¼«ÂΤϴޤޤʤ¤¡Ë¤Þ¤Ç¤ò¡¢ M-text $MT2 ¤Î 
2648     $FROM2 ¡Ê$FROM2 ¼«ÂΤâ´Þ¤à¡Ë¤«¤é $TO2 ¡Ê$TO2 ¼«ÂΤϴޤޤʤ¤¡Ë¤ÇÃÖ
2649     ¤­´¹¤¨¤ë¡£¿·¤·¤¯ÁÞÆþ¤µ¤ì¤¿Éôʬ¤Ï¡¢ÃÖ¤­´¹¤¨¤ëÁ°¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£
2650     ¤¹¤Ù¤Æ¤ò·Ñ¾µ¤¹¤ë¡£
2651
2652     @return 
2653     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢ mtext_replace () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê
2654     ¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
2655
2656 /***
2657     @errors
2658     @c MERROR_MTEXT , @c MERROR_RANGE
2659
2660     @seealso
2661     mtext_insert ()  */
2662
2663 int
2664 mtext_replace (MText *mt1, int from1, int to1,
2665                MText *mt2, int from2, int to2)
2666 {
2667   int len1, len2;
2668   int from1_byte, from2_byte, old_bytes, new_bytes;
2669   int unit_bytes, total_bytes;
2670   unsigned char *p;
2671   int free_mt2 = 0;
2672
2673   M_CHECK_READONLY (mt1, -1);
2674   M_CHECK_RANGE_X (mt1, from1, to1, -1);
2675   M_CHECK_RANGE_X (mt2, from2, to2, -1);
2676
2677   if (from1 == to1)
2678     {
2679       struct MTextPlist *saved = mt2->plist;
2680
2681       mt2->plist = NULL;
2682       insert (mt1, from1, mt2, from2, to2);
2683       mt2->plist = saved;
2684       return 0;
2685     }
2686
2687   if (from2 == to2)
2688     {
2689       return mtext_del (mt1, from1, to1);
2690     }
2691
2692   if (mt1 == mt2)
2693     {
2694       mt2 = mtext_duplicate (mt2, from2, to2);
2695       to2 -= from2;
2696       from2 = 0;
2697       free_mt2 = 1;
2698     }
2699
2700   if (mt1->format != mt2->format
2701       && mt1->format == MTEXT_FORMAT_US_ASCII)
2702     mt1->format = MTEXT_FORMAT_UTF_8;
2703   if (mt1->format != mt2->format
2704       && mt1->coverage < mt2->coverage)
2705     mtext__adjust_format (mt1, mt2->format);
2706   if (mt1->format != mt2->format)
2707     {
2708       mt2 = mtext_duplicate (mt2, from2, to2);
2709       mtext__adjust_format (mt2, mt1->format);
2710       to2 -= from2;
2711       from2 = 0;
2712       free_mt2 = 1;
2713     }
2714
2715   len1 = to1 - from1;
2716   len2 = to2 - from2;
2717   mtext__adjust_plist_for_change (mt1, from1, len1, len2);
2718
2719   unit_bytes = UNIT_BYTES (mt1->format);
2720   from1_byte = POS_CHAR_TO_BYTE (mt1, from1) * unit_bytes;
2721   from2_byte = POS_CHAR_TO_BYTE (mt2, from2) * unit_bytes;
2722   old_bytes = POS_CHAR_TO_BYTE (mt1, to1) * unit_bytes - from1_byte;
2723   new_bytes = POS_CHAR_TO_BYTE (mt2, to2) * unit_bytes - from2_byte;
2724   total_bytes = mt1->nbytes * unit_bytes + (new_bytes - old_bytes);
2725   if (total_bytes + unit_bytes > mt1->allocated)
2726     {
2727       mt1->allocated = total_bytes + unit_bytes;
2728       MTABLE_REALLOC (mt1->data, mt1->allocated, MERROR_MTEXT);
2729     }
2730   p = mt1->data + from1_byte;
2731   if (to1 < mt1->nchars
2732       && old_bytes != new_bytes)
2733     memmove (p + new_bytes, p + old_bytes,
2734              (mt1->nbytes + 1) * unit_bytes - (from1_byte + old_bytes));
2735   memcpy (p, mt2->data + from2_byte, new_bytes);
2736   mt1->nchars += len2 - len1;
2737   mt1->nbytes += (new_bytes - old_bytes) / unit_bytes;
2738   if (mt1->cache_char_pos >= to1)
2739     {
2740       mt1->cache_char_pos += len2 - len1;
2741       mt1->cache_byte_pos += new_bytes - old_bytes;
2742     }
2743   else if (mt1->cache_char_pos > from1)
2744     {
2745       mt1->cache_char_pos = from1;
2746       mt1->cache_byte_pos = from1_byte;
2747     }
2748
2749   if (free_mt2)
2750     M17N_OBJECT_UNREF (mt2);
2751   return 0;
2752 }
2753
2754 /*=*/
2755
2756 /***en
2757     @brief Search a character in an M-text.
2758
2759     The mtext_character () function searches M-text $MT for character
2760     $C.  If $FROM is less than $TO, the search begins at position $FROM
2761     and goes forward but does not exceed ($TO - 1).  Otherwise, the search
2762     begins at position ($FROM - 1) and goes backward but does not
2763     exceed $TO.  An invalid position specification is regarded as both
2764     $FROM and $TO being 0.
2765
2766     @return
2767     If $C is found, mtext_character () returns the position of its
2768     first occurrence.  Otherwise it returns -1 without changing the
2769     external variable #merror_code.  If an error is detected, it returns -1 and
2770     assigns an error code to the external variable #merror_code.  */
2771
2772 /***ja
2773     @brief M-text Ãæ¤Çʸ»ú¤òõ¤¹.
2774
2775     ´Ø¿ô mtext_character () ¤Ï M-text $MT Ãæ¤Çʸ»ú $C ¤òõ¤¹¡£¤â¤· 
2776     $FROM ¤¬ $TO ¤è¤ê¾®¤µ¤±¤ì¤Ð¡¢Ãµº÷¤Ï°ÌÃÖ $FROM ¤«¤éËöÈøÊý¸þ¤Ø¡¢ºÇÂç 
2777     ($TO - 1) ¤Þ¤Ç¿Ê¤à¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð°ÌÃÖ ($FROM - 1) ¤«¤éÀèƬÊý¸þ¤Ø¡¢ºÇÂç
2778     $TO ¤Þ¤Ç¿Ê¤à¡£°ÌÃ֤λØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢$FROM ¤È $TO 
2779     ¤ÎξÊý¤Ë 0 ¤¬»ØÄꤵ¤ì¤¿¤â¤Î¤È¤ß¤Ê¤¹¡£
2780
2781     @return
2782     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_character () 
2783     ¤Ï¤½¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï³°ÉôÊÑ¿ô #merror_code
2784     ¤òÊѹ¹¤»¤º¤Ë -1 ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô
2785     #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
2786
2787 /***
2788     @seealso
2789     mtext_chr(), mtext_rchr ()  */
2790
2791 int
2792 mtext_character (MText *mt, int from, int to, int c)
2793 {
2794   if (from < to)
2795     {
2796       /* We do not use M_CHECK_RANGE () because this function should
2797          not set merror_code.  */
2798       if (from < 0 || to > mt->nchars)
2799         return -1;
2800       return find_char_forward (mt, from, to, c);
2801     }
2802   else
2803     {
2804       /* ditto */
2805       if (to < 0 || from > mt->nchars)
2806         return -1;
2807       return find_char_backward (mt, to, from, c);
2808     }
2809 }
2810
2811
2812 /*=*/
2813
2814 /***en
2815     @brief Return the position of the first occurrence of a character in an M-text.
2816
2817     The mtext_chr () function searches M-text $MT for character $C.
2818     The search starts from the beginning of $MT and goes toward the end.
2819
2820     @return
2821     If $C is found, mtext_chr () returns its position; otherwise it
2822     returns -1.  */
2823
2824 /***ja
2825     @brief M-text Ãæ¤Ç»ØÄꤵ¤ì¤¿Ê¸»ú¤¬ºÇ½é¤Ë¸½¤ì¤ë°ÌÃÖ¤òÊÖ¤¹.
2826
2827     ´Ø¿ô mtext_chr () ¤Ï M-text $MT Ãæ¤Çʸ»ú $C ¤òõ¤¹¡£Ãµº÷¤Ï $MT 
2828     ¤ÎÀèƬ¤«¤éËöÈøÊý¸þ¤Ë¿Ê¤à¡£
2829
2830     @return
2831     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_chr () 
2832     ¤Ï¤½¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£
2833
2834     @latexonly \IPAlabel{mtext_chr} @endlatexonly  */
2835
2836 /***
2837     @errors
2838     @c MERROR_RANGE
2839
2840     @seealso
2841     mtext_rchr (), mtext_character ()  */
2842
2843 int
2844 mtext_chr (MText *mt, int c)
2845 {
2846   return find_char_forward (mt, 0, mt->nchars, c);
2847 }
2848
2849 /*=*/
2850
2851 /***en
2852     @brief Return the position of the last occurrence of a character in an M-text.
2853
2854     The mtext_rchr () function searches M-text $MT for character $C.
2855     The search starts from the end of $MT and goes backwardly toward the
2856     beginning.
2857
2858     @return
2859     If $C is found, mtext_rchr () returns its position; otherwise it
2860     returns -1.  */
2861
2862 /***ja
2863     @brief M-text Ãæ¤Ç»ØÄꤵ¤ì¤¿Ê¸»ú¤¬ºÇ¸å¤Ë¸½¤ì¤ë°ÌÃÖ¤òÊÖ¤¹.
2864
2865     ´Ø¿ô mtext_rchr () ¤Ï M-text $MT Ãæ¤Çʸ»ú $C ¤òõ¤¹¡£Ãµº÷¤Ï $MT 
2866     ¤ÎºÇ¸å¤«¤éÀèƬÊý¸þ¤Ø¤È¸å¸þ¤­¤Ë¿Ê¤à¡£
2867
2868     @return
2869     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_rchr () 
2870     ¤Ï¤½¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£
2871
2872     @latexonly \IPAlabel{mtext_rchr} @endlatexonly  */
2873
2874 /***
2875     @errors
2876     @c MERROR_RANGE
2877
2878     @seealso
2879     mtext_chr (), mtext_character ()  */
2880
2881 int
2882 mtext_rchr (MText *mt, int c)
2883 {
2884   return find_char_backward (mt, mt->nchars, 0, c);
2885 }
2886
2887
2888 /*=*/
2889
2890 /***en
2891     @brief Compare two M-texts character-by-character.
2892
2893     The mtext_cmp () function compares M-texts $MT1 and $MT2 character
2894     by character.
2895
2896     @return
2897     This function returns 1, 0, or -1 if $MT1 is found greater than,
2898     equal to, or less than $MT2, respectively.  Comparison is based on
2899     character codes.  */
2900
2901 /***ja
2902     @brief Æó¤Ä¤Î M-text ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë.
2903
2904     ´Ø¿ô mtext_cmp () ¤Ï¡¢ M-text $MT1 ¤È $MT2 ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë¡£
2905
2906     @return
2907     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì¤Ð
2908     1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð¤Å¤¯¡£
2909
2910     @latexonly \IPAlabel{mtext_cmp} @endlatexonly  */
2911
2912 /***
2913     @seealso
2914     mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
2915     mtext_compare (), mtext_case_compare ()  */
2916
2917 int
2918 mtext_cmp (MText *mt1, MText *mt2)
2919 {
2920   return compare (mt1, 0, mt1->nchars, mt2, 0, mt2->nchars);
2921 }
2922
2923
2924 /*=*/
2925
2926 /***en
2927     @brief Compare initial parts of two M-texts character-by-character.
2928
2929     The mtext_ncmp () function is similar to mtext_cmp (), but
2930     compares at most $N characters from the beginning.
2931
2932     @return
2933     This function returns 1, 0, or -1 if $MT1 is found greater than,
2934     equal to, or less than $MT2, respectively.  */
2935
2936 /***ja
2937     @brief Æó¤Ä¤Î M-text ¤ÎÀèƬÉôʬ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë.
2938
2939     ´Ø¿ô mtext_ncmp () ¤Ï¡¢´Ø¿ô mtext_cmp () Æ±ÍͤΠM-text 
2940     Æ±»Î¤ÎÈæ³Ó¤òÀèƬ¤«¤éºÇÂç $N Ê¸»ú¤Þ¤Ç¤Ë´Ø¤·¤Æ¹Ô¤Ê¤¦¡£
2941
2942     @return
2943     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì¤Ð 
2944     1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
2945
2946     @latexonly \IPAlabel{mtext_ncmp} @endlatexonly  */
2947
2948 /***
2949     @seealso
2950     mtext_cmp (), mtext_casecmp (), mtext_ncasecmp ()
2951     mtext_compare (), mtext_case_compare ()  */
2952
2953 int
2954 mtext_ncmp (MText *mt1, MText *mt2, int n)
2955 {
2956   if (n < 0)
2957     return 0;
2958   return compare (mt1, 0, (mt1->nchars < n ? mt1->nchars : n),
2959                   mt2, 0, (mt2->nchars < n ? mt2->nchars : n));
2960 }
2961
2962 /*=*/
2963
2964 /***en
2965     @brief Compare specified regions of two M-texts.
2966
2967     The mtext_compare () function compares two M-texts $MT1 and $MT2,
2968     character-by-character.  The compared regions are between $FROM1
2969     and $TO1 in $MT1 and $FROM2 to $TO2 in MT2.  $FROM1 and $FROM2 are
2970     inclusive, $TO1 and $TO2 are exclusive.  $FROM1 being equal to
2971     $TO1 (or $FROM2 being equal to $TO2) means an M-text of length
2972     zero.  An invalid region specification is regarded as both $FROM1
2973     and $TO1 (or $FROM2 and $TO2) being 0.
2974
2975     @return
2976     This function returns 1, 0, or -1 if $MT1 is found greater than,
2977     equal to, or less than $MT2, respectively.  Comparison is based on
2978     character codes.  */
2979
2980 /***ja
2981     @brief Æó¤Ä¤Î M-text ¤Î»ØÄꤷ¤¿ÎΰèƱ»Î¤òÈæ³Ó¤¹¤ë.
2982
2983     ´Ø¿ô mtext_compare () ¤ÏÆó¤Ä¤Î M-text $MT1 ¤È $MT2 
2984     ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë¡£Èæ³Ó¤ÎÂоݤϠ$MT1 ¤Î¤¦¤Á $FROM1 ¤«¤é $TO1 ¤Þ¤Ç¤È¡¢$MT2 
2985     ¤Î¤¦¤Á $FROM2 ¤«¤é $TO2 ¤Þ¤Ç¤Ç¤¢¤ë¡£$FROM1 ¤È $FROM2 ¤Ï´Þ¤Þ¤ì¡¢$TO1 
2986     ¤È $TO2 ¤Ï´Þ¤Þ¤ì¤Ê¤¤¡£$FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 
2987     ¡Ë¤¬Åù¤·¤¤¾ì¹ç¤ÏŤµ¥¼¥í¤Î M-text ¤ò°ÕÌ£¤¹¤ë¡£ÈÏ°Ï»ØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢
2988     $FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 ¡Ë Î¾Êý¤Ë 0 ¤¬»ØÄꤵ¤ì¤¿¤â¤Î¤È¤ß¤Ê¤¹¡£
2989
2990     @return
2991     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì¤Ð
2992     1 ¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð¤Å¤¯¡£  */
2993
2994 /***
2995     @seealso
2996     mtext_cmp (), mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
2997     mtext_case_compare ()  */
2998
2999 int
3000 mtext_compare (MText *mt1, int from1, int to1, MText *mt2, int from2, int to2)
3001 {
3002   if (from1 < 0 || from1 > to1 || to1 > mt1->nchars)
3003     from1 = to1 = 0;
3004
3005   if (from2 < 0 || from2 > to2 || to2 > mt2->nchars)
3006     from2 = to2 = 0;
3007
3008   return compare (mt1, from1, to1, mt2, from2, to2);
3009 }
3010
3011 /*=*/
3012
3013 /***en
3014     @brief Search an M-text for a set of characters.
3015
3016     The mtext_spn () function returns the length of the initial
3017     segment of M-text $MT1 that consists entirely of characters in
3018     M-text $MT2.  */
3019
3020 /***ja
3021     @brief ¤¢¤ë½¸¹ç¤Îʸ»ú¤ò M-text ¤ÎÃæ¤Çõ¤¹.
3022
3023     ´Ø¿ô mtext_spn () ¤Ï¡¢M-text $MT1 ¤ÎÀèƬ¤«¤é M-text $MT2 
3024     ¤Ë´Þ¤Þ¤ì¤ëʸ»ú¤À¤±¤Ç¤Ç¤­¤Æ¤¤¤ëÉôʬ¤ÎŤµ¤òÊÖ¤¹¡£
3025
3026     @latexonly \IPAlabel{mtext_spn} @endlatexonly  */
3027
3028 /***
3029     @seealso
3030     mtext_cspn ()  */
3031
3032 int
3033 mtext_spn (MText *mt, MText *accept)
3034 {
3035   return span (mt, accept, 0, Mnil);
3036 }
3037
3038 /*=*/
3039
3040 /***en
3041     @brief Search an M-text for the complement of a set of characters.
3042
3043     The mtext_cspn () returns the length of the initial segment of
3044     M-text $MT1 that consists entirely of characters not in M-text $MT2.  */
3045
3046 /***ja
3047     @brief ¤¢¤ë½¸¹ç¤Ë°¤µ¤Ê¤¤Ê¸»ú¤ò M-text ¤ÎÃæ¤Çõ¤¹.
3048
3049     ´Ø¿ô mtext_cspn () ¤Ï¡¢M-text $MT1 ¤ÎÀèƬÉôʬ¤Ç M-text $MT2
3050     ¤Ë´Þ¤Þ¤ì¤Ê¤¤Ê¸»ú¤À¤±¤Ç¤Ç¤­¤Æ¤¤¤ëÉôʬ¤ÎŤµ¤òÊÖ¤¹¡£
3051
3052     @latexonly \IPAlabel{mtext_cspn} @endlatexonly  */
3053
3054 /***
3055     @seealso
3056     mtext_spn ()  */
3057
3058 int
3059 mtext_cspn (MText *mt, MText *reject)
3060 {
3061   return span (mt, reject, 0, Mt);
3062 }
3063
3064 /*=*/
3065
3066 /***en
3067     @brief Search an M-text for any of a set of characters.
3068
3069     The mtext_pbrk () function locates the first occurrence in M-text
3070     $MT1 of any of the characters in M-text $MT2.
3071
3072     @return
3073     This function returns the position in $MT1 of the found character.
3074     If no such character is found, it returns -1. */
3075
3076 /***ja
3077     @brief ¤¢¤ë½¸¹ç¤Ë°¤¹Ê¸»ú¤ò M-text ¤ÎÃ椫¤éõ¤¹.
3078
3079     ´Ø¿ô mtext_pbrk () ¤Ï¡¢M-text $MT1 Ãæ¤Ç M-text $MT2 
3080     ¤Îʸ»ú¤Î¤É¤ì¤«¤¬ºÇ½é¤Ë¸½¤ì¤ë°ÌÃÖ¤òÄ´¤Ù¤ë¡£
3081
3082     @return 
3083     ¸«¤Ä¤«¤Ã¤¿Ê¸»ú¤Î¡¢$MT1 
3084     Æâ¤Ë¤ª¤±¤ë½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¤â¤·¤½¤Î¤è¤¦¤Êʸ»ú¤¬¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
3085
3086     @latexonly \IPAlabel{mtext_pbrk} @endlatexonly  */
3087
3088 int
3089 mtext_pbrk (MText *mt, MText *accept)
3090 {
3091   int nchars = mtext_nchars (mt);
3092   int len = span (mt, accept, 0, Mt);
3093
3094   return (len == nchars ? -1 : len);
3095 }
3096
3097 /*=*/
3098
3099 /***en
3100     @brief Look for a token in an M-text.
3101
3102     The mtext_tok () function searches a token that firstly occurs
3103     after position $POS in M-text $MT.  Here, a token means a
3104     substring each of which does not appear in M-text $DELIM.  Note
3105     that the type of $POS is not @c int but pointer to @c int.
3106
3107     @return
3108     If a token is found, mtext_tok () copies the corresponding part of
3109     $MT and returns a pointer to the copy.  In this case, $POS is set
3110     to the end of the found token.  If no token is found, it returns
3111     @c NULL without changing the external variable #merror_code.  If an
3112     error is detected, it returns @c NULL and assigns an error code
3113     to the external variable #merror_code. */
3114
3115 /***ja
3116     @brief M-text Ãæ¤Î¥È¡¼¥¯¥ó¤òõ¤¹.
3117
3118     ´Ø¿ô mtext_tok () ¤Ï¡¢M-text $MT ¤ÎÃæ¤Ç°ÌÃÖ $POS 
3119     °Ê¹ßºÇ½é¤Ë¸½¤ì¤ë¥È¡¼¥¯¥ó¤òõ¤¹¡£¤³¤³¤Ç¥È¡¼¥¯¥ó¤È¤Ï M-text $DELIM
3120     ¤ÎÃæ¤Ë¸½¤ï¤ì¤Ê¤¤Ê¸»ú¤À¤±¤«¤é¤Ê¤ëÉôʬʸ»úÎó¤Ç¤¢¤ë¡£$POS ¤Î·¿¤¬ @c int ¤Ç¤Ï¤Ê¤¯¤Æ @c
3121     int ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¤³¤È¤ËÃí°Õ¡£
3122
3123     @return
3124     ¤â¤·¥È¡¼¥¯¥ó¤¬¸«¤Ä¤«¤ì¤Ð mtext_tok ()¤Ï¤½¤Î¥È¡¼¥¯¥ó¤ËÁêÅö¤¹¤ëÉôʬ¤Î 
3125     $MT ¤ò¥³¥Ô¡¼¤·¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢$POS 
3126     ¤Ï¸«¤Ä¤«¤Ã¤¿¥È¡¼¥¯¥ó¤Î½ªÃ¼¤Ë¥»¥Ã¥È¤µ¤ì¤ë¡£¥È¡¼¥¯¥ó¤¬¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï³°ÉôÊÑ¿ô
3127     #merror_code ¤òÊѤ¨¤º¤Ë @c NULL ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï 
3128     @c NULL ¤òÊÖ¤·¡¢ÊÑÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
3129
3130     @latexonly \IPAlabel{mtext_tok} @endlatexonly  */
3131
3132 /***
3133     @errors
3134     @c MERROR_RANGE  */
3135
3136 MText *
3137 mtext_tok (MText *mt, MText *delim, int *pos)
3138 {
3139   int nchars = mtext_nchars (mt);
3140   int pos2;
3141
3142   M_CHECK_POS (mt, *pos, NULL);
3143
3144   /*
3145     Skip delimiters starting at POS in MT.
3146     Never do *pos += span(...), or you will change *pos
3147     even though no token is found.
3148    */
3149   pos2 = *pos + span (mt, delim, *pos, Mnil);
3150
3151   if (pos2 == nchars)
3152     return NULL;
3153
3154   *pos = pos2 + span (mt, delim, pos2, Mt);
3155   return (insert (mtext (), 0, mt, pos2, *pos));
3156 }
3157
3158 /*=*/
3159
3160 /***en
3161     @brief Locate an M-text in another.
3162
3163     The mtext_text () function finds the first occurrence of M-text
3164     $MT2 in M-text $MT1 after the position $POS while ignoring
3165     difference of the text properties.
3166
3167     @return
3168     If $MT2 is found in $MT1, mtext_text () returns the position of it
3169     first occurrence.  Otherwise it returns -1.  If $MT2 is empty, it
3170     returns 0.  */
3171
3172 /***ja
3173     @brief M-text Ãæ¤ÇÊ̤ΠM-text ¤òõ¤¹.
3174
3175     ´Ø¿ô mtext_text () ¤Ï¡¢M-text $MT1 Ãæ¤Ç°ÌÃÖ $POS °Ê¹ß¤Ë¸½¤ï¤ì¤ë 
3176     M-text $MT2 ¤ÎºÇ½é¤Î°ÌÃÖ¤òÄ´¤Ù¤ë¡£¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î°ã¤¤¤Ï̵»ë¤µ¤ì¤ë¡£
3177
3178     @return
3179     $MT1 Ãæ¤Ë $MT2 ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_text() 
3180     ¤Ï¤½¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤¤¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£¤â¤· $MT2 ¤¬¶õ¤Ê¤é¤Ð 0 ¤òÊÖ¤¹¡£
3181
3182     @latexonly \IPAlabel{mtext_text} @endlatexonly  */
3183
3184 int
3185 mtext_text (MText *mt1, int pos, MText *mt2)
3186 {
3187   int from = pos;
3188   int c = mtext_ref_char (mt2, 0);
3189   int nbytes2 = mtext_nbytes (mt2);
3190   int limit;
3191   int use_memcmp = (mt1->format == mt2->format
3192                     || (mt1->format < MTEXT_FORMAT_UTF_8
3193                         && mt2->format == MTEXT_FORMAT_UTF_8));
3194   int unit_bytes = UNIT_BYTES (mt1->format);
3195
3196   if (from + mtext_nchars (mt2) > mtext_nchars (mt1))
3197     return -1;
3198   limit = mtext_nchars (mt1) - mtext_nchars (mt2) + 1;
3199
3200   while (1)
3201     {
3202       int pos_byte;
3203
3204       if ((pos = mtext_character (mt1, from, limit, c)) < 0)
3205         return -1;
3206       pos_byte = POS_CHAR_TO_BYTE (mt1, pos);
3207       if (use_memcmp
3208           ? ! memcmp (mt1->data + pos_byte * unit_bytes, 
3209                       mt2->data, nbytes2 * unit_bytes)
3210           : ! compare (mt1, pos, mt2->nchars, mt2, 0, mt2->nchars))
3211         break;
3212       from = pos + 1;
3213     }
3214   return pos;
3215 }
3216
3217 /***en
3218     @brief Locate an M-text in a specific range of another.
3219
3220     The mtext_search () function searches for the first occurrence of
3221     M-text $MT2 in M-text $MT1 in the region $FROM and $TO while
3222     ignoring difference of the text properties.  If $FROM is less than
3223     $TO, the forward search starts from $FROM, otherwise the backward
3224     search starts from $TO.
3225
3226     @return
3227     If $MT2 is found in $MT1, mtext_search () returns the position of the
3228     first occurrence.  Otherwise it returns -1.  If $MT2 is empty, it
3229     returns 0.  */
3230
3231 /***ja
3232     @brief M-text Ãæ¤ÎÆÃÄê¤ÎÎΰè¤ÇÊ̤ΠM-text ¤òõ¤¹.
3233
3234     ´Ø¿ô mtext_search () ¤Ï¡¢M-text $MT1 Ãæ¤Î $FROM ¤«¤é $TO 
3235     ¤Þ¤Ç¤Î´Ö¤ÎÎΰè¤ÇM-text $MT2 
3236     ¤¬ºÇ½é¤Ë¸½¤ï¤ì¤ë°ÌÃÖ¤òÄ´¤Ù¤ë¡£¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î°ã¤¤¤Ï̵»ë¤µ¤ì¤ë¡£¤â¤·
3237     $FROM ¤¬ $TO ¤è¤ê¾®¤µ¤±¤ì¤Ðõº÷¤Ï°ÌÃÖ $FROM ¤«¤éËöÈøÊý¸þ¤Ø¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
3238     $TO ¤«¤éÀèƬÊý¸þ¤Ø¿Ê¤à¡£
3239
3240     @return
3241     $MT1 Ãæ¤Ë $MT2 ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_search() 
3242     ¤Ï¤½¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤¤¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£¤â¤· $MT2 ¤¬¶õ¤Ê¤é¤Ð 0 ¤òÊÖ¤¹¡£
3243     */
3244
3245 int
3246 mtext_search (MText *mt1, int from, int to, MText *mt2)
3247 {
3248   int c = mtext_ref_char (mt2, 0);
3249   int from_byte;
3250   int nbytes2 = mtext_nbytes (mt2);
3251
3252   if (mt1->format > MTEXT_FORMAT_UTF_8
3253       || mt2->format > MTEXT_FORMAT_UTF_8)
3254     MERROR (MERROR_MTEXT, -1);
3255
3256   if (from < to)
3257     {
3258       to -= mtext_nchars (mt2);
3259       if (from > to)
3260         return -1;
3261       while (1)
3262         {
3263           if ((from = find_char_forward (mt1, from, to, c)) < 0)
3264             return -1;
3265           from_byte = POS_CHAR_TO_BYTE (mt1, from);
3266           if (! memcmp (mt1->data + from_byte, mt2->data, nbytes2))
3267             break;
3268           from++;
3269         }
3270     }
3271   else if (from > to)
3272     {
3273       from -= mtext_nchars (mt2);
3274       if (from < to)
3275         return -1;
3276       while (1)
3277         {
3278           if ((from = find_char_backward (mt1, to, from + 1, c)) < 0)
3279             return -1;
3280           from_byte = POS_CHAR_TO_BYTE (mt1, from);
3281           if (! memcmp (mt1->data + from_byte, mt2->data, nbytes2))
3282             break;
3283           from--;
3284         }
3285     }
3286
3287   return from;
3288 }
3289
3290 /*=*/
3291
3292 /***en
3293     @brief Compare two M-texts ignoring cases.
3294
3295     The mtext_casecmp () function is similar to mtext_cmp (), but
3296     ignores cases on comparison.
3297
3298     @return
3299     This function returns 1, 0, or -1 if $MT1 is found greater than,
3300     equal to, or less than $MT2, respectively.  */
3301
3302 /***ja
3303     @brief Æó¤Ä¤Î M-text ¤òÂçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤ÆÈæ³Ó¤¹¤ë.
3304
3305     ´Ø¿ô mtext_casecmp () ¤Ï¡¢´Ø¿ô mtext_cmp () Æ±ÍͤΠM-text 
3306     Æ±»Î¤ÎÈæ³Ó¤ò¡¢Âçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤Æ¹Ô¤Ê¤¦¡£
3307
3308     @return
3309     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 
3310     ¤è¤êÂ礭¤±¤ì¤Ð 1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
3311
3312     @latexonly \IPAlabel{mtext_casecmp} @endlatexonly  */
3313
3314 /***
3315     @seealso
3316     mtext_cmp (), mtext_ncmp (), mtext_ncasecmp ()
3317     mtext_compare (), mtext_case_compare ()  */
3318
3319 int
3320 mtext_casecmp (MText *mt1, MText *mt2)
3321 {
3322   return case_compare (mt1, 0, mt1->nchars, mt2, 0, mt2->nchars);
3323 }
3324
3325 /*=*/
3326
3327 /***en
3328     @brief Compare initial parts of two M-texts ignoring cases.
3329
3330     The mtext_ncasecmp () function is similar to mtext_casecmp (), but
3331     compares at most $N characters from the beginning.
3332
3333     @return
3334     This function returns 1, 0, or -1 if $MT1 is found greater than,
3335     equal to, or less than $MT2, respectively.  */
3336
3337 /***ja
3338     @brief Æó¤Ä¤Î M-text ¤ÎÀèƬÉôʬ¤òÂçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤ÆÈæ³Ó¤¹¤ë.
3339
3340     ´Ø¿ô mtext_ncasecmp () ¤Ï¡¢´Ø¿ô mtext_casecmp () Æ±ÍͤΠM-text 
3341     Æ±»Î¤ÎÈæ³Ó¤òÀèƬ¤«¤éºÇÂç $N Ê¸»ú¤Þ¤Ç¤Ë´Ø¤·¤Æ¹Ô¤Ê¤¦¡£
3342
3343     @return
3344     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 
3345     ¤è¤êÂ礭¤±¤ì¤Ð 1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
3346
3347     @latexonly \IPAlabel{mtext_ncasecmp} @endlatexonly  */
3348
3349 /***
3350     @seealso
3351     mtext_cmp (), mtext_casecmp (), mtext_casecmp ()
3352     mtext_compare (), mtext_case_compare ()  */
3353
3354 int
3355 mtext_ncasecmp (MText *mt1, MText *mt2, int n)
3356 {
3357   if (n < 0)
3358     return 0;
3359   return case_compare (mt1, 0, (mt1->nchars < n ? mt1->nchars : n),
3360                        mt2, 0, (mt2->nchars < n ? mt2->nchars : n));
3361 }
3362
3363 /*=*/
3364
3365 /***en
3366     @brief Compare specified regions of two M-texts ignoring cases. 
3367
3368     The mtext_case_compare () function compares two M-texts $MT1 and
3369     $MT2, character-by-character, ignoring cases.  The compared
3370     regions are between $FROM1 and $TO1 in $MT1 and $FROM2 to $TO2 in
3371     MT2.  $FROM1 and $FROM2 are inclusive, $TO1 and $TO2 are
3372     exclusive.  $FROM1 being equal to $TO1 (or $FROM2 being equal to
3373     $TO2) means an M-text of length zero.  An invalid region
3374     specification is regarded as both $FROM1 and $TO1 (or $FROM2 and
3375     $TO2) being 0.
3376
3377     @return
3378     This function returns 1, 0, or -1 if $MT1 is found greater than,
3379     equal to, or less than $MT2, respectively.  Comparison is based on
3380     character codes.  */
3381
3382 /***ja 
3383     @brief Æó¤Ä¤Î M-text ¤Î»ØÄꤷ¤¿Îΰè¤ò¡¢Âçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤ÆÈæ³Ó¤¹¤ë.
3384
3385     ´Ø¿ô mtext_compare () ¤ÏÆó¤Ä¤Î M-text $MT1 ¤È $MT2 
3386     ¤ò¡¢Âçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤Æʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë¡£Èæ³Ó¤ÎÂоݤϠ$MT1 
3387     ¤Î $FROM1 ¤«¤é $TO1 ¤Þ¤Ç¡¢$MT2 ¤Î $FROM2 ¤«¤é $TO2 ¤Þ¤Ç¤Ç¤¢¤ë¡£
3388     $FROM1 ¤È $FROM2 ¤Ï´Þ¤Þ¤ì¡¢$TO1 ¤È $TO2 ¤Ï´Þ¤Þ¤ì¤Ê¤¤¡£$FROM1 ¤È $TO1
3389     ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 ¡Ë¤¬Åù¤·¤¤¾ì¹ç¤ÏŤµ¥¼¥í¤Î M-text 
3390     ¤ò°ÕÌ£¤¹¤ë¡£ÈÏ°Ï»ØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢$FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï 
3391     $FROM2 ¤È $TO2 ¡ËξÊý¤Ë 0 ¤¬»ØÄꤵ¤ì¤¿¤â¤Î¤È¸«¤Ê¤¹¡£
3392
3393     @return
3394     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì¤Ð
3395     1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð¤Å¤¯¡£
3396
3397   @latexonly \IPAlabel{mtext_case_compare} @endlatexonly
3398 */
3399
3400 /***
3401     @seealso
3402     mtext_cmp (), mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
3403     mtext_compare ()  */
3404
3405 int
3406 mtext_case_compare (MText *mt1, int from1, int to1,
3407                     MText *mt2, int from2, int to2)
3408 {
3409   if (from1 < 0 || from1 > to1 || to1 > mt1->nchars)
3410     from1 = to1 = 0;
3411
3412   if (from2 < 0 || from2 > to2 || to2 > mt2->nchars)
3413     from2 = to2 = 0;
3414
3415   return case_compare (mt1, from1, to1, mt2, from2, to2);
3416 }
3417
3418 /*=*/
3419
3420 /***en
3421     @brief Lowercase an M-text.
3422
3423     The mtext_lowercase () function destructively converts each
3424     character in M-text $MT to lowercase.  Adjacent characters in $MT
3425     may affect the case conversion.  If the Mlanguage text property is
3426     attached to $MT, it may also affect the conversion.  The length of
3427     $MT may change.  Characters that cannot be converted to lowercase
3428     is left unchanged.  All the text properties are inherited.
3429
3430     @return
3431     This function returns the length of the updated $MT.
3432 */
3433
3434 /***ja
3435     @brief M-text ¤ò¾®Ê¸»ú¤Ë¤¹¤ë.
3436
3437     ´Ø¿ô mtext_lowercase () ¤Ï M-text $MT Ãæ¤Î³Æʸ»ú¤òÇ˲õŪ¤Ë¾®Ê¸»ú¤ËÊÑ
3438     ´¹¤¹¤ë¡£ÊÑ´¹¤ËºÝ¤·¤ÆÎÙÀܤ¹¤ëʸ»ú¤Î±Æ¶Á¤ò¼õ¤±¤ë¤³¤È¤¬¤¢¤ë¡£$MT ¤Ë¥Æ
3439     ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ Mlanguage ¤¬ÉÕ¤¤¤Æ¤¤¤ë¾ì¹ç¤Ï¡¢¤½¤ì¤âÊÑ´¹¤Ë±Æ¶Á¤ò
3440     Í¿¤¨¤¦¤ë¡£$MT ¤ÎŤµ¤ÏÊѤï¤ë¤³¤È¤¬¤¢¤ë¡£¾®Ê¸»ú¤ËÊÑ´¹¤Ç¤­¤Ê¤«¤Ã¤¿Ê¸
3441     »ú¤Ï¤½¤Î¤Þ¤Þ»Ä¤ë¡£¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£
3442
3443     @return
3444     ¤³¤Î´Ø¿ô¤Ï¹¹¿·¸å¤Î $MT ¤ÎŤµ¤òÊÖ¤¹¡£
3445 */
3446
3447 /***
3448     @seealso
3449      mtext_titlecase (), mtext_uppercase ()
3450 */
3451
3452 int
3453 mtext_lowercase (MText *mt)
3454
3455 {
3456   CASE_CONV_INIT (-1);
3457
3458   return mtext__lowercase (mt, 0, mtext_len (mt));
3459 }
3460
3461 /*=*/
3462
3463 /***en
3464     @brief Titlecase an M-text.
3465
3466     The mtext_titlecase () function destructively converts the first
3467     character with the cased property in M-text $MT to titlecase and
3468     the others to lowercase.  The length of $MT may change.  If the
3469     character cannot be converted to titlecase, it is left unchanged.
3470     All the text properties are inherited.
3471
3472     @return
3473     This function returns the length of the updated $MT.
3474 */
3475
3476 /***ja
3477     @brief M-text ¤ò¥¿¥¤¥È¥ë¥±¡¼¥¹¤Ë¤¹¤ë.
3478
3479     ´Ø¿ô mtext_titlecase () ¤Ï M-text $MT Ãæ¤Ç cased ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä
3480     ºÇ½é¤Îʸ»ú¤ò¥¿¥¤¥È¥ë¥±¡¼¥¹¤Ë¡¢¤½¤·¤Æ¤½¤ì°Ê¹ß¤Îʸ»ú¤ò¾®Ê¸»ú¤ËÇ˲õŪ
3481     ¤ËÊÑ´¹¤¹¤ë¡£$MT ¤ÎŤµ¤ÏÊѤï¤ë¤³¤È¤¬¤¢¤ë¡£¥¿¥¤¥È¥ë¥±¡¼¥¹¤Ë¤ËÊÑ´¹¤Ç
3482     ¤­¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï¤½¤Î¤Þ¤Þ¤ÇÊѤï¤é¤Ê¤¤¡£¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ
3483     ¾µ¤µ¤ì¤ë¡£
3484
3485     @return
3486     ¤³¤Î´Ø¿ô¤Ï¹¹¿·¸å¤Î $MT ¤ÎŤµ¤òÊÖ¤¹¡£
3487 */
3488
3489 /***
3490     @seealso
3491      mtext_lowercase (), mtext_uppercase ()
3492 */
3493
3494 int
3495 mtext_titlecase (MText *mt)
3496 {
3497   int len = mtext_len (mt), from, to;
3498
3499   CASE_CONV_INIT (-1);
3500
3501   /* Find 1st cased character. */
3502   for (from = 0; from < len; from++)
3503     {
3504       int csd = (int) mchartable_lookup (cased, mtext_ref_char (mt, from));
3505
3506       if (csd > 0 && csd & CASED)
3507         break;
3508     }
3509
3510   if (from == len)
3511     return len;
3512
3513   if (from == len - 1)
3514     return (mtext__titlecase (mt, from, len));
3515
3516   /* Go through following combining characters. */
3517   for (to = from + 1;
3518        (to < len
3519         && ((int) mchartable_lookup (combining_class, mtext_ref_char (mt, to))
3520             > 0));
3521        to++);
3522
3523   /* Titlecase the region and prepare for next lowercase operation.
3524      MT may be shortened or lengthened. */
3525   from = mtext__titlecase (mt, from, to);
3526
3527   return (mtext__lowercase (mt, from, mtext_len (mt)));
3528 }
3529
3530 /*=*/
3531
3532 /***en
3533     @brief Uppercase an M-text.
3534
3535
3536     The mtext_uppercase () function destructively converts each
3537     character in M-text $MT to uppercase.  Adjacent characters in $MT
3538     may affect the case conversion.  If the Mlanguage text property is
3539     attached to $MT, it may also affect the conversion.  The length of
3540     $MT may change.  Characters that cannot be converted to uppercase
3541     is left unchanged.  All the text properties are inherited.
3542
3543     @return
3544     This function returns the length of the updated $MT.
3545 */
3546
3547 /***ja
3548     @brief M-text ¤òÂçʸ»ú¤Ë¤¹¤ë.
3549
3550     ´Ø¿ô mtext_uppercase () ¤Ï M-text $MT Ãæ¤Î³Æʸ»ú¤òÇ˲õŪ¤ËÂçʸ»ú¤ËÊÑ
3551     ´¹¤¹¤ë¡£ÊÑ´¹¤ËºÝ¤·¤ÆÎÙÀܤ¹¤ëʸ»ú¤Î±Æ¶Á¤ò¼õ¤±¤ë¤³¤È¤¬¤¢¤ë¡£$MT ¤Ë¥Æ
3552     ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ Mlanguage ¤¬ÉÕ¤¤¤Æ¤¤¤ë¾ì¹ç¤Ï¡¢¤½¤ì¤âÊÑ´¹¤Ë±Æ¶Á¤ò
3553     Í¿¤¨¤¦¤ë¡£$MT ¤ÎŤµ¤ÏÊѤï¤ë¤³¤È¤¬¤¢¤ë¡£Âçʸ»ú¤ËÊÑ´¹¤Ç¤­¤Ê¤«¤Ã¤¿Ê¸
3554     »ú¤Ï¤½¤Î¤Þ¤Þ»Ä¤ë¡£¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£
3555
3556     @return
3557     ¤³¤Î´Ø¿ô¤Ï¹¹¿·¸å¤Î $MT ¤ÎŤµ¤òÊÖ¤¹¡£
3558 */
3559
3560 /***
3561     @seealso
3562      mtext_lowercase (), mtext_titlecase ()
3563 */
3564
3565 int
3566 mtext_uppercase (MText *mt)
3567 {
3568   CASE_CONV_INIT (-1);
3569
3570   return (mtext__uppercase (mt, 0, mtext_len (mt)));
3571 }
3572
3573 /*** @} */
3574
3575 #include <stdio.h>
3576
3577 /*** @addtogroup m17nDebug */
3578 /*=*/
3579 /*** @{  */
3580
3581 /***en
3582     @brief Dump an M-text.
3583
3584     The mdebug_dump_mtext () function prints the M-text $MT in a human
3585     readable way to the stderr.  $INDENT specifies how many columns to
3586     indent the lines but the first one.  If $FULLP is zero, this
3587     function prints only a character code sequence.  Otherwise, it
3588     prints the internal byte sequence and text properties as well.
3589
3590     @return
3591     This function returns $MT.  */
3592 /***ja
3593     @brief M-text ¤ò¥À¥ó¥×¤¹¤ë.
3594
3595     ´Ø¿ô mdebug_dump_mtext () ¤Ï M-text $MT ¤ò stderr 
3596     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
3597     $FULLP ¤¬ 0 ¤Ê¤é¤Ð¡¢Ê¸»ú¥³¡¼¥ÉÎó¤À¤±¤ò°õºþ¤¹¤ë¡£
3598     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢ÆâÉô¥Ð¥¤¥ÈÎó¤È¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤â°õºþ¤¹¤ë¡£
3599
3600     @return
3601     ¤³¤Î´Ø¿ô¤Ï $MT ¤òÊÖ¤¹¡£  */
3602
3603 MText *
3604 mdebug_dump_mtext (MText *mt, int indent, int fullp)
3605 {
3606   int i;
3607
3608   if (! fullp)
3609     {
3610       fprintf (stderr, "\"");
3611       for (i = 0; i < mt->nchars; i++)
3612         {
3613           int c = mtext_ref_char (mt, i);
3614
3615           if (c == '"' || c == '\\')
3616             fprintf (stderr, "\\%c", c);
3617           else if ((c >= ' ' && c < 127) || c == '\n')
3618             fprintf (stderr, "%c", c);
3619           else
3620             fprintf (stderr, "\\x%02X", c);
3621         }
3622       fprintf (stderr, "\"");
3623       return mt;
3624     }
3625
3626   fprintf (stderr,
3627            "(mtext (size %d %d %d) (cache %d %d)",
3628            mt->nchars, mt->nbytes, mt->allocated,
3629            mt->cache_char_pos, mt->cache_byte_pos);
3630
3631   if (mt->nchars > 0)
3632     {
3633       char *prefix = (char *) alloca (indent + 1);
3634       unsigned char *p;
3635
3636       memset (prefix, 32, indent);
3637       prefix[indent] = 0;
3638
3639       fprintf (stderr, "\n%s (bytes \"", prefix);
3640       for (i = 0; i < mt->nbytes; i++)
3641         fprintf (stderr, "\\x%02x", mt->data[i]);
3642       fprintf (stderr, "\")\n");
3643       fprintf (stderr, "%s (chars \"", prefix);
3644       p = mt->data;
3645       for (i = 0; i < mt->nchars; i++)
3646         {
3647           int len;
3648           int c = STRING_CHAR_AND_BYTES (p, len);
3649
3650           if (c == '"' || c == '\\')
3651             fprintf (stderr, "\\%c", c);
3652           else if (c >= ' ' && c < 127)
3653             fputc (c, stderr);
3654           else
3655             fprintf (stderr, "\\x%X", c);
3656           p += len;
3657         }
3658       fprintf (stderr, "\")");
3659       if (mt->plist)
3660         {
3661           fprintf (stderr, "\n%s ", prefix);
3662           dump_textplist (mt->plist, indent + 1);
3663         }
3664     }
3665   fprintf (stderr, ")");
3666   return mt;
3667 }
3668
3669 /*** @} */ 
3670
3671 /*
3672   Local Variables:
3673   coding: euc-japan
3674   End:
3675 */