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