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