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