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