(mfont__ft_init): Add oblique and boldoblique.
[m17n/m17n-lib.git] / src / mtext.c
1 /* mtext.c -- M-text module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nMtext
25     @brief M-text objects and API for them.
26
27     In the m17n library, text is represented as an object called @e
28     M-text rather than as a C-string (<tt>char *</tt> or <tt>unsigned
29     char *</tt>).  An M-text is a sequence of characters whose length
30     is equals to or more than 0, and can be coined from various
31     character sources, e.g. C-strings, files, character codes, etc.
32
33     M-texts are more useful than C-strings in the following points.
34
35     @li M-texts can handle mixture of characters of various scripts,
36     including all Unicode characters and more.  This is an
37     indispensable facility when handling multilingual text.
38
39     @li Each character in an M-text can have properties called @e text
40     @e properties. Text properties store various kinds of information
41     attached to parts of an M-text to provide application programs
42     with a unified view of those information.  As rich information can
43     be stored in M-texts in the form of text properties, functions in
44     application programs can be simple.
45
46     In addition, the library provides many functions to manipulate an
47     M-text just the same way as a C-string.  */
48
49 /***ja
50     @addtogroup m17nMtext
51
52     @brief M-text ¥ª¥Ö¥¸¥§¥¯¥È¤È¤½¤ì¤Ë´Ø¤¹¤ë API
53
54     m17n ¥é¥¤¥Ö¥é¥ê¤ÏÄ̾ï¤Î C-string¡Ê<tt>char *</tt> ¤ä <tt>unsigned
55     char *</tt>¡Ë¤Ç¤Ï¤Ê¤¯ M-text ¤È¸Æ¤Ö¥ª¥Ö¥¸¥§¥¯¥È¤Ç¥Æ¥­¥¹¥È¤òɽ¸½¤¹
56     ¤ë¡£M-text ¤ÏŤµ£°°Ê¾å¤Îʸ»ú¤ÎÎ󤫤é¤Ê¤ê¡¢¼ï¡¹¤Îʸ»ú¥½¡¼¥¹¡ÊÎ㤨
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 int
810 mtext__replace (MText *mt, int from, int to, char *from_str, char *to_str)
811 {
812   int from_byte = POS_CHAR_TO_BYTE (mt, from);
813   int to_byte = POS_CHAR_TO_BYTE (mt, to);
814   unsigned char *p = MTEXT_DATA (mt) + from_byte;
815   unsigned char *endp = MTEXT_DATA (mt) + to_byte;
816   int from_str_len = strlen (from_str);
817   int to_str_len = strlen (to_str);
818   int diff = to_str_len - from_str_len;
819   unsigned char saved_byte;
820   int pos, pos_byte;
821
822   if (mtext_nchars (mt) == 0
823       || from_str_len == 0)
824     return 0;
825   M_CHECK_READONLY (mt, -1);
826   M_CHECK_RANGE (mt, from, to, -1, 0);
827
828   saved_byte = *endp;
829   *endp = '\0';
830   while ((p = (unsigned char *) strstr ((char *) p, from_str)) != NULL)
831     {
832       if (diff < 0)
833         {
834           pos_byte = p - MTEXT_DATA (mt);
835           pos = POS_BYTE_TO_CHAR (mt, pos_byte);
836           mtext_del (mt, pos, pos - diff);
837         }
838       else if (diff > 0)
839         {
840           pos_byte = p - MTEXT_DATA (mt);
841           pos = POS_BYTE_TO_CHAR (mt, pos_byte);
842           mtext_ins_char (mt, pos, ' ', diff);
843           /* The above may relocate mt->data.  */
844           endp += (MTEXT_DATA (mt) + pos_byte) - p;
845           p = MTEXT_DATA (mt) + pos_byte;
846         }
847       memmove (p, to_str, to_str_len);
848       p += to_str_len;
849       endp += diff;
850     }
851   *endp = saved_byte;
852   return 0;
853 }
854
855
856 /* Find the position of a character at the beginning of a line of
857    M-Text MT searching backward from POS.  */
858
859 int
860 mtext__bol (MText *mt, int pos)
861 {
862   int byte_pos;
863
864   if (pos == 0)
865     return pos;
866   byte_pos = POS_CHAR_TO_BYTE (mt, pos);
867   if (mt->format <= MTEXT_FORMAT_UTF_8)
868     {
869       unsigned char *p = mt->data + byte_pos;
870
871       if (p[-1] == '\n')
872         return pos;
873       p--;
874       while (p > mt->data && p[-1] != '\n')
875         p--;
876       if (p == mt->data)
877         return 0;
878       byte_pos = p - mt->data;
879       return POS_BYTE_TO_CHAR (mt, byte_pos);
880     }
881   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
882     {
883       unsigned short *p = ((unsigned short *) (mt->data)) + byte_pos;
884       unsigned short newline = mt->format == default_utf_16 ? 0x0A00 : 0x000A;
885
886       if (p[-1] == newline)
887         return pos;
888       p--;
889       while (p > (unsigned short *) (mt->data) && p[-1] != newline)
890         p--;
891       if (p == (unsigned short *) (mt->data))
892         return 0;
893       byte_pos = p - (unsigned short *) (mt->data);
894       return POS_BYTE_TO_CHAR (mt, byte_pos);;
895     }
896   else
897     {
898       unsigned *p = ((unsigned *) (mt->data)) + byte_pos;
899       unsigned newline = mt->format == default_utf_32 ? 0x0A000000 : 0x0000000A;
900
901       if (p[-1] == newline)
902         return pos;
903       p--, pos--;
904       while (p > (unsigned *) (mt->data) && p[-1] != newline)
905         p--, pos--;
906       return pos;
907     }
908 }
909
910
911 /* Find the position of a character at the end of a line of M-Text MT
912    searching forward from POS.  */
913
914 int
915 mtext__eol (MText *mt, int pos)
916 {
917   int byte_pos;
918
919   if (pos == mt->nchars)
920     return pos;
921   byte_pos = POS_CHAR_TO_BYTE (mt, pos);
922   if (mt->format <= MTEXT_FORMAT_UTF_8)
923     {
924       unsigned char *p = mt->data + byte_pos;
925       unsigned char *endp;
926
927       if (*p == '\n')
928         return pos + 1;
929       p++;
930       endp = mt->data + mt->nbytes;
931       while (p < endp && *p != '\n')
932         p++;
933       if (p == endp)
934         return mt->nchars;
935       byte_pos = p + 1 - mt->data;
936       return POS_BYTE_TO_CHAR (mt, byte_pos);
937     }
938   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
939     {
940       unsigned short *p = ((unsigned short *) (mt->data)) + byte_pos;
941       unsigned short *endp;
942       unsigned short newline = mt->format == default_utf_16 ? 0x0A00 : 0x000A;
943
944       if (*p == newline)
945         return pos + 1;
946       p++;
947       endp = (unsigned short *) (mt->data) + mt->nbytes;
948       while (p < endp && *p != newline)
949         p++;
950       if (p == endp)
951         return mt->nchars;
952       byte_pos = p + 1 - (unsigned short *) (mt->data);
953       return POS_BYTE_TO_CHAR (mt, byte_pos);
954     }
955   else
956     {
957       unsigned *p = ((unsigned *) (mt->data)) + byte_pos;
958       unsigned *endp;
959       unsigned newline = mt->format == default_utf_32 ? 0x0A000000 : 0x0000000A;
960
961       if (*p == newline)
962         return pos + 1;
963       p++, pos++;
964       endp = (unsigned *) (mt->data) + mt->nbytes;
965       while (p < endp && *p != newline)
966         p++, pos++;
967       return pos;
968     }
969 }
970
971 /*** @} */
972 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
973
974 \f
975 /* External API */
976
977 /*** @addtogroup m17nMtext */
978 /*** @{ */
979 /*=*/
980
981 /***en
982     @brief Allocate a new M-text.
983
984     The mtext () function allocates a new M-text of length 0 and
985     returns a pointer to it.  The allocated M-text will not be freed
986     unless the user explicitly does so with the m17n_object_free ()
987     function.  */
988
989 /***ja
990     @brief ¿·¤·¤¤M-text¤ò³ä¤êÅö¤Æ¤ë
991
992     ´Ø¿ô mtext () ¤Ï¡¢Ä¹¤µ 0 ¤Î¿·¤·¤¤ M-text ¤ò³ä¤êÅö¤Æ¡¢¤½¤ì¤Ø¤Î¥Ý¥¤
993     ¥ó¥¿¤òÊÖ¤¹¡£³ä¤êÅö¤Æ¤é¤ì¤¿ M-text ¤Ï¡¢´Ø¿ô m17n_object_free () ¤Ë
994     ¤è¤Ã¤Æ¥æ¡¼¥¶¤¬ÌÀ¼¨Åª¤Ë¹Ô¤Ê¤ï¤Ê¤¤¸Â¤ê¡¢²òÊü¤µ¤ì¤Ê¤¤¡£
995
996     @latexonly \IPAlabel{mtext} @endlatexonly  */
997
998 /***
999     @seealso
1000     m17n_object_free ()  */
1001
1002 MText *
1003 mtext ()
1004 {
1005   MText *mt;
1006
1007   M17N_OBJECT (mt, free_mtext, MERROR_MTEXT);
1008   mt->format = MTEXT_FORMAT_UTF_8;
1009   M17N_OBJECT_REGISTER (mtext_table, mt);
1010   return mt;
1011 }
1012
1013 /***en
1014     @brief Allocate a new M-text with specified data.
1015
1016     The mtext_from_data () function allocates a new M-text whose
1017     character sequence is specified by array $DATA of $NITEMS
1018     elements.  $FORMAT specifies the format of $DATA.
1019
1020     When $FORMAT is either #MTEXT_FORMAT_US_ASCII or
1021     #MTEXT_FORMAT_UTF_8, the contents of $DATA must be of the type @c
1022     unsigned @c char, and $NITEMS counts by byte.
1023
1024     When $FORMAT is either #MTEXT_FORMAT_UTF_16LE or
1025     #MTEXT_FORMAT_UTF_16BE, the contents of $DATA must be of the type
1026     @c unsigned @c short, and $NITEMS counts by unsigned short.
1027
1028     When $FORMAT is either #MTEXT_FORMAT_UTF_32LE or
1029     #MTEXT_FORMAT_UTF_32BE, the contents of $DATA must be of the type
1030     @c unsigned, and $NITEMS counts by unsigned.
1031
1032     The character sequence of the M-text is not modifiable.  
1033     The contents of $DATA must not be modified while the M-text is alive.
1034
1035     The allocated M-text will not be freed unless the user explicitly
1036     does so with the m17n_object_free () function.  Even in that case,
1037     $DATA is not freed.
1038
1039     @return
1040     If the operation was successful, mtext_from_data () returns a
1041     pointer to the allocated M-text.  Otherwise it returns @c NULL and
1042     assigns an error code to the external variable #merror_code.  */
1043
1044 /***
1045     @errors
1046     @c MERROR_MTEXT  */
1047
1048 MText *
1049 mtext_from_data (void *data, int nitems, enum MTextFormat format)
1050 {
1051   if (nitems < 0)
1052     MERROR (MERROR_MTEXT, NULL);
1053   if (nitems == 0)
1054     {
1055       if (format == MTEXT_FORMAT_US_ASCII
1056           || format == MTEXT_FORMAT_UTF_8)
1057         {
1058           unsigned char *p = data;
1059
1060           while (*p++) nitems++;
1061         }
1062       else if (format <= MTEXT_FORMAT_UTF_16BE)
1063         {
1064           unsigned short *p = data;
1065
1066           while (*p++) nitems++;
1067         }
1068       else if (format <= MTEXT_FORMAT_UTF_32BE)
1069         {
1070           unsigned *p = data;
1071
1072           while (*p++) nitems++;
1073         }
1074       else
1075         MERROR (MERROR_MTEXT, NULL);
1076     }
1077   return mtext__from_data (data, nitems, format, 0);
1078 }
1079
1080 /*=*/
1081
1082 /***en
1083     @brief Number of characters in M-text.
1084
1085     The mtext_len () function returns the number of characters in
1086     M-text $MT.  */
1087
1088 /***ja
1089     @brief M-text Ãæ¤Îʸ»ú¿ô
1090
1091     ´Ø¿ô mtext_len () ¤Ï M-text $MT Ãæ¤Îʸ»ú¿ô¤òÊÖ¤¹¡£
1092
1093     @latexonly \IPAlabel{mtext_len} @endlatexonly  */
1094
1095 int
1096 mtext_len (MText *mt)
1097 {
1098   return (mt->nchars);
1099 }
1100
1101 /*=*/
1102
1103 /***en
1104     @brief Return the character at the specified position in an M-text.
1105
1106     The mtext_ref_char () function returns the character at $POS in
1107     M-text $MT.  If an error is detected, it returns -1 and assigns an
1108     error code to the external variable #merror_code.  */
1109
1110 /***ja
1111     @brief M-text Ãæ¤Î»ØÄꤵ¤ì¤¿°ÌÃÖ¤Îʸ»ú¤òÊÖ¤¹
1112
1113     ´Ø¿ô mtext_ref_char () ¤Ï¡¢M-text $MT ¤Î°ÌÃÖ $POS ¤Îʸ»ú¤òÊÖ¤¹¡£
1114     ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code
1115     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1116
1117     @latexonly \IPAlabel{mtext_ref_char} @endlatexonly  */
1118
1119 /***
1120     @errors
1121     @c MERROR_RANGE  */
1122
1123 int
1124 mtext_ref_char (MText *mt, int pos)
1125 {
1126   int c;
1127
1128   M_CHECK_POS (mt, pos, -1);
1129   if (mt->format <= MTEXT_FORMAT_UTF_8)
1130     {
1131       unsigned char *p = mt->data + POS_CHAR_TO_BYTE (mt, pos);
1132
1133       c = STRING_CHAR (p);
1134     }
1135   else if (mt->format <= MTEXT_FORMAT_UTF_16BE)
1136     {
1137       unsigned short *p
1138         = (unsigned short *) (mt->data) + POS_CHAR_TO_BYTE (mt, pos);
1139
1140       if (mt->format == default_utf_16)
1141         c = STRING_CHAR_UTF16 (p);
1142       else
1143         {
1144           c = (*p >> 8) | ((*p & 0xFF) << 8);
1145           if (c >= 0xD800 && c < 0xE000)
1146             {
1147               int c1 = (p[1] >> 8) | ((p[1] & 0xFF) << 8);
1148               c = ((c - 0xD800) << 10) + (c1 - 0xDC00) + 0x10000;
1149             }
1150         }
1151     }
1152   else
1153     {
1154       unsigned *p = (unsigned *) (mt->data) + POS_CHAR_TO_BYTE (mt, pos);
1155
1156       if (mt->format == default_utf_32)
1157         c = *p;
1158       else
1159         c = SWAP_32 (*p);
1160     }
1161   return c;
1162 }
1163
1164 /*=*/
1165
1166 /***en
1167     @brief Store a character into an M-text.
1168
1169     The mtext_set_char () function sets character $C, which has no
1170     text properties, at $POS in M-text $MT.
1171
1172     @return
1173     If the operation was successful, mtext_set_char () returns 0.
1174     Otherwise it returns -1 and assigns an error code to the external
1175     variable #merror_code.  */
1176
1177 /***ja
1178     @brief M-text ¤Ë°ìʸ»ú¤òÀßÄꤹ¤ë
1179
1180     ´Ø¿ô mtext_set_char () ¤Ï¡¢¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£Ìµ¤·¤Îʸ»ú $C ¤ò 
1181     M-text $MT ¤Î $POS ¤Î°ÌÃÖ¤ËÀßÄꤹ¤ë¡£
1182
1183     @return
1184     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mtext_set_char () ¤Ï 0 ¤òÊÖ¤¹¡£¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ
1185     ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1186
1187     @latexonly \IPAlabel{mtext_set_char} @endlatexonly  */
1188
1189 /***
1190     @errors
1191     @c MERROR_RANGE */
1192
1193 int
1194 mtext_set_char (MText *mt, int pos, int c)
1195 {
1196   int byte_pos;
1197   int bytes_old, bytes_new;
1198   int delta;
1199   unsigned char str[MAX_UTF8_CHAR_BYTES];
1200   unsigned char *p;
1201   int i;
1202
1203   M_CHECK_POS (mt, pos, -1);
1204   M_CHECK_READONLY (mt, -1);
1205
1206   byte_pos = POS_CHAR_TO_BYTE (mt, pos);
1207   p = mt->data + byte_pos;
1208   bytes_old = CHAR_BYTES_AT (p);
1209   bytes_new = CHAR_STRING (c, str);
1210   delta = bytes_new - bytes_old;
1211
1212   /* mtext__adjust_plist_for_change (mt, pos, pos + 1);*/
1213
1214   if (delta)
1215     {
1216       int byte_pos_old = byte_pos + bytes_old;
1217       int byte_pos_new = byte_pos + bytes_new;
1218
1219       if (mt->cache_char_pos > pos)
1220         mt->cache_byte_pos += delta;
1221
1222       if ((mt->allocated - mt->nbytes) <= delta)
1223         {
1224           mt->allocated = mt->nbytes + delta + 1;
1225           MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
1226         }
1227
1228       memmove (mt->data + byte_pos_old, mt->data + byte_pos_new,
1229                mt->nbytes - byte_pos_old);
1230       mt->nbytes += delta;
1231       mt->data[mt->nbytes] = 0;
1232     }
1233   for (i = 0; i < bytes_new; i++)
1234     mt->data[byte_pos + i] = str[i];
1235   return 0;
1236 }
1237
1238 /*=*/
1239
1240 /***en
1241     @brief  Append a character to an M-text.
1242
1243     The mtext_cat_char () function appends character $C, which has no
1244     text properties, to the end of M-text $MT.
1245
1246     @return
1247     This function returns a pointer to the resulting M-text $MT.  If
1248     $C is an invalid character, it returns @c NULL.  */
1249
1250 /***ja
1251     @brief M-text ¤Ë°ìʸ»úÄɲ乤ë
1252
1253     ´Ø¿ô mtext_cat_char () ¤Ï¡¢¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£Ìµ¤·¤Îʸ»ú $C ¤ò 
1254     M-text $MT ¤ÎËöÈø¤ËÄɲ乤롣
1255
1256     @return
1257     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$C ¤¬Àµ¤·¤¤Ê¸
1258     »ú¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï @c NULL ¤òÊÖ¤¹¡£  */
1259
1260 /***
1261     @seealso
1262     mtext_cat (), mtext_ncat ()  */
1263
1264 MText *
1265 mtext_cat_char (MText *mt, int c)
1266 {
1267   unsigned char buf[MAX_UTF8_CHAR_BYTES];
1268   int nbytes;
1269   int total_bytes;
1270
1271   M_CHECK_READONLY (mt, NULL);
1272   if (c < 0 || c > MCHAR_MAX)
1273     return NULL;
1274   nbytes = CHAR_STRING (c, buf);
1275
1276   total_bytes = mt->nbytes + nbytes;
1277
1278   mtext__adjust_plist_for_insert (mt, mt->nchars, 1, NULL);
1279
1280   if (total_bytes >= mt->allocated)
1281     {
1282       mt->allocated = total_bytes + 1;
1283       MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
1284     }
1285   memcpy (mt->data + mt->nbytes, buf, nbytes);
1286   mt->nbytes = total_bytes;
1287   mt->nchars++;
1288   mt->data[total_bytes] = 0;
1289   return mt;
1290 }
1291
1292 /*=*/
1293
1294 /***en
1295     @brief  Create a copy of an M-text.
1296
1297     The mtext_dup () function creates a copy of M-text $MT while
1298     inheriting all the text properties of $MT.
1299
1300     @return
1301     This function returns a pointer to the created copy.  */
1302
1303 /***ja
1304     @brief M-text ¤Î¥³¥Ô¡¼¤òºî¤ë
1305
1306     ´Ø¿ô mtext_dup () ¤Ï¡¢M-text $MT ¤Î¥³¥Ô¡¼¤òºî¤ë¡£$MT ¤Î¥Æ¥­¥¹¥È¥×
1307     ¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£
1308
1309     @return
1310     ¤³¤Î´Ø¿ô¤Ïºî¤é¤ì¤¿¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1311
1312      @latexonly \IPAlabel{mtext_dup} @endlatexonly  */
1313
1314 /***
1315     @seealso
1316     mtext_duplicate ()  */
1317
1318 MText *
1319 mtext_dup (MText *mt)
1320 {
1321   return copy (mtext (), 0, mt, 0, mt->nchars);
1322 }
1323
1324 /*=*/
1325
1326 /***en
1327     @brief  Append an M-text to another.
1328
1329     The mtext_cat () function appends M-text $MT2 to the end of M-text
1330     $MT1 while inheriting all the text properties.  $MT2 itself is not
1331     modified.
1332
1333     @return
1334     This function returns a pointer to the resulting M-text $MT1.  */
1335
1336 /***ja
1337     @brief 2¸Ä¤Î M-text¤òÏ¢·ë¤¹¤ë
1338
1339     ´Ø¿ô mtext_cat () ¤Ï¡¢ M-text $MT2 ¤ò M-text $MT1 ¤ÎËöÈø¤ËÉÕ¤±²Ã¤¨
1340     ¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê
1341     ¤¤¡£
1342
1343     @return
1344     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1345
1346     @latexonly \IPAlabel{mtext_cat} @endlatexonly  */
1347
1348 /***
1349     @seealso
1350     mtext_ncat (), mtext_cat_char ()  */
1351
1352 MText *
1353 mtext_cat (MText *mt1, MText *mt2)
1354 {
1355   M_CHECK_READONLY (mt1, NULL);
1356
1357   return copy (mt1, mt1->nchars, mt2, 0, mt2->nchars);
1358 }
1359
1360
1361 /*=*/
1362
1363 /***en
1364     @brief Append a part of an M-text to another.
1365
1366     The mtext_ncat () function appends the first $N characters of
1367     M-text $MT2 to the end of M-text $MT1 while inheriting all the
1368     text properties.  If the length of $MT2 is less than $N, all
1369     characters are copied.  $MT2 is not modified.  
1370
1371     @return
1372     If the operation was successful, mtext_ncat () returns a pointer
1373     to the resulting M-text $MT1.  If an error is detected, it returns
1374     @c NULL and assigns an error code to the global variable @c
1375     merror_code.  */
1376
1377
1378 /***ja
1379     @brief M-text ¤Î°ìÉô¤òÊ̤ΠM-text ¤ËÉղ乤ë
1380
1381     ´Ø¿ô mtext_ncat () ¤Ï¡¢M-text $MT2 ¤Î¤Ï¤¸¤á¤Î $N Ê¸»ú¤ò M-text
1382     $MT1 ¤ÎËöÈø¤ËÉÕ¤±²Ã¤¨¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì
1383     ¤ë¡£$MT2 ¤ÎŤµ¤¬ $N °Ê²¼¤Ê¤é¤Ð¡¢$MT2 ¤Î¤¹¤Ù¤Æ¤Îʸ»ú¤¬Éղ䵤ì¤ë¡£
1384     $N ¤¬Éé¤Î¾ì¹ç¡¢$MT1 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1385     $MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1386
1387     @return
1388     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_ncat () ¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 ¤Ø¤Î¥Ý
1389     ¥¤¥ó¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô @c
1390     merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1391
1392     @latexonly \IPAlabel{mtext_ncat} @endlatexonly  */
1393
1394 /***
1395     @errors
1396     @c MERROR_RANGE
1397
1398     @seealso
1399     mtext_cat (), mtext_cat_char ()  */
1400
1401 MText *
1402 mtext_ncat (MText *mt1, MText *mt2, int n)
1403 {
1404   M_CHECK_READONLY (mt1, NULL);
1405   if (n < 0)
1406     MERROR (MERROR_RANGE, NULL);
1407   return copy (mt1, mt1->nchars, mt2, 0, mt2->nchars < n ? mt2->nchars : n);
1408 }
1409
1410
1411 /*=*/
1412
1413 /***en
1414     @brief Copy an M-text to another.
1415
1416     The mtext_cpy () function copies M-text $MT2 to M-text $MT1 while
1417     inheriting all the text properties.  The old text in $MT1 is
1418     overwritten and the length of $MT1 is extended if necessary.  $MT2
1419     is not modified.
1420
1421     @return
1422     This function returns a pointer to the resulting M-text $MT1.  */
1423
1424 /***ja
1425     @brief M-text ¤ò¥³¥Ô¡¼¤¹¤ë
1426
1427     ´Ø¿ô mtext_cpy () ¤Ï M-text $MT2 ¤ò M-text $MT1 ¤Ë¾å½ñ¤­¥³¥Ô¡¼¤¹¤ë¡£
1428     $MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT1 ¤ÎŤµ¤ÏɬÍפ˱þ
1429     ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1430
1431     @return
1432     ¤³¤Î´Ø¿ô¤ÏÊѹ¹¤µ¤ì¤¿ M-text $MT1 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1433
1434     @latexonly \IPAlabel{mtext_cpy} @endlatexonly  */
1435
1436 /***
1437     @seealso
1438     mtext_ncpy (), mtext_copy ()  */
1439
1440 MText *
1441 mtext_cpy (MText *mt1, MText *mt2)
1442 {
1443   M_CHECK_READONLY (mt1, NULL);
1444   return copy (mt1, 0, mt2, 0, mt2->nchars);
1445 }
1446
1447 /*=*/
1448
1449 /***en
1450     @brief Copy the first some characters in an M-text to another.
1451
1452     The mtext_ncpy () function copies the first $N characters of
1453     M-text $MT2 to M-text $MT1 while inheriting all the text
1454     properties.  If the length of $MT2 is less than $N, all characters
1455     of $MT2 are copied.  The old text in $MT1 is overwritten and the
1456     length of $MT1 is extended if necessary.  $MT2 is not modified.
1457
1458     @return
1459     If the operation was successful, mtext_ncpy () returns a pointer
1460     to the resulting M-text $MT1.  If an error is detected, it returns
1461     @c NULL and assigns an error code to the global variable @c
1462     merror_code.  */
1463
1464 /***ja
1465     @brief M-text ¤Ë´Þ¤Þ¤ì¤ëºÇ½é¤Î²¿Ê¸»ú¤«¤ò¥³¥Ô¡¼¤¹¤ë
1466
1467     ´Ø¿ô mtext_ncpy () ¤Ï¡¢M-text $MT2 ¤ÎºÇ½é¤Î $N Ê¸»ú¤ò M-text $MT1 
1468     ¤Ë¾å½ñ¤­¥³¥Ô¡¼¤¹¤ë¡£¤â¤· $MT2 ¤ÎŤµ¤¬ $N ¤è¤ê¤â¾®¤µ¤±¤ì¤Ð $MT2 ¤Î
1469     ¤¹¤Ù¤Æ¤Îʸ»ú¤ò¥³¥Ô¡¼¤¹¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ
1470     ¤ì¤ë¡£$MT1 ¤ÎŤµ¤ÏɬÍפ˱þ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1471
1472     @return
1473     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_ncpy () ¤ÏÊѹ¹¤µ¤ì¤¿ M-text$MT1 ¤Ø¤Î¥Ý¥¤
1474     ¥ó¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô @c
1475     merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1476
1477     @latexonly \IPAlabel{mtext_ncpy} @endlatexonly  */
1478
1479 /***
1480     @errors
1481     @c MERROR_RANGE
1482
1483     @seealso
1484     mtext_cpy (), mtext_copy ()  */
1485
1486 MText *
1487 mtext_ncpy (MText *mt1, MText *mt2, int n)
1488 {
1489   M_CHECK_READONLY (mt1, NULL);
1490   if (n < 0)
1491     MERROR (MERROR_RANGE, NULL);
1492   return (copy (mt1, 0, mt2, 0, mt2->nchars < n ? mt2->nchars : n));
1493 }
1494
1495 /*=*/
1496
1497 /***en
1498     @brief Create a new M-text from a part of an existing M-text.
1499
1500     The mtext_duplicate () function creates a copy of sub-text of
1501     M-text $MT, starting at $FROM (inclusive) and ending at $TO
1502     (exclusive) while inheriting all the text properties of $MT.  $MT
1503     itself is not modified.
1504
1505     @return
1506     If the operation was successful, mtext_duplicate () returns a
1507     pointer to the created M-text.  If an error is detected, it returns 0
1508     and assigns an error code to the external variable #merror_code.  */
1509
1510 /***ja
1511     @brief M-text ¤Î°ìÉô¤«¤é¿·¤·¤¤ M-text ¤ò¤Ä¤¯¤ë
1512
1513     ´Ø¿ô mtext_duplicate () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê´Þ¤à¡Ë¤«¤é $TO 
1514     ¡Ê´Þ¤Þ¤Ê¤¤¡Ë¤Þ¤Ç¤ÎÉôʬʸ»úÎó¤Î¥³¥Ô¡¼¤òºî¤ë¡£¤³¤Î¤È¤­ $MT ¤Î¥Æ¥­¥¹
1515     ¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT ¤½¤Î¤â¤Î¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1516
1517     @return
1518     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_duplicate () ¤Ïºî¤é¤ì¤¿ M-text ¤Ø¤Î¥Ý¥¤¥ó
1519     ¥¿¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code 
1520     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1521
1522     @latexonly \IPAlabel{mtext_duplicate} @endlatexonly  */
1523
1524 /***
1525     @errors
1526     @c MERROR_RANGE
1527
1528     @seealso
1529     mtext_dup ()  */
1530
1531 MText *
1532 mtext_duplicate (MText *mt, int from, int to)
1533 {
1534   MText *new = mtext ();
1535
1536   M_CHECK_RANGE (mt, from, to, NULL, new);
1537   return copy (new, 0, mt, from, to);
1538 }
1539
1540 /*=*/
1541
1542 /***en
1543     @brief Copy characters in the specified range into an M-text.
1544
1545     The mtext_copy () function copies the text between $FROM
1546     (inclusive) and $TO (exclusive) in M-text $MT2 to the region
1547     starting at $POS in M-text $MT1 while inheriting the text
1548     properties.  The old text in $MT1 is overwritten and the length of
1549     $MT1 is extended if necessary.  $MT2 is not modified.
1550
1551     @return
1552     If the operation was successful, mtext_copy () returns a pointer
1553     to the modified $MT1.  Otherwise, it returns @c NULL and assigns
1554     an error code to the external variable #merror_code.  */
1555
1556 /***ja
1557     @brief M-text ¤Î»ØÄêÈϰϤÎʸ»ú¤ò¥³¥Ô¡¼¤¹¤ë
1558
1559     ´Ø¿ô mtext_copy () ¤Ï¡¢ M-text $MT2 ¤Î $FROM ¡Ê´Þ¤à¡Ë¤«¤é $TO ¡Ê´Þ
1560     ¤Þ¤Ê¤¤¡Ë¤Þ¤Ç¤ÎÈϰϤΥƥ­¥¹¥È¤ò M-text $MT1 ¤Î°ÌÃÖ $POS ¤«¤é¾å½ñ¤­
1561     ¥³¥Ô¡¼¤¹¤ë¡£$MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT1 ¤ÎĹ
1562     ¤µ¤ÏɬÍפ˱þ¤¸¤Æ¿­¤Ð¤µ¤ì¤ë¡£$MT2 ¤ÏÊѹ¹¤µ¤ì¤Ê¤¤¡£
1563
1564     @latexonly \IPAlabel{mtext_copy} @endlatexonly
1565
1566     @return
1567     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mtext_copy () ¤ÏÊѹ¹¤µ¤ì¤¿ $MT1 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò
1568     ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼
1569     ¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1570
1571 /***
1572     @errors
1573     @c MERROR_RANGE
1574
1575     @seealso
1576     mtext_cpy (), mtext_ncpy ()  */
1577
1578 MText *
1579 mtext_copy (MText *mt1, int pos, MText *mt2, int from, int to)
1580 {
1581   M_CHECK_POS_X (mt1, pos, NULL);
1582   M_CHECK_READONLY (mt1, NULL);
1583   M_CHECK_RANGE (mt2, from, to, NULL, mt1);
1584   return copy (mt1, pos, mt2, from, to);
1585 }
1586
1587 /*=*/
1588
1589
1590 /***en
1591     @brief Delete characters in the specified range destructively.
1592
1593     The mtext_del () function deletes the characters in the range
1594     $FROM (inclusive) and $TO (exclusive) from M-text $MT
1595     destructively.  As a result, the length of $MT shrinks by ($TO -
1596     $FROM) characters.
1597
1598     @return
1599     If the operation was successful, mtext_del () returns 0.
1600     Otherwise, it returns -1 and assigns an error code to the external
1601     variable #merror_code.  */
1602
1603 /***ja
1604     @brief »ØÄêÈϰϤÎʸ»ú¤òÇ˲õŪ¤Ë¼è¤ê½ü¤¯
1605
1606     ´Ø¿ô mtext_del () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê´Þ¤à¡Ë¤«¤é $TO ¡Ê´Þ¤Þ
1607     ¤Ê¤¤¡Ë¤Þ¤Ç¤Îʸ»ú¤òÇ˲õŪ¤Ë¼è¤ê½ü¤¯¡£·ë²ÌŪ¤Ë $MT ¤ÏŤµ¤¬ ($TO @c
1608     - $FROM) ¤À¤±½Ì¤à¤³¤È¤Ë¤Ê¤ë¡£
1609
1610     @return
1611     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_del () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ
1612     ¤·¡¢Æ±»þ¤Ë³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1613
1614 /***
1615     @errors
1616     @c MERROR_RANGE
1617
1618     @seealso
1619     mtext_ins ()  */
1620
1621 int
1622 mtext_del (MText *mt, int from, int to)
1623 {
1624   int from_byte, to_byte;
1625
1626   M_CHECK_READONLY (mt, -1);
1627   M_CHECK_RANGE (mt, from, to, -1, 0);
1628
1629   from_byte = POS_CHAR_TO_BYTE (mt, from);
1630   to_byte = POS_CHAR_TO_BYTE (mt, to);
1631
1632   if (mt->cache_char_pos >= to)
1633     {
1634       mt->cache_char_pos -= to - from;
1635       mt->cache_byte_pos -= to_byte - from_byte;
1636     }
1637   else if (mt->cache_char_pos > from)
1638     {
1639       mt->cache_char_pos -= from;
1640       mt->cache_byte_pos -= from_byte;
1641     }
1642
1643   mtext__adjust_plist_for_delete (mt, from, to - from);
1644   memmove (mt->data + from_byte, mt->data + to_byte, mt->nbytes - to_byte + 1);
1645   mt->nchars -= (to - from);
1646   mt->nbytes -= (to_byte - from_byte);
1647   mt->cache_char_pos = from;
1648   mt->cache_byte_pos = from_byte;
1649   return 0;
1650 }
1651
1652
1653 /*=*/
1654
1655 /***en
1656     @brief Insert an M-text into another M-text.
1657
1658     The mtext_ins () function inserts M-text $MT2 into M-text $MT1, at
1659     position $POS.  As a result, $MT1 is lengthen by the length of
1660     $MT2.  On insertion, all the text properties of $MT2 are
1661     inherited.  The original $MT2 is not modified.
1662
1663     @return
1664     If the operation was successful, mtext_ins () returns 0.
1665     Otherwise, it returns -1 and assigns an error code to the external
1666     variable #merror_code.  */
1667
1668 /***ja
1669     @brief M-text ¤òÊ̤ΠM-text ¤ËÁÞÆþ¤¹¤ë
1670
1671     ´Ø¿ô mtext_ins () ¤Ï M-text $MT1 ¤Î $POS ¤Î°ÌÃ֤ˠÊ̤ΠM-text $MT2 
1672     ¤òÁÞÆþ¤¹¤ë¡£¤³¤Î·ë²Ì $MT1 ¤ÎŤµ¤Ï $MT2 ¤Î¤Ö¤ó¤À¤±Áý¤¨¤ë¡£ÁÞÆþ¤ÎºÝ¡¢
1673     $MT2 ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ·Ñ¾µ¤µ¤ì¤ë¡£$MT2 ¤½¤Î¤â¤Î¤ÏÊѹ¹¤µ
1674     ¤ì¤Ê¤¤¡£
1675
1676     @return
1677     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_ins () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ
1678     ¤·¡¢Æ±»þ¤Ë³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1679
1680 /***
1681     @errors
1682     @c MERROR_RANGE
1683
1684     @seealso
1685     mtext_del ()  */
1686
1687 int
1688 mtext_ins (MText *mt1, int pos, MText *mt2)
1689 {
1690   int byte_pos;
1691   int total_bytes;
1692
1693   M_CHECK_READONLY (mt1, -1);
1694   M_CHECK_POS_X (mt1, pos, -1);
1695
1696   if (mt2->nchars == 0)
1697     return 0;
1698   mtext__adjust_plist_for_insert
1699     (mt1, pos, mt2->nchars,
1700      mtext__copy_plist (mt2->plist, 0, mt2->nchars, mt1, pos));
1701
1702   total_bytes = mt1->nbytes + mt2->nbytes;
1703   if (total_bytes >= mt1->allocated)
1704     {
1705       mt1->allocated = total_bytes + 1;
1706       MTABLE_REALLOC (mt1->data, mt1->allocated, MERROR_MTEXT);
1707     }
1708   byte_pos = POS_CHAR_TO_BYTE (mt1, pos);
1709   if (mt1->cache_char_pos > pos)
1710     {
1711       mt1->cache_char_pos += mt2->nchars;
1712       mt1->cache_byte_pos += mt2->nbytes;
1713     }
1714   memmove (mt1->data + byte_pos + mt2->nbytes, mt1->data + byte_pos,
1715            mt1->nbytes - byte_pos + 1);
1716   memcpy (mt1->data + byte_pos, mt2->data, mt2->nbytes);
1717   mt1->nbytes += mt2->nbytes;
1718   mt1->nchars += mt2->nchars;
1719   return 0;
1720 }
1721
1722
1723 int
1724 mtext_ins_char (MText *mt, int pos, int c, int n)
1725 {
1726   int byte_pos;
1727   int nbytes, total_bytes;
1728   unsigned char *buf;
1729   int i;
1730
1731   M_CHECK_READONLY (mt, -1);
1732   M_CHECK_POS_X (mt, pos, -1);
1733   if (c < 0 || c > MCHAR_MAX)
1734     MERROR (MERROR_MTEXT, -1);
1735   if (n <= 0)
1736     return 0;
1737   mtext__adjust_plist_for_insert (mt, pos, n, NULL);
1738   buf = alloca (MAX_UTF8_CHAR_BYTES * n);
1739   for (i = 0, nbytes = 0; i < n; i++)
1740     nbytes += CHAR_STRING (c, buf + nbytes);
1741   total_bytes = mt->nbytes + nbytes;
1742   if (total_bytes >= mt->allocated)
1743     {
1744       mt->allocated = total_bytes + 1;
1745       MTABLE_REALLOC (mt->data, mt->allocated, MERROR_MTEXT);
1746     }
1747   byte_pos = POS_CHAR_TO_BYTE (mt, pos);
1748   if (mt->cache_char_pos > pos)
1749     {
1750       mt->cache_char_pos++;
1751       mt->cache_byte_pos += nbytes;
1752     }
1753   memmove (mt->data + byte_pos + nbytes, mt->data + byte_pos,
1754            mt->nbytes - byte_pos + 1);
1755   memcpy (mt->data + byte_pos, buf, nbytes);
1756   mt->nbytes += nbytes;
1757   mt->nchars += n;
1758   return 0;
1759 }
1760
1761 /*=*/
1762
1763 /***en
1764     @brief Search a character in an M-text.
1765
1766     The mtext_character () function searches M-text $MT for character
1767     $C.  If $FROM < $TO, search begins at position $FROM and goes
1768     forward but does not exceed ($TO - 1).  Otherwise, search begins
1769     at position ($FROM - 1) and goes backward but does not exceed $TO.
1770     An invalid position specification is regarded as both $FROM and
1771     $TO being 0.
1772
1773     @return
1774     If $C is found, mtext_character () returns the position of its
1775     first occurrence.  Otherwise it returns -1 without changing the
1776     external variable #merror_code.  If an error is detected, it returns -1 and
1777     assigns an error code to the external variable #merror_code.  */
1778
1779 /***ja
1780     @brief M-text Ãæ¤ÎÆÃÄê¤Îʸ»ú¤òõ¤¹
1781
1782     ´Ø¿ô mtext_character () ¤Ï M-text $MT Ãæ¤Ë¤ª¤±¤ëʸ»ú $C ¤Î½Ð¸½°ÌÃÖ
1783     ¤òÄ´¤Ù¤ë¡£¤â¤· $FROM < $TO ¤Ê¤é¤Ð¡¢Ãµº÷¤Ï°ÌÃÖ $FROM ¤«¤éËöÈøÊý¸þ¤Ø¡¢
1784     ºÇÂç ($TO - 1) ¤Þ¤Ç¿Ê¤à¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð°ÌÃÖ ($FROM - 1) ¤«¤éÀèƬÊý
1785     ¸þ¤Ø¡¢ºÇÂç $TO ¤Þ¤Ç¿Ê¤à¡£°ÌÃ֤λØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢$FROM ¤È 
1786     $TO ¤ÎξÊý¤Ë 0 ¤¬»ØÄꤵ¤ì¤¿¤â¤Î¤È¸«¤Ê¤¹¡£
1787
1788     @return
1789     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_character () ¤Ï¤½¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤òÊÖ
1790     ¤¹¡£¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï³°ÉôÊÑ¿ô #merror_code ¤òÊѹ¹¤»¤º¤Ë -1 ¤òÊÖ
1791     ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼
1792     ¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1793
1794 /***
1795     @seealso
1796     mtext_chr(), mtext_rchr ()  */
1797
1798 int
1799 mtext_character (MText *mt, int from, int to, int c)
1800 {
1801   if (from < to)
1802     {
1803       /* We do not use M_CHECK_RANGE () because this function should
1804          not set merror_code.  */
1805       if (from < 0 || to > mt->nchars)
1806         return -1;
1807       return find_char_forward (mt, from, to, c);
1808     }
1809   else
1810     {
1811       /* ditto */
1812       if (to < 0 || from > mt->nchars)
1813         return -1;
1814       return find_char_backward (mt, to, from, c);
1815     }
1816 }
1817
1818
1819 /*=*/
1820
1821 /***en
1822     @brief Return the position of the first occurrence of a
1823     character in an M-text.
1824
1825     The mtext_chr () function searches M-text $MT for character $C.
1826     Search starts from the beginning of $MT and goes toward the end.
1827
1828     @return
1829     If $C is found, mtext_chr () returns its position; otherwise it
1830     returns.  */
1831
1832 /***ja
1833     @brief M-text Ãæ¤Ç»ØÄꤵ¤ì¤¿Ê¸»ú¤¬ºÇ½é¤Ë¸½¤ì¤ë°ÌÃÖ¤òÊÖ¤¹
1834
1835     ´Ø¿ô mtext_chr () ¤Ï M-text $MT Ãæ¤Ë¤ª¤±¤ëʸ»ú $C ¤Î½Ð¸½°ÌÃÖ¤òÄ´¤Ù
1836     ¤ë¡£Ãµº÷¤Ï $MT ¤ÎÀèƬ¤«¤éËöÈøÊý¸þ¤Ë¿Ê¤à¡£
1837
1838     @return
1839     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_chr () ¤Ï¤½¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é
1840     ¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£
1841
1842     @latexonly \IPAlabel{mtext_chr} @endlatexonly  */
1843
1844 /***
1845     @errors
1846     @c MERROR_RANGE
1847
1848     @seealso
1849     mtext_rchr (), mtext_character ()  */
1850
1851 int
1852 mtext_chr (MText *mt, int c)
1853 {
1854   return find_char_forward (mt, 0, mt->nchars, c);
1855 }
1856
1857 /*=*/
1858
1859 /***en
1860     @brief Return the position of the last occurrence of a
1861     character in an M-text.
1862
1863     The mtext_rchr () function searches M-text $MT for character $C.
1864     Search starts from the end of $MT and goes backwardly toward the
1865     beginning.
1866
1867     @return
1868     If $C is found, mtext_chr () returns its position; otherwise it
1869     returns -1.  */
1870
1871 /***ja
1872     @brief M-text Ãæ¤Ç»ØÄꤵ¤ì¤¿Ê¸»ú¤¬ºÇ¸å¤Ë¸½¤ì¤ë°ÌÃÖ¤òÊÖ¤¹
1873
1874     ´Ø¿ô mtext_rchr () ¤Ï M-text $MT Ãæ¤Ë¤ª¤±¤ëʸ»ú $C ¤Î½Ð¸½°ÌÃÖ¤òÄ´
1875     ¤Ù¤ë¡£Ãµº÷¤Ï $MT ¤ÎºÇ¸å¤«¤éÀèƬÊý¸þ¤Ø¤È¸å¸þ¤­¤Ë¿Ê¤à¡£
1876
1877     @return
1878     ¤â¤· $C ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_chr () ¤Ï¤½¤Î½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¸«¤Ä¤«¤é
1879     ¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£
1880
1881     @latexonly \IPAlabel{mtext_rchr} @endlatexonly  */
1882
1883 /***
1884     @errors
1885     @c MERROR_RANGE
1886
1887     @seealso
1888     mtext_chr (), mtext_character ()  */
1889
1890 int
1891 mtext_rchr (MText *mt, int c)
1892 {
1893   return find_char_backward (mt, mt->nchars, 0, c);
1894 }
1895
1896
1897 /*=*/
1898
1899 /***en
1900     @brief Compare two M-texts character-by-character.
1901
1902     The mtext_cmp () function compares M-texts $MT1 and $MT2 character
1903     by character.
1904
1905     @return
1906     This function returns 1, 0, or -1 if $MT1 is found greater than,
1907     equal to, or less than $MT2, respectively.  Comparison is based on
1908     character codes.  */
1909
1910 /***ja
1911     @brief Æó¤Ä¤Î M-text ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë
1912
1913     ´Ø¿ô mtext_cmp () ¤Ï¡¢ M-text $MT1 ¤È $MT2 ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë¡£
1914
1915     @return
1916     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì
1917     ¤Ð 1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð¤Å
1918     ¤¯¡£
1919
1920     @latexonly \IPAlabel{mtext_cmp} @endlatexonly  */
1921
1922 /***
1923     @seealso
1924     mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
1925     mtext_compare (), mtext_case_compare ()  */
1926
1927 int
1928 mtext_cmp (MText *mt1, MText *mt2)
1929 {
1930   return compare (mt1, 0, mt1->nchars, mt2, 0, mt2->nchars);
1931 }
1932
1933
1934 /*=*/
1935
1936 /***en
1937     @brief Compare two M-texts character-by-character.
1938
1939     The mtext_ncmp () function is similar to mtext_cmp (), but
1940     compares at most $N characters from the beginning.
1941
1942     @return
1943     This function returns 1, 0, or -1 if $MT1 is found greater than,
1944     equal to, or less than $MT2, respectively.  */
1945
1946 /***ja
1947     @brief Æó¤Ä¤Î M-text ¤òʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë
1948
1949     ´Ø¿ô mtext_ncmp () ¤Ï¡¢´Ø¿ô mtext_cmp () Æ±ÍͤΠM-text Æ±»Î¤ÎÈæ³Ó
1950     ¤òÀèƬ¤«¤éºÇÂç $N Ê¸»ú¤Þ¤Ç¤Ë´Ø¤·¤Æ¹Ô¤Ê¤¦¡£
1951
1952     @return
1953     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì
1954     ¤Ð 1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
1955
1956     @latexonly \IPAlabel{mtext_ncmp} @endlatexonly  */
1957
1958 /***
1959     @seealso
1960     mtext_cmp (), mtext_casecmp (), mtext_ncasecmp ()
1961     mtext_compare (), mtext_case_compare ()  */
1962
1963 int
1964 mtext_ncmp (MText *mt1, MText *mt2, int n)
1965 {
1966   if (n < 0)
1967     return 0;
1968   return compare (mt1, 0, (mt1->nchars < n ? mt1->nchars : n),
1969                   mt2, 0, (mt2->nchars < n ? mt2->nchars : n));
1970 }
1971
1972 /*=*/
1973
1974 /***en
1975     @brief Compare two M-texts.
1976
1977     The mtext_compare () function compares two M-texts $MT1 and $MT2,
1978     character-by-character.  The compared regions are between $FROM1
1979     and $TO1 in $MT1 and $FROM2 to $TO2 in MT2.  $FROM1 and $FROM2 are
1980     inclusive, $TO1 and $TO2 are exclusive.  $FROM1 being equal to
1981     $TO1 (or $FROM2 being equal to $TO2) means an M-text of length
1982     zero.  An invalid region specification is regarded as both $FROM1
1983     and $TO1 (or $FROM2 and $TO2) being 0.
1984
1985     @return
1986     This function returns 1, 0, or -1 if $MT1 is found greater than,
1987     equal to, or less than $MT2, respectively.  Comparison is based on
1988     character codes.  */
1989
1990 /***ja
1991     @brief Æó¤Ä¤Î M-text ¤òÈæ³Ó¤¹¤ë
1992
1993     ´Ø¿ô mtext_compare () ¤ÏÆó¤Ä¤Î M-text $MT1 ¤È $MT2 ¤òʸ»úñ°Ì¤ÇÈæ
1994     ³Ó¤¹¤ë¡£Èæ³ÓÂоݤȤʤë¤Î¤Ï $MT1 ¤Ç¤Ï $FROM1 ¤«¤é $TO1 ¤Þ¤Ç¡¢$MT2 
1995     ¤Ç¤Ï $FROM2 ¤«¤é $TO2 ¤Þ¤Ç¤Ç¤¢¤ë¡£$FROM1 ¤È $FROM2 ¤Ï´Þ¤Þ¤ì¡¢$TO1 
1996     ¤È $TO2 ¤Ï´Þ¤Þ¤ì¤Ê¤¤¡£$FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 ¡Ë
1997     ¤¬Åù¤·¤¤¾ì¹ç¤ÏŤµ¥¼¥í¤Î M-text ¤ò°ÕÌ£¤¹¤ë¡£ÈÏ°Ï»ØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì
1998     ¹ç¤Ï¡¢$FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 ¡Ë Î¾Êý¤Ë 0 ¤¬»ØÄꤵ
1999     ¤ì¤¿¤â¤Î¤È¸«¤Ê¤¹¡£
2000
2001     @return
2002     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì
2003     ¤Ð 1 ¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð
2004     ¤Å¤¯¡£  */
2005
2006 /***
2007     @seealso
2008     mtext_cmp (), mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
2009     mtext_case_compare ()  */
2010
2011 int
2012 mtext_compare (MText *mt1, int from1, int to1, MText *mt2, int from2, int to2)
2013 {
2014   if (from1 < 0 || from1 > to1 || to1 > mt1->nchars)
2015     from1 = to1 = 0;
2016
2017   if (from2 < 0 || from2 > to2 || to2 > mt2->nchars)
2018     from2 = to2 = 0;
2019
2020   return compare (mt1, from1, to1, mt2, from2, to2);
2021 }
2022
2023 /*=*/
2024
2025 /***en
2026     @brief Search an M-text for a set of characters.
2027
2028     The mtext_spn () function returns the length of the initial
2029     segment of M-text $MT1 that consists entirely of characters in
2030     M-text $MT2.  */
2031
2032 /***ja
2033     @brief ¤¢¤ëʸ»ú¤Î½¸¹ç¤ò M-text ¤ÎÃæ¤Çõ¤¹
2034
2035     ´Ø¿ô mtext_spn () ¤Ï¡¢M-text $MT1 ¤ÎÀèƬÉôʬ¤Ç M-text $MT2 ¤Ë´Þ¤Þ
2036     ¤ì¤ëʸ»ú¤À¤±¤Ç¤Ç¤­¤Æ¤¤¤ëÉôʬ¤ÎºÇÂ獵¤ò·×»»¤¹¤ë¡£
2037
2038     @latexonly \IPAlabel{mtext_spn} @endlatexonly  */
2039
2040 /***
2041     @seealso
2042     mtext_cspn ()  */
2043
2044 int
2045 mtext_spn (MText *mt, MText *accept)
2046 {
2047   return span (mt, accept, 0, Mnil);
2048 }
2049
2050 /*=*/
2051
2052 /***en
2053     @brief Search an M-text for the complement of a set of characters.
2054
2055     The mtext_cspn () returns the length of the initial segment of
2056     M-text $MT1 that consists entirely of characters not in M-text $MT2.  */
2057
2058 /***ja
2059     @brief ¤¢¤ë½¸¹ç¤Ë°¤µ¤Ê¤¤Ê¸»ú¤ò M-text ¤ÎÃæ¤Çõ¤¹
2060
2061     ´Ø¿ô mtext_cspn () ¤Ï¡¢M-text $MT1 ¤ÎÀèƬÉôʬ¤Ç M-text $MT2 ¤Ë´Þ¤Þ
2062     ¤ì¤Ê¤¤Ê¸»ú¤À¤±¤Ç¤Ç¤­¤Æ¤¤¤ëÉôʬ¤ÎºÇÂ獵¤òÊÖ¤¹¡£
2063
2064     @latexonly \IPAlabel{mtext_cspn} @endlatexonly  */
2065
2066 /***
2067     @seealso
2068     mtext_spn ()  */
2069
2070 int
2071 mtext_cspn (MText *mt, MText *reject)
2072 {
2073   return span (mt, reject, 0, Mt);
2074 }
2075
2076 /*=*/
2077
2078 /***en
2079     @brief Search an M-text for any of a set of characters
2080
2081     The mtext_pbrk () function locates the first occurrence in M-text
2082     $MT1 of any of the characters in M-text $MT2.
2083
2084     @return
2085     This function returns the position in $MT1 of the found character.
2086     If no such character is found, it returns -1. */
2087
2088 /***ja
2089     @brief Ê̤ΠM-text ¤Ë´Þ¤Þ¤ì¤ëʸ»ú¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤ò¸«¤Ä¤±¤ë
2090
2091     ´Ø¿ô mtext_pbrk () ¤Ï¡¢M-text $MT1 Ãæ¤Ç M-text $MT2 ¤Î¤¤¤º¤ì¤«¤Îʸ
2092     »ú¤¬ºÇ½é¤Ë¸½¤ì¤ë°ÌÃÖ¤òÄ´¤Ù¤ë¡£
2093
2094     @return
2095     ¸«¤Ä¤«¤Ã¤¿Ê¸»ú¤Î¡¢$MT1 Æâ¤Ë¤ª¤±¤ë½Ð¸½°ÌÃÖ¤òÊÖ¤¹¡£¤â¤·¤½¤Î¤è¤¦¤Êʸ
2096     »ú¤¬¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£
2097
2098     @latexonly \IPAlabel{mtext_pbrk} @endlatexonly  */
2099
2100 int
2101 mtext_pbrk (MText *mt, MText *accept)
2102 {
2103   int nchars = mtext_nchars (mt);
2104   int len = span (mt, accept, 0, Mt);
2105
2106   return (len == nchars ? -1 : len);
2107 }
2108
2109 /*=*/
2110
2111 /***en
2112     @brief Look for a token in an M-text
2113
2114     The mtext_tok () function searches a token that firstly occurs
2115     after position $POS in M-text $MT.  Here, a token means a
2116     substring each of which does not appear in M-text $DELIM.  Note
2117     that the type of $POS is not @c int but pointer to @c int.
2118
2119     @return
2120     If a token is found, mtext_tok () copies the corresponding part of
2121     $MT and returns a pointer to the copy.  In this case, $POS is set
2122     to the end of the found token.  If no token is found, it returns
2123     @c NULL without changing the external variable #merror_code.  If an
2124     error is detected, it returns @c NULL and assigns an error code
2125     to the external variable #merror_code. */
2126
2127 /***ja
2128     @brief M-text Ãæ¤Î¥È¡¼¥¯¥ó¤òõ¤¹
2129
2130     ´Ø¿ô mtext_tok () ¤Ï¡¢M-text $MT ¤ÎÃæ¤Ç $POS °Ê¹ßºÇ½é¤Ë¸½¤ì¤ë¥È¡¼
2131     ¥¯¥ó¤òõ¤¹¡£¤³¤³¤Ç¥È¡¼¥¯¥ó¤È¤Ï M-text $DELIM ¤ÎÃæ¤Ë¸½¤ï¤ì¤Ê¤¤Ê¸»ú
2132     ¤À¤±¤«¤é¤Ê¤ëÉôʬʸ»úÎó¤Ç¤¢¤ë¡£$POS ¤Î·¿¤¬ @c int ¤Ç¤Ï¤Ê¤¯¤Æ @c int 
2133     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¤³¤È¤ËÃí°Õ¡£
2134
2135     @return
2136     ¤â¤·¥È¡¼¥¯¥ó¤¬¸«¤Ä¤«¤ì¤Ð mtext_tok ()¤Ï¤½¤Î¥È¡¼¥¯¥ó¤ËÁêÅö¤¹¤ëÉôʬ
2137     ¤Î $MT ¤ò¥³¥Ô¡¼¤·¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢$POS ¤Ï
2138     ¸«¤Ä¤«¤Ã¤¿¥È¡¼¥¯¥ó¤Î½ªÃ¼¤Ë¥»¥Ã¥È¤µ¤ì¤ë¡£¥È¡¼¥¯¥ó¤¬¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿
2139     ¾ì¹ç¤Ï³°ÉôÊÑ¿ô #merror_code ¤òÊѤ¨¤º¤Ë @c NULL ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð
2140     ¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢ÊÑÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
2141     ÀßÄꤹ¤ë¡£
2142
2143     @latexonly \IPAlabel{mtext_tok} @endlatexonly  */
2144
2145 /***
2146     @errors
2147     @c MERROR_RANGE  */
2148
2149 MText *
2150 mtext_tok (MText *mt, MText *delim, int *pos)
2151 {
2152   int nchars = mtext_nchars (mt);
2153   int pos2;
2154
2155   M_CHECK_POS (mt, *pos, NULL);
2156
2157   /*
2158     Skip delimiters starting at POS in MT.
2159     Never do *pos += span(...), or you will change *pos
2160     even though no token is found.
2161    */
2162   pos2 = *pos + span (mt, delim, *pos, Mnil);
2163
2164   if (pos2 == nchars)
2165     return NULL;
2166
2167   *pos = pos2 + span (mt, delim, pos2, Mt);
2168   return (copy (mtext (), 0, mt, pos2, *pos));
2169 }
2170
2171 /*=*/
2172
2173 /***en
2174     @brief Locate an M-text in another.
2175
2176     The mtext_text () function finds the first occurrence of M-text
2177     $MT2 in M-text $MT1 after the position $POS while ignoring
2178     difference of the text properties.
2179
2180     @return
2181     If $MT2 is found in $MT1, mtext_text () returns the position of it
2182     first occurrence.  Otherwise it returns -1.  If $MT2 is empty, it
2183     returns 0.  */
2184
2185 /***ja
2186     @brief M-text Ãæ¤ÎÊ̤ΠM-text ¤òõ¤¹
2187
2188     ´Ø¿ô mtext_text () ¤Ï¡¢M-text $MT1 Ãæ¤Ë¤ª¤±¤ë M-text $MT2 ¤ÎºÇ½é¤Î
2189     ½Ð¸½°ÌÃÖ¤òÄ´¤Ù¤ë¡£¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î°ã¤¤¤Ï̵»ë¤µ¤ì¤ë¡£
2190
2191     @return
2192     $MT1 Ãæ¤Ë $MT2 ¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_text() ¤Ï¤½¤ÎºÇ½é¤Î½Ð¸½°ÌÃÖ¤òÊÖ
2193     ¤¹¡£¸«¤Ä¤«¤é¤Ê¤¤¾ì¹ç¤Ï -1 ¤òÊÖ¤¹¡£¤â¤· $MT2 ¤¬¶õ¤Ê¤é¤Ð 0 ¤òÊÖ¤¹¡£
2194
2195     @latexonly \IPAlabel{mtext_text} @endlatexonly  */
2196
2197 int
2198 mtext_text (MText *mt1, int pos, MText *mt2)
2199 {
2200   int from = pos;
2201   int pos_byte = POS_CHAR_TO_BYTE (mt1, pos);
2202   int c = mtext_ref_char (mt2, 0);
2203   int nbytes1 = mtext_nbytes (mt1);
2204   int nbytes2 = mtext_nbytes (mt2);
2205   int limit;
2206   int use_memcmp = (mt1->format == mt2->format
2207                     || (mt1->format < MTEXT_FORMAT_UTF_8
2208                         && mt2->format == MTEXT_FORMAT_UTF_8));
2209   int unit_bytes = (mt1->format <= MTEXT_FORMAT_UTF_8 ? 1
2210                     : mt1->format <= MTEXT_FORMAT_UTF_16BE ? 2
2211                     : 4);
2212
2213   if (nbytes2 > pos_byte + nbytes1)
2214     return -1;
2215   pos_byte = nbytes1 - nbytes2;
2216   limit = POS_BYTE_TO_CHAR (mt1, pos_byte);
2217
2218   while (1)
2219     {
2220       if ((pos = mtext_character (mt1, from, limit, c)) < 0)
2221         return -1;
2222       pos_byte = POS_CHAR_TO_BYTE (mt1, pos);
2223       if (use_memcmp
2224           ? ! memcmp (mt1->data + pos_byte * unit_bytes, 
2225                       mt2->data, nbytes2 * unit_bytes)
2226           : ! compare (mt1, pos, mt2->nchars, mt2, 0, mt2->nchars))
2227         break;
2228       from = pos + 1;
2229     }
2230   return pos;
2231 }
2232
2233 int
2234 mtext_search (MText *mt1, int from, int to, MText *mt2)
2235 {
2236   int c = mtext_ref_char (mt2, 0);
2237   int from_byte;
2238   int nbytes2 = mtext_nbytes (mt2);
2239
2240   if (mt1->format > MTEXT_FORMAT_UTF_8
2241       || mt2->format > MTEXT_FORMAT_UTF_8)
2242     MERROR (MERROR_MTEXT, -1);
2243
2244   if (from < to)
2245     {
2246       to -= mtext_nchars (mt2);
2247       if (from > to)
2248         return -1;
2249       while (1)
2250         {
2251           if ((from = find_char_forward (mt1, from, to, c)) < 0)
2252             return -1;
2253           from_byte = POS_CHAR_TO_BYTE (mt1, from);
2254           if (! memcmp (mt1->data + from_byte, mt2->data, nbytes2))
2255             break;
2256           from++;
2257         }
2258     }
2259   else if (from > to)
2260     {
2261       from -= mtext_nchars (mt2);
2262       if (from < to)
2263         return -1;
2264       while (1)
2265         {
2266           if ((from = find_char_backward (mt1, from, to, c)) < 0)
2267             return -1;
2268           from_byte = POS_CHAR_TO_BYTE (mt1, from);
2269           if (! memcmp (mt1->data + from_byte, mt2->data, nbytes2))
2270             break;
2271           from--;
2272         }
2273     }
2274
2275   return from;
2276 }
2277
2278 /*=*/
2279
2280 /***en
2281     @brief Compare two M-texts ignoring cases.
2282
2283     The mtext_casecmp () function is similar to mtext_cmp (), but
2284     ignores cases on comparison.
2285
2286     @return
2287     This function returns 1, 0, or -1 if $MT1 is found greater than,
2288     equal to, or less than $MT2, respectively.  */
2289
2290 /***ja
2291     @brief Æó¤Ä¤Î M-text ¤òÂçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤ÆÈæ³Ó¤¹¤ë
2292
2293     ´Ø¿ô mtext_casecmp () ¤Ï¡¢´Ø¿ô mtext_cmp () Æ±ÍͤΠM-text Æ±»Î¤ÎÈæ
2294     ³Ó¤ò¡¢Âçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤Æ¹Ô¤Ê¤¦¡£
2295
2296     @return
2297     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì
2298     ¤Ð 1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
2299
2300     @latexonly \IPAlabel{mtext_casecmp} @endlatexonly  */
2301
2302 /***
2303     @seealso
2304     mtext_cmp (), mtext_ncmp (), mtext_ncasecmp ()
2305     mtext_compare (), mtext_case_compare ()  */
2306
2307 int
2308 mtext_casecmp (MText *mt1, MText *mt2)
2309 {
2310   return case_compare (mt1, 0, mt1->nchars, mt2, 0, mt2->nchars);
2311 }
2312
2313 /*=*/
2314
2315 /***en
2316     @brief Compare two M-texts ignoring cases.
2317
2318     The mtext_ncasecmp () function is similar to mtext_casecmp (), but
2319     compares at most $N characters from the beginning.
2320
2321     @return
2322     This function returns 1, 0, or -1 if $MT1 is found greater than,
2323     equal to, or less than $MT2, respectively.  */
2324
2325 /***ja
2326     @brief Æó¤Ä¤Î M-text ¤òÂçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤ÆÈæ³Ó¤¹¤ë
2327
2328     ´Ø¿ô mtext_ncasecmp () ¤Ï¡¢´Ø¿ô mtext_casecmp () Æ±ÍͤΠM-text Æ±
2329     »Î¤ÎÈæ³Ó¤òÀèƬ¤«¤éºÇÂç $N Ê¸»ú¤Þ¤Ç¤Ë´Ø¤·¤Æ¹Ô¤Ê¤¦¡£
2330
2331     @return
2332     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð 0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì
2333     ¤Ð 1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
2334
2335     @latexonly \IPAlabel{mtext_ncasecmp} @endlatexonly  */
2336
2337 /***
2338     @seealso
2339     mtext_cmp (), mtext_casecmp (), mtext_casecmp ()
2340     mtext_compare (), mtext_case_compare ()  */
2341
2342 int
2343 mtext_ncasecmp (MText *mt1, MText *mt2, int n)
2344 {
2345   if (n < 0)
2346     return 0;
2347   return case_compare (mt1, 0, (mt1->nchars < n ? mt1->nchars : n),
2348                        mt2, 0, (mt2->nchars < n ? mt2->nchars : n));
2349 }
2350
2351 /*=*/
2352
2353 /***en
2354     @brief Compare two M-texts ignoring cases.
2355
2356     The mtext_case_compare () function compares two M-texts $MT1 and
2357     $MT2, character-by-character, ignoring cases.  The compared
2358     regions are between $FROM1 and $TO1 in $MT1 and $FROM2 to $TO2 in
2359     MT2.  $FROM1 and $FROM2 are inclusive, $TO1 and $TO2 are
2360     exclusive.  $FROM1 being equal to $TO1 (or $FROM2 being equal to
2361     $TO2) means an M-text of length zero.  An invalid region
2362     specification is regarded as both $FROM1 and $TO1 (or $FROM2 and
2363     $TO2) being 0.
2364
2365     @return
2366     This function returns 1, 0, or -1 if $MT1 is found greater than,
2367     equal to, or less than $MT2, respectively.  Comparison is based on
2368     character codes.  */
2369
2370 /***ja
2371     @brief Æó¤Ä¤Î M-text ¤ò¡¢Âçʸ»ú¡¿¾®Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤¿Ê¸»úñ°Ì¤ÇÈæ³Ó¤¹¤ë
2372
2373     ´Ø¿ô mtext_compare () ¤ÏÆó¤Ä¤Î M-text $MT1 ¤È $MT2 ¤ò¡¢Âçʸ»ú¡¿¾®
2374     Ê¸»ú¤Î¶èÊ̤ò̵»ë¤·¤Ä¤Äʸ»úñ°Ì¤ÇÈæ³Ó¤¹¤ë¡£Èæ³ÓÂоݤȤʤë¤Î¤Ï $MT1 
2375     ¤Ç¤Ï $FROM1 ¤«¤é $TO1 ¤Þ¤Ç¡¢$MT2 ¤Ç¤Ï $FROM2 ¤«¤é $TO2 ¤Þ¤Ç¤Ç¤¢¤ë¡£
2376     $FROM1 ¤È $FROM2 ¤Ï´Þ¤Þ¤ì¡¢$TO1 ¤È $TO2 ¤Ï´Þ¤Þ¤ì¤Ê¤¤¡£$FROM1 ¤È 
2377     $TO1 ¡Ê¤¢¤ë¤¤¤Ï $FROM2 ¤È $TO2 ¡Ë¤¬Åù¤·¤¤¾ì¹ç¤ÏŤµ¥¼¥í¤Î M-text 
2378     ¤ò°ÕÌ£¤¹¤ë¡£ÈÏ°Ï»ØÄê¤Ë¸í¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢$FROM1 ¤È $TO1 ¡Ê¤¢¤ë¤¤¤Ï 
2379     $FROM2 ¤È $TO2 ¡ËξÊý¤Ë 0 ¤¬»ØÄꤵ¤ì¤¿¤â¤Î¤È¸«¤Ê¤¹¡£
2380
2381     @return
2382     ¤³¤Î´Ø¿ô¤Ï¡¢$MT1 ¤È $MT2 ¤¬Åù¤·¤±¤ì¤Ð0¡¢$MT1 ¤¬ $MT2 ¤è¤êÂ礭¤±¤ì
2383     ¤Ð1¡¢$MT1 ¤¬ $MT2 ¤è¤ê¾®¤µ¤±¤ì¤Ð-1¤òÊÖ¤¹¡£Èæ³Ó¤Ïʸ»ú¥³¡¼¥É¤Ë´ð¤Å¤¯¡£
2384
2385   @latexonly \IPAlabel{mtext_case_compare} @endlatexonly
2386 */
2387
2388 /***
2389     @seealso
2390     mtext_cmp (), mtext_ncmp (), mtext_casecmp (), mtext_ncasecmp (),
2391     mtext_compare ()  */
2392
2393 int
2394 mtext_case_compare (MText *mt1, int from1, int to1,
2395                     MText *mt2, int from2, int to2)
2396 {
2397   if (from1 < 0 || from1 > to1 || to1 > mt1->nchars)
2398     from1 = to1 = 0;
2399
2400   if (from2 < 0 || from2 > to2 || to2 > mt2->nchars)
2401     from2 = to2 = 0;
2402
2403   return case_compare (mt1, from1, to1, mt2, from2, to2);
2404 }
2405
2406 /*** @} */
2407
2408 #include <stdio.h>
2409
2410 /*** @addtogroup m17nDebug */
2411 /*=*/
2412 /*** @{  */
2413
2414 /***en
2415     @brief Dump an M-text
2416
2417     The mdebug_dump_mtext () function prints the M-text $MT in a human
2418     readable way to the stderr.  $INDENT specifies how many columns to
2419     indent the lines but the first one.  If $FULLP is zero, this
2420     function prints only a character code sequence.  Otherwise, it
2421     prints the internal byte sequence and text properties as well.
2422
2423     @return
2424     This function returns $MT.  */
2425
2426 MText *
2427 mdebug_dump_mtext (MText *mt, int indent, int fullp)
2428 {
2429   char *prefix = (char *) alloca (indent + 1);
2430   int i;
2431   unsigned char *p;
2432
2433   memset (prefix, 32, indent);
2434   prefix[indent] = 0;
2435
2436   if (! fullp)
2437     {
2438       fprintf (stderr, "\"");
2439       for (i = 0; i < mt->nbytes; i++)
2440         {
2441           int c = mt->data[i];
2442           if (c >= ' ' && c < 127)
2443             fprintf (stderr, "%c", c);
2444           else
2445             fprintf (stderr, "\\x%02X", c);
2446         }
2447       fprintf (stderr, "\"");
2448       return mt;
2449     }
2450
2451   fprintf (stderr,
2452            "(mtext (size %d %d %d) (cache %d %d)",
2453            mt->nchars, mt->nbytes, mt->allocated,
2454            mt->cache_char_pos, mt->cache_byte_pos);
2455   if (mt->nchars > 0)
2456     {
2457       fprintf (stderr, "\n%s (bytes \"", prefix);
2458       for (i = 0; i < mt->nbytes; i++)
2459         fprintf (stderr, "\\x%02x", mt->data[i]);
2460       fprintf (stderr, "\")\n");
2461       fprintf (stderr, "%s (chars \"", prefix);
2462       p = mt->data;
2463       for (i = 0; i < mt->nchars; i++)
2464         {
2465           int len;
2466           int c = STRING_CHAR_AND_BYTES (p, len);
2467
2468           if (c >= ' ' && c < 127 && c != '\\' && c != '"')
2469             fputc (c, stderr);
2470           else
2471             fprintf (stderr, "\\x%X", c);
2472           p += len;
2473         }
2474       fprintf (stderr, "\")");
2475       if (mt->plist)
2476         {
2477           fprintf (stderr, "\n%s ", prefix);
2478           dump_textplist (mt->plist, indent + 1);
2479         }
2480     }
2481   fprintf (stderr, ")");
2482   return mt;
2483 }
2484
2485 /*** @} */ 
2486
2487 /*
2488   Local Variables:
2489   coding: euc-japan
2490   End:
2491 */