1 /* textprop.c -- text property module.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
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.
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.
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., 51 Franklin Street, Fifth Floor,
24 @addtogroup m17nTextProperty
25 @brief Function to handle text properties.
27 Each character in an M-text can have properties called @e text @e
28 properties. Text properties store various kinds of information
29 attached to parts of an M-text to provide application programs
30 with a unified view of those information. As rich information can
31 be stored in M-texts in the form of text properties, functions in
32 application programs can be simple.
34 A text property consists of a @e key and @e values, where key is a
35 symbol and values are anything that can be cast to <tt>(void *)
36 </tt>. Unlike other types of properties, a text property can
37 have multiple values. "The text property whose key is K" may be
38 shortened to "K property". */
41 @addtogroup m17nTextProperty
42 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÁàºî¤¹¤ë¤¿¤á¤Î´Ø¿ô.
44 M-text Æâ¤Î³Æʸ»ú¤Ï¡¢@e ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ ¤È¸Æ¤Ð¤ì¤ë¥×¥í¥Ñ¥Æ¥£¤ò
45 »ý¤Ä¤³¤È¤¬¤Ç¤¤ë¡£¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¡¢M-text ¤Î³ÆÉô°Ì¤ËÉղ䵤ì
46 ¤¿¤µ¤Þ¤¶¤Þ¤Ê¾ðÊó¤òÊÝ»ý¤·¤Æ¤ª¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¤½¤ì¤é
47 ¤Î¾ðÊó¤òÅý°ìŪ¤Ë°·¤¦¤³¤È¤¬¤Ç¤¤ë¡£M-text ¼«ÂΤ¬ËÉ٤ʾðÊó¤ò»ý¤Ä¤¿
48 ¤á¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥àÃæ¤Î´Ø¿ô¤ò´ÊÁDz½¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¡£
50 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï @e ¥¡¼ ¤È @e ÃÍ ¤«¤é¤Ê¤ë¡£¥¡¼¤Ï¥·¥ó¥Ü¥ë¤Ç¤¢
51 ¤ê¡¢ÃÍ¤Ï <tt>(void *)</tt> ·¿¤Ë¥¥ã¥¹¥È¤Ç¤¤ë¤â¤Î¤Ê¤é²¿¤Ç¤â¤è¤¤¡£
52 ¾¤Î¥¿¥¤¥×¤Î¥×¥í¥Ñ¥Æ¥£¤È°Û¤Ê¤ê¡¢°ì¤Ä¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬Ê£¿ô¤ÎÃÍ
53 ¤ò»ý¤Ä¤³¤È¤¬µö¤µ¤ì¤ë¡£¡Ö¥¡¼¤¬ K ¤Ç¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¡×¤Î¤³¤È
54 ¤ò´Êñ¤Ë¡ÖK ¥×¥í¥Ñ¥Æ¥£¡×¤È¸Æ¤Ö¤³¤È¤¬¤¢¤ë¡£ */
58 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
59 /*** @addtogroup m17nInternal
68 #include <libxml/tree.h>
69 #include <libxml/parser.h>
70 #include <libxml/xmlmemory.h>
71 #include <libxml/xpath.h>
75 #include "m17n-misc.h"
81 #define TEXT_PROP_DEBUG
84 #ifdef TEXT_PROP_DEBUG
85 #define xassert(X) do {if (!(X)) mdebug_hook ();} while (0)
87 #define xassert(X) (void) 0
88 #endif /* not FONTSET_DEBUG */
90 /* Hierarchy of objects (MText, MTextPlist, MInterval, MTextProperty)
94 +--> MTextPlist -> MTextPlist -> ... -> MTextPlist
96 | +- tail <-----------------------------------------+
98 | +- head <--> MInterval <--> ... <--> MInterval <--+
100 +- tail --------------------------------------------------------+
102 +- head --> MInterval <--> MInterval <--> ... <--> MInterval <--+
104 +---------------+------------> MTextProperty
111 MTextProperty a/A [AAAAAAAAAAAAAAAAAAAAA]
112 MTextProperty a/B [BBBBBBBBBBBBBBBBB]
113 MTextPlist a |--intvl1--|-intvl2-|-intvl3-|---intvl4---|-intvl5-|
116 MTextProperty b/A [AAAAAAAAAA]
117 MTextProperty b/B [BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB]
118 MTextPlist b |-intvl1-|--intvl2--|--intvl3--|-intvl4-|--intvl5--|
120 M-text |--------------------------------------------------|
126 /* The structure MTextProperty is defined in textprop.h. */
128 /** MInterval is the structure for an interval that holds text
129 properties of the same key in a specific range of M-text.
130 All intervals are stored in MIntervalPool. */
132 typedef struct MInterval MInterval;
136 /** Stack of pointers to text properties. If the interval does not
137 have any text properties, this member is NULL or contains random
139 MTextProperty **stack;
141 /** How many values are in <stack>. */
144 /** Length of <stack>. */
147 /** Start and end character positions of the interval. If <end> is
148 negative, this interval is not in use. */
151 /** Pointers to the previous and next intervals. If <start> is 0,
152 <prev> is NULL and this interval is pointed by MTextPlist->head.
153 If <end> is the size of the M-text, <next> is NULL, and this
154 interval is pointed by MTextPlist->tail. */
155 MInterval *prev, *next;
158 /** MTextPlist is a structure to hold text properties of an M-text by
159 chain. Each element in the chain is for a specific key. */
161 typedef struct MTextPlist MTextPlist;
165 /** Key of the property. */
168 /** The head and tail intervals. <head>->start is always 0.
169 <tail->end is always MText->nchars. */
170 MInterval *head, *tail;
172 /** Lastly accessed interval. */
175 /* Not yet implemented. */
176 int (*modification_hook) (MText *mt, MSymbol key, int from, int to);
178 /** Pointer to the next property in the chain, or NULL if the
179 property is the last one in the chain. */
184 /** How many intervals one interval-pool can contain. */
186 #define INTERVAL_POOL_SIZE 1024
188 typedef struct MIntervalPool MIntervalPool;
191 /** MIntervalPool is the structure for an interval-pool which store
192 intervals. Each interval-pool contains INTERVAL_POOL_SIZE number
193 of intervals, and is chained from the root #interval_pool. */
197 /** Array of intervals. */
198 MInterval intervals[INTERVAL_POOL_SIZE];
200 /** The smallest index to an unused interval. */
203 /** Pointer to the next interval-pool. */
208 /** Root of interval-pools. */
210 static MIntervalPool interval_pool_root;
214 static M17NObjectArray text_property_table;
216 /** Return a newly allocated interval pool. */
218 static MIntervalPool *
224 MSTRUCT_CALLOC (pool, MERROR_TEXTPROP);
225 for (i = 0; i < INTERVAL_POOL_SIZE; i++)
226 pool->intervals[i].end = -1;
233 /** Return a new interval for the region START and END. */
236 new_interval (int start, int end)
241 for (pool = &interval_pool_root;
242 pool->free_slot >= INTERVAL_POOL_SIZE;
246 pool->next = new_interval_pool ();
249 interval = &(pool->intervals[pool->free_slot]);
250 interval->stack = NULL;
251 interval->nprops = 0;
252 interval->stack_length = 0;
253 interval->prev = interval->next = NULL;
254 interval->start = start;
258 while (pool->free_slot < INTERVAL_POOL_SIZE
259 && pool->intervals[pool->free_slot].end >= 0)
266 /** Free INTERVAL and return INTERVAL->next. It assumes that INTERVAL
267 has no properties. */
270 free_interval (MInterval *interval)
272 MIntervalPool *pool = &interval_pool_root;
275 xassert (interval->nprops == 0);
277 free (interval->stack);
278 while ((interval < pool->intervals
279 || interval >= pool->intervals + INTERVAL_POOL_SIZE)
283 i = interval - pool->intervals;
285 if (i < pool->free_slot)
287 return interval->next;
291 /** If necessary, allocate a stack for INTERVAL so that it can contain
292 NUM number of text properties. */
294 #define PREPARE_INTERVAL_STACK(interval, num) \
296 if ((num) > (interval)->stack_length) \
298 MTABLE_REALLOC ((interval)->stack, (num), MERROR_TEXTPROP); \
299 (interval)->stack_length = (num); \
304 /** Return a copy of INTERVAL. The copy still shares text properties
305 with INTERVAL. If MASK_BITS is not zero, don't copy such text
306 properties whose control flags contains bits in MASK_BITS. */
309 copy_interval (MInterval *interval, int mask_bits)
311 MInterval *new = new_interval (interval->start, interval->end);
312 int nprops = interval->nprops;
313 MTextProperty **props = alloca (sizeof (MTextProperty *) * nprops);
316 for (i = n = 0; i < nprops; i++)
317 if (! (interval->stack[i]->control.flag & mask_bits))
318 props[n++] = interval->stack[i];
322 PREPARE_INTERVAL_STACK (new, n);
323 memcpy (new->stack, props, sizeof (MTextProperty *) * n);
330 /** Free text property OBJECT. */
333 free_text_property (void *object)
335 MTextProperty *prop = (MTextProperty *) object;
337 if (prop->key->managing_key)
338 M17N_OBJECT_UNREF (prop->val);
339 M17N_OBJECT_UNREGISTER (text_property_table, prop);
344 /** Return a newly allocated text property whose key is KEY and value
347 static MTextProperty *
348 new_text_property (MText *mt, int from, int to, MSymbol key, void *val,
353 M17N_OBJECT (prop, free_text_property, MERROR_TEXTPROP);
354 prop->control.flag = control_bits;
355 prop->attach_count = 0;
361 if (key->managing_key)
362 M17N_OBJECT_REF (val);
363 M17N_OBJECT_REGISTER (text_property_table, prop);
368 /** Return a newly allocated copy of text property PROP. */
370 #define COPY_TEXT_PROPERTY(prop) \
371 new_text_property ((prop)->mt, (prop)->start, (prop)->end, \
372 (prop)->key, (prop)->val, (prop)->control.flag)
375 /** Split text property PROP at position INTERVAL->start, and make all
376 the following intervals contain the copy of PROP instead of PROP.
377 It assumes that PROP starts before INTERVAL. */
380 split_property (MTextProperty *prop, MInterval *interval)
386 prop->end = interval->start;
387 copy = COPY_TEXT_PROPERTY (prop);
388 copy->start = interval->start;
390 /* Check all stacks of the following intervals, and if it contains
391 PROP, change it to the copy of it. */
392 for (; interval && interval->start < end; interval = interval->next)
393 for (i = 0; i < interval->nprops; i++)
394 if (interval->stack[i] == prop)
396 interval->stack[i] = copy;
397 M17N_OBJECT_REF (copy);
398 copy->attach_count++;
399 prop->attach_count--;
400 M17N_OBJECT_UNREF (prop);
402 M17N_OBJECT_UNREF (copy);
405 /** Divide INTERVAL of PLIST at POS if POS is in between the range of
409 divide_interval (MTextPlist *plist, MInterval *interval, int pos)
414 if (pos == interval->start || pos == interval->end)
416 new = copy_interval (interval, 0);
417 interval->end = new->start = pos;
418 new->prev = interval;
419 new->next = interval->next;
420 interval->next = new;
422 new->next->prev = new;
423 if (plist->tail == interval)
425 for (i = 0; i < new->nprops; i++)
427 new->stack[i]->attach_count++;
428 M17N_OBJECT_REF (new->stack[i]);
433 /** Check if INTERVAL of PLIST can be merged with INTERVAL->next. If
434 mergeable, extend INTERVAL to the end of INTEVAL->next, free
435 INTERVAL->next, and return INTERVAL. Otherwise, return
439 maybe_merge_interval (MTextPlist *plist, MInterval *interval)
441 int nprops = interval->nprops;
442 MInterval *next = interval->next;
445 if (! next || nprops != next->nprops)
448 for (i = 0; i < nprops; i++)
450 MTextProperty *prop = interval->stack[i];
451 MTextProperty *old = next->stack[i];
454 && (prop->val != old->val
455 || prop->end != old->start
456 || prop->control.flag & MTEXTPROP_NO_MERGE
457 || old->control.flag & MTEXTPROP_NO_MERGE))
458 return interval->next;
462 for (i = 0; i < nprops; i++)
464 MTextProperty *prop = interval->stack[i];
465 MTextProperty *old = next->stack[i];
471 for (tail = next->next; tail && tail->start < old->end;
473 for (j = 0; j < tail->nprops; j++)
474 if (tail->stack[j] == old)
477 xassert (old->attach_count);
478 tail->stack[j] = prop;
479 prop->attach_count++;
480 M17N_OBJECT_REF (prop);
482 xassert (old->attach_count == 1);
484 prop->end = old->end;
487 M17N_OBJECT_UNREF (old);
490 interval->end = next->end;
491 interval->next = next->next;
493 next->next->prev = interval;
494 if (plist->tail == next)
495 plist->tail = interval;
496 plist->cache = interval;
498 free_interval (next);
503 /** Adjust start and end positions of intervals between HEAD and TAIL
504 (both inclusive) by diff. Adjust also start and end positions
505 of text properties belonging to those intervals. */
508 adjust_intervals (MInterval *head, MInterval *tail, int diff)
515 /* Adjust end positions of properties starting before HEAD. */
516 for (i = 0; i < head->nprops; i++)
518 prop = head->stack[i];
519 if (prop->start < head->start)
523 /* Adjust start and end positions of properties starting at
524 HEAD, and adjust HEAD itself. */
527 for (i = 0; i < head->nprops; i++)
529 prop = head->stack[i];
530 if (prop->start == head->start)
531 prop->start += diff, prop->end += diff;
542 /* Adjust start poistions of properties ending after TAIL. */
543 for (i = 0; i < tail->nprops; i++)
545 prop = tail->stack[i];
546 if (prop->end > tail->end)
550 /* Adjust start and end positions of properties ending at
551 TAIL, and adjust TAIL itself. */
554 for (i = 0; i < tail->nprops; i++)
556 prop = tail->stack[i];
557 if (prop->end == tail->end)
558 prop->start += diff, prop->end += diff;
569 /* Return an interval of PLIST that covers the position POS. */
572 find_interval (MTextPlist *plist, int pos)
577 if (pos < plist->head->end)
579 if (pos >= plist->tail->start)
580 return (pos < plist->tail->end ? plist->tail : NULL);
582 interval = plist->cache;
584 if (pos < interval->start)
585 highest = interval->prev, interval = plist->head->next;
586 else if (pos < interval->end)
589 highest = plist->tail->prev, interval = interval->next;
591 if (pos - interval->start < highest->end - pos)
593 while (interval->end <= pos)
594 /* Here, we are sure that POS is not included in PLIST->tail,
595 thus, INTERVAL->next always points a valid next
597 interval = interval->next;
601 while (highest->start > pos)
602 highest = highest->prev;
605 plist->cache = interval;
609 /* Push text property PROP on the stack of INTERVAL. */
611 #define PUSH_PROP(interval, prop) \
613 int n = (interval)->nprops; \
615 PREPARE_INTERVAL_STACK ((interval), n + 1); \
616 (interval)->stack[n] = (prop); \
617 (interval)->nprops += 1; \
618 (prop)->attach_count++; \
619 M17N_OBJECT_REF (prop); \
620 if ((prop)->start > (interval)->start) \
621 (prop)->start = (interval)->start; \
622 if ((prop)->end < (interval)->end) \
623 (prop)->end = (interval)->end; \
627 /* Pop the topmost text property of INTERVAL from the stack. If it
628 ends after INTERVAL->end, split it. */
630 #define POP_PROP(interval) \
632 MTextProperty *prop; \
634 (interval)->nprops--; \
635 prop = (interval)->stack[(interval)->nprops]; \
636 xassert (prop->control.ref_count > 0); \
637 xassert (prop->attach_count > 0); \
638 if (prop->start < (interval)->start) \
640 if (prop->end > (interval)->end) \
641 split_property (prop, (interval)->next); \
642 prop->end = (interval)->start; \
644 else if (prop->end > (interval)->end) \
645 prop->start = (interval)->end; \
646 prop->attach_count--; \
647 if (! prop->attach_count) \
649 M17N_OBJECT_UNREF (prop); \
653 #define REMOVE_PROP(interval, prop) \
657 for (i = (interval)->nprops - 1; i >= 0; i--) \
658 if ((interval)->stack[i] == (prop)) \
662 (interval)->nprops--; \
663 for (; i < (interval)->nprops; i++) \
664 (interval)->stack[i] = (interval)->stack[i + 1]; \
665 (prop)->attach_count--; \
666 if (! (prop)->attach_count) \
668 M17N_OBJECT_UNREF (prop); \
672 #ifdef TEXT_PROP_DEBUG
674 check_plist (MTextPlist *plist, int start)
676 MInterval *interval = plist->head;
677 MInterval *cache = plist->cache;
680 if (interval->start != start
681 || interval->start >= interval->end)
682 return mdebug_hook ();
687 if (interval == interval->next)
688 return mdebug_hook ();
690 if (interval == cache)
693 if (interval->start >= interval->end)
694 return mdebug_hook ();
696 ? (interval->end != interval->next->start
697 || interval != interval->next->prev)
698 : interval != plist->tail))
699 return mdebug_hook ();
700 for (i = 0; i < interval->nprops; i++)
702 if (interval->stack[i]->start > interval->start
703 || interval->stack[i]->end < interval->end)
704 return mdebug_hook ();
706 if (! interval->stack[i]->attach_count)
707 return mdebug_hook ();
708 if (! interval->stack[i]->mt)
709 return mdebug_hook ();
710 if (interval->stack[i]->start == interval->start)
712 MTextProperty *prop = interval->stack[i];
713 int count = prop->attach_count - 1;
714 MInterval *interval2;
716 for (interval2 = interval->next;
717 interval2 && interval2->start < prop->end;
718 count--, interval2 = interval2->next)
720 return mdebug_hook ();
723 if (interval->stack[i]->end > interval->end)
725 MTextProperty *prop = interval->stack[i];
726 MInterval *interval2;
729 for (interval2 = interval->next;
730 interval2 && interval2->start < prop->end;
731 interval2 = interval2->next)
733 for (j = 0; j < interval2->nprops; j++)
734 if (interval2->stack[j] == prop)
736 if (j == interval2->nprops)
737 return mdebug_hook ();
740 if (interval->stack[i]->start < interval->start)
742 MTextProperty *prop = interval->stack[i];
743 MInterval *interval2;
746 for (interval2 = interval->prev;
747 interval2 && interval2->end > prop->start;
748 interval2 = interval2->prev)
750 for (j = 0; j < interval2->nprops; j++)
751 if (interval2->stack[j] == prop)
753 if (j == interval2->nprops)
754 return mdebug_hook ();
758 interval = interval->next;
761 return mdebug_hook ();
762 if (plist->head->prev || plist->tail->next)
763 return mdebug_hook ();
769 /** Return a copy of plist that contains intervals between FROM and TO
770 of PLIST. The copy goes to the position POS of M-text MT. */
773 copy_single_property (MTextPlist *plist, int from, int to, MText *mt, int pos)
776 MInterval *interval1, *interval2;
778 int diff = pos - from;
780 int mask_bits = MTEXTPROP_VOLATILE_STRONG | MTEXTPROP_VOLATILE_WEAK;
782 MSTRUCT_CALLOC (new, MERROR_TEXTPROP);
783 new->key = plist->key;
786 interval1 = find_interval (plist, from);
787 new->head = copy_interval (interval1, mask_bits);
788 for (interval1 = interval1->next, interval2 = new->head;
789 interval1 && interval1->start < to;
790 interval1 = interval1->next, interval2 = interval2->next)
792 interval2->next = copy_interval (interval1, mask_bits);
793 interval2->next->prev = interval2;
795 new->tail = interval2;
796 new->head->start = from;
798 for (interval1 = new->head; interval1; interval1 = interval1->next)
799 for (i = 0; i < interval1->nprops; i++)
800 if (interval1->start == interval1->stack[i]->start
801 || interval1 == new->head)
803 prop = interval1->stack[i];
804 interval1->stack[i] = COPY_TEXT_PROPERTY (prop);
805 interval1->stack[i]->mt = mt;
806 interval1->stack[i]->attach_count++;
807 if (interval1->stack[i]->start < from)
808 interval1->stack[i]->start = from;
809 if (interval1->stack[i]->end > to)
810 interval1->stack[i]->end = to;
811 for (interval2 = interval1->next; interval2;
812 interval2 = interval2->next)
813 for (j = 0; j < interval2->nprops; j++)
814 if (interval2->stack[j] == prop)
816 interval2->stack[j] = interval1->stack[i];
817 interval1->stack[i]->attach_count++;
818 M17N_OBJECT_REF (interval1->stack[i]);
821 adjust_intervals (new->head, new->tail, diff);
822 new->cache = new->head;
823 for (interval1 = new->head; interval1 && interval1->next;
824 interval1 = maybe_merge_interval (new, interval1));
825 xassert (check_plist (new, pos) == 0);
826 if (new->head == new->tail
827 && new->head->nprops == 0)
829 free_interval (new->head);
837 /** Return a newly allocated plist whose key is KEY on M-text MT. */
840 new_plist (MText *mt, MSymbol key)
844 MSTRUCT_MALLOC (plist, MERROR_TEXTPROP);
846 plist->head = new_interval (0, mtext_nchars (mt));
847 plist->tail = plist->head;
848 plist->cache = plist->head;
849 plist->next = mt->plist;
854 /* Free PLIST and return PLIST->next. */
857 free_textplist (MTextPlist *plist)
859 MTextPlist *next = plist->next;
860 MInterval *interval = plist->head;
864 while (interval->nprops > 0)
866 interval = free_interval (interval);
872 /** Return a plist that contains the property KEY of M-text MT. If
873 such a plist does not exist and CREATE is nonzero, create a new
874 plist and return it. */
877 get_plist_create (MText *mt, MSymbol key, int create)
882 while (plist && plist->key != key)
885 /* If MT does not have PROP, make one. */
886 if (! plist && create)
887 plist = new_plist (mt, key);
891 /* Detach PROP. INTERVAL (if not NULL) contains PROP. */
894 detach_property (MTextPlist *plist, MTextProperty *prop, MInterval *interval)
902 M17N_OBJECT_REF (prop);
904 while (interval->start > prop->start)
905 interval = interval->prev;
907 interval = find_interval (plist, prop->start);
911 REMOVE_PROP (interval, prop);
912 if (interval->end == to)
914 interval = interval->next;
916 xassert (prop->attach_count == 0 && prop->mt == NULL);
917 M17N_OBJECT_UNREF (prop);
919 while (head && head->end <= to)
920 head = maybe_merge_interval (plist, head);
921 xassert (check_plist (plist, 0) == 0);
924 /* Delete text properties of PLIST between FROM and TO. MASK_BITS
925 specifies what kind of properties to delete. If DELETING is
926 nonzero, delete such properties too that are completely included in
929 If the resulting PLIST still has any text properties, return 1,
933 delete_properties (MTextPlist *plist, int from, int to,
934 int mask_bits, int deleting)
938 int modified_from = from;
939 int modified_to = to;
943 for (interval = find_interval (plist, from);
944 interval && interval->start < to;
945 interval = interval->next)
946 for (i = 0; i < interval->nprops; i++)
948 MTextProperty *prop = interval->stack[i];
950 if (prop->control.flag & mask_bits)
952 if (prop->start < modified_from)
953 modified_from = prop->start;
954 if (prop->end > modified_to)
955 modified_to = prop->end;
956 detach_property (plist, prop, interval);
960 else if (deleting && prop->start >= from && prop->end <= to)
962 detach_property (plist, prop, interval);
970 interval = find_interval (plist, modified_from);
971 while (interval && interval->start < modified_to)
972 interval = maybe_merge_interval (plist, interval);
975 return (plist->head != plist->tail || plist->head->nprops > 0);
979 pop_interval_properties (MInterval *interval)
981 while (interval->nprops > 0)
987 pop_all_properties (MTextPlist *plist, int from, int to)
991 /* Be sure to have interval boundary at TO. */
992 interval = find_interval (plist, to);
993 if (interval && interval->start < to)
994 divide_interval (plist, interval, to);
996 /* Be sure to have interval boundary at FROM. */
997 interval = find_interval (plist, from);
998 if (interval->start < from)
1000 divide_interval (plist, interval, from);
1001 interval = interval->next;
1004 pop_interval_properties (interval);
1005 while (interval->end < to)
1007 MInterval *next = interval->next;
1009 pop_interval_properties (next);
1010 interval->end = next->end;
1011 interval->next = next->next;
1013 interval->next->prev = interval;
1014 if (next == plist->tail)
1015 plist->tail = interval;
1016 if (plist->cache == next)
1017 plist->cache = interval;
1018 free_interval (next);
1024 /* Delete volatile text properties between FROM and TO. If DELETING
1025 is nonzero, we are going to delete text, thus both strongly and
1026 weakly volatile properties must be deleted. Otherwise we are going
1027 to modify a text property KEY, thus only strongly volatile
1028 properties whose key is not KEY must be deleted. */
1031 prepare_to_modify (MText *mt, int from, int to, MSymbol key, int deleting)
1033 MTextPlist *plist = mt->plist, *prev = NULL;
1034 int mask_bits = MTEXTPROP_VOLATILE_STRONG;
1037 mask_bits |= MTEXTPROP_VOLATILE_WEAK;
1040 if (plist->key != key
1041 && ! delete_properties (plist, from, to, mask_bits, deleting))
1044 plist = prev->next = free_textplist (plist);
1046 plist = mt->plist = free_textplist (plist);
1049 prev = plist, plist = plist->next;
1054 extract_text_properties (MText *mt, int from, int to, MSymbol key,
1058 MTextPlist *list = get_plist_create (mt, key, 0);
1059 MInterval *interval;
1063 interval = find_interval (list, from);
1064 if (interval->nprops == 0
1065 && interval->start <= from && interval->end >= to)
1068 while (interval && interval->start < to)
1070 if (interval->nprops == 0)
1071 top = mplist_find_by_key (top, Mnil);
1074 MPlist *current = top, *place;
1077 for (i = 0; i < interval->nprops; i++)
1079 MTextProperty *prop = interval->stack[i];
1081 place = mplist_find_by_value (current, prop);
1083 current = MPLIST_NEXT (place);
1086 place = mplist_find_by_value (top, prop);
1090 if (MPLIST_NEXT (place) == MPLIST_NEXT (current))
1093 mplist_push (current, Mt, prop);
1094 current = MPLIST_NEXT (current);
1098 interval = interval->next;
1103 #define XML_TEMPLATE "<?xml version=\"1.0\" ?>\n\
1104 <!DOCTYPE mtext [\n\
1105 <!ELEMENT mtext (property*,body+)>\n\
1106 <!ELEMENT property EMPTY>\n\
1107 <!ELEMENT body (#PCDATA)>\n\
1108 <!ATTLIST property key CDATA #REQUIRED>\n\
1109 <!ATTLIST property value CDATA #REQUIRED>\n\
1110 <!ATTLIST property from CDATA #REQUIRED>\n\
1111 <!ATTLIST property to CDATA #REQUIRED>\n\
1112 <!ATTLIST property control CDATA #REQUIRED>\n\
1118 /* for debugging... */
1122 dump_interval (MInterval *interval, int indent)
1124 char *prefix = (char *) alloca (indent + 1);
1127 memset (prefix, 32, indent);
1130 fprintf (stderr, "(interval %d-%d (%d)", interval->start, interval->end,
1132 for (i = 0; i < interval->nprops; i++)
1133 fprintf (stderr, "\n%s (%d %d/%d %d-%d 0x%x)",
1135 interval->stack[i]->control.ref_count,
1136 interval->stack[i]->attach_count,
1137 interval->stack[i]->start, interval->stack[i]->end,
1138 (unsigned) interval->stack[i]->val);
1139 fprintf (stderr, ")");
1143 dump_textplist (MTextPlist *plist, int indent)
1145 char *prefix = (char *) alloca (indent + 1);
1147 memset (prefix, 32, indent);
1150 fprintf (stderr, "(properties");
1152 fprintf (stderr, ")\n");
1155 fprintf (stderr, "\n");
1158 MInterval *interval = plist->head;
1160 fprintf (stderr, "%s (%s", prefix, msymbol_name (plist->key));
1163 fprintf (stderr, " (%d %d", interval->start, interval->end);
1164 if (interval->nprops > 0)
1168 for (i = 0; i < interval->nprops; i++)
1169 fprintf (stderr, " 0x%x", (int) interval->stack[i]->val);
1171 fprintf (stderr, ")");
1172 interval = interval->next;
1174 fprintf (stderr, ")\n");
1175 xassert (check_plist (plist, 0) == 0);
1176 plist = plist->next;
1187 M17N_OBJECT_ADD_ARRAY (text_property_table, "Text property");
1188 Mtext_prop_serializer = msymbol ("text-prop-serializer");
1189 Mtext_prop_deserializer = msymbol ("text-prop-deserializer");
1196 MIntervalPool *pool = interval_pool_root.next;
1200 MIntervalPool *next = pool->next;
1204 interval_pool_root.next = NULL;
1208 /** Free all plists. */
1211 mtext__free_plist (MText *mt){
1213 MTextPlist *plist = mt->plist;
1216 plist = free_textplist (plist);
1221 /** Extract intervals between FROM and TO of all properties (except
1222 for volatile ones) in PLIST, and make a new plist from them for
1226 mtext__copy_plist (MTextPlist *plist, int from, int to, MText *mt, int pos)
1228 MTextPlist *copy, *this;
1232 for (copy = NULL; plist && ! copy; plist = plist->next)
1233 copy = copy_single_property (plist, from, to, mt, pos);
1236 for (; plist; plist = plist->next)
1237 if ((this = copy_single_property (plist, from, to, mt, pos)))
1247 mtext__adjust_plist_for_delete (MText *mt, int pos, int len)
1252 if (len == 0 || pos == mt->nchars)
1254 if (len == mt->nchars)
1256 mtext__free_plist (mt);
1261 prepare_to_modify (mt, pos, to, Mnil, 1);
1262 for (plist = mt->plist; plist; plist = plist->next)
1264 MInterval *interval = pop_all_properties (plist, pos, to);
1265 MInterval *prev = interval->prev, *next = interval->next;
1273 adjust_intervals (next, plist->tail, -len);
1279 next = maybe_merge_interval (plist, prev);
1280 plist->cache = next ? next : prev;
1281 free_interval (interval);
1282 xassert (check_plist (plist, 0) == 0);
1287 mtext__adjust_plist_for_insert (MText *mt, int pos, int nchars,
1290 MTextPlist *pl, *pl_last, *pl2, *p;
1292 MInterval *interval;
1294 if (mt->nchars == 0)
1296 mtext__free_plist (mt);
1300 if (pos > 0 && pos < mtext_nchars (mt))
1301 prepare_to_modify (mt, pos, pos, Mnil, 0);
1303 for (pl_last = NULL, pl = mt->plist; pl; pl_last = pl, pl = pl->next)
1305 MInterval *interval, *prev, *next, *head, *tail;
1308 prev = NULL, next = pl->head;
1309 else if (pos == mtext_nchars (mt))
1310 prev = pl->tail, next = NULL;
1313 next = find_interval (pl, pos);
1314 if (next->start < pos)
1316 divide_interval (pl, next, pos);
1319 for (i = 0; i < next->nprops; i++)
1320 if (next->stack[i]->start < pos)
1321 split_property (next->stack[i], next);
1325 xassert (check_plist (pl, 0) == 0);
1326 for (p = NULL, pl2 = plist; pl2 && pl->key != pl2->key;
1327 p = pl2, pl2 = p->next);
1330 xassert (check_plist (pl2, pl2->head->start) == 0);
1332 p->next = pl2->next;
1334 plist = plist->next;
1342 head = tail = new_interval (pos, pos + nchars);
1355 adjust_intervals (next, pl->tail, nchars);
1357 xassert (check_plist (pl, 0) == 0);
1358 if (prev && prev->nprops > 0)
1360 for (interval = prev;
1361 interval->next != next && interval->next->nprops == 0;
1362 interval = interval->next)
1363 for (i = 0; i < interval->nprops; i++)
1365 MTextProperty *prop = interval->stack[i];
1367 if (prop->control.flag & MTEXTPROP_REAR_STICKY)
1368 PUSH_PROP (interval->next, prop);
1371 xassert (check_plist (pl, 0) == 0);
1372 if (next && next->nprops > 0)
1374 for (interval = next;
1375 interval->prev != prev && interval->prev->nprops == 0;
1376 interval = interval->prev)
1377 for (i = 0; i < interval->nprops; i++)
1379 MTextProperty *prop = interval->stack[i];
1381 if (prop->control.flag & MTEXTPROP_FRONT_STICKY)
1382 PUSH_PROP (interval->prev, prop);
1386 interval = prev ? prev : pl->head;
1387 pl->cache = interval;
1388 while (interval && interval->start <= pos + nchars)
1389 interval = maybe_merge_interval (pl, interval);
1390 xassert (check_plist (pl, 0) == 0);
1394 pl_last->next = plist;
1398 for (; plist; plist = plist->next)
1400 plist->cache = plist->head;
1403 if (plist->head->nprops)
1405 interval = new_interval (0, pos);
1406 interval->next = plist->head;
1407 plist->head->prev = interval;
1408 plist->head = interval;
1411 plist->head->start = 0;
1413 if (pos < mtext_nchars (mt))
1415 if (plist->tail->nprops)
1417 interval = new_interval (pos + nchars,
1418 mtext_nchars (mt) + nchars);
1419 interval->prev = plist->tail;
1420 plist->tail->next = interval;
1421 plist->tail = interval;
1424 plist->tail->end = mtext_nchars (mt) + nchars;
1426 xassert (check_plist (plist, 0) == 0);
1430 /* len1 > 0 && len2 > 0 */
1433 mtext__adjust_plist_for_change (MText *mt, int pos, int len1, int len2)
1435 int pos2 = pos + len1;
1437 prepare_to_modify (mt, pos, pos2, Mnil, 0);
1441 int diff = len2 - len1;
1444 for (plist = mt->plist; plist; plist = plist->next)
1446 MInterval *head = find_interval (plist, pos2);
1447 MInterval *tail = plist->tail;
1448 MTextProperty *prop;
1453 if (head->start == pos2)
1455 while (tail != head)
1457 for (i = 0; i < tail->nprops; i++)
1459 prop = tail->stack[i];
1460 if (prop->start == tail->start)
1461 prop->start += diff, prop->end += diff;
1463 tail->start += diff;
1468 for (i = 0; i < tail->nprops; i++)
1469 tail->stack[i]->end += diff;
1473 else if (len1 > len2)
1475 mtext__adjust_plist_for_delete (mt, pos + len2, len1 - len2);
1481 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1486 /*** @addtogroup m17nTextProperty */
1491 @brief Get the value of the topmost text property.
1493 The mtext_get_prop () function searches the character at $POS in
1494 M-text $MT for the text property whose key is $KEY.
1497 If a text property is found, mtext_get_prop () returns the value
1498 of the property. If the property has multiple values, it returns
1499 the topmost one. If no such property is found, it returns @c NULL
1500 without changing the external variable #merror_code.
1502 If an error is detected, mtext_get_prop () returns @c NULL and
1503 assigns an error code to the external variable #merror_code.
1505 @note If @c NULL is returned without an error, there are two
1508 @li the character at $POS does not have a property whose key is $KEY, or
1510 @li the character does have such a property and its value is @c NULL.
1512 If you need to distinguish these two cases, use the
1513 mtext_get_prop_values () function instead. */
1516 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î°ìÈÖ¾å¤ÎÃͤòÆÀ¤ë.
1518 ´Ø¿ô mtext_get_prop () ¤Ï¡¢M-text $MT Æâ¤Î°ÌÃÖ $POS ¤Ë¤¢¤ëʸ»ú¤Î¥Æ
1519 ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥¡¼¤¬ $KEY ¤Ç¤¢¤ë¤â¤Î¤òõ¤¹¡£
1522 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬¤ß¤Ä¤«¤ì¤Ð¡¢mtext_get_prop () ¤Ï¤½¤Î¥×¥í¥Ñ¥Æ¥£
1523 ¤ÎÃͤòÊÖ¤¹¡£Ãͤ¬Ê£¿ô¸ºß¤¹¤ë¤È¤¤Ï¡¢°ìÈÖ¾å¤ÎÃͤòÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±
1524 ¤ì¤Ð³°ÉôÊÑ¿ô #merror_code ¤òÊѹ¹¤¹¤ë¤³¤È¤Ê¤¯ @c NULL ¤òÊÖ¤¹¡£
1526 ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç mtext_get_prop () ¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ
1527 ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1529 @note ¥¨¥é¡¼¤Ê¤·¤Ç @c NULL ¤¬ÊÖ¤µ¤ì¤¿¾ì¹ç¤Ë¤ÏÆó¤Ä¤Î²ÄǽÀ¤¬¤¢¤ë¡£
1531 @li $POS ¤Î°ÌÃÖ¤Îʸ»ú¤Ï $KEY ¤ò¥¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤¡£
1533 @li ¤½¤Îʸ»ú¤Ï¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤ¬ @c NULL ¤Ç¤¢¤ë¡£
1535 ¤³¤ÎÆó¤Ä¤ò¶èÊ̤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢´Ø¿ô mtext_get_prop_values ()
1536 ¤òÂå¤ï¤ê¤Ë»ÈÍѤ¹¤ë¤³¤È¡£
1538 @latexonly \IPAlabel{mtext_get_prop} @endlatexonly */
1542 @c MERROR_RANGE, @c MERROR_SYMBOL
1545 mtext_get_prop_values (), mtext_put_prop (), mtext_put_prop_values (),
1546 mtext_push_prop (), mtext_pop_prop (), mtext_prop_range () */
1549 mtext_get_prop (MText *mt, int pos, MSymbol key)
1552 MInterval *interval;
1555 M_CHECK_POS (mt, pos, NULL);
1557 plist = get_plist_create (mt, key, 0);
1561 interval = find_interval (plist, pos);
1562 val = (interval->nprops
1563 ? interval->stack[interval->nprops - 1]->val : NULL);
1570 @brief Get multiple values of a text property.
1572 The mtext_get_prop_values () function searches the character at
1573 $POS in M-text $MT for the property whose key is $KEY. If such
1574 a property is found, its values are stored in the memory area
1575 pointed to by $VALUES. $NUM limits the maximum number of stored
1579 If the operation was successful, mtext_get_prop_values () returns
1580 the number of actually stored values. If the character at $POS
1581 does not have a property whose key is $KEY, the return value is
1582 0. If an error is detected, mtext_get_prop_values () returns -1 and
1583 assigns an error code to the external variable #merror_code. */
1586 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊ£¿ô¸ÄÆÀ¤ë.
1588 ´Ø¿ô mtext_get_prop_values () ¤Ï¡¢M-text $MT Æâ¤Ç $POS ¤È¤¤¤¦°ÌÃÖ
1589 ¤Ë¤¢¤ëʸ»ú¤Î¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥¡¼¤¬ $KEY ¤Ç¤¢¤ë¤â¤Î¤òõ¤¹¡£¤â¤·¤½
1590 ¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤¬»ý¤ÄÃÍ (Ê£¿ô²Ä) ¤ò $VALUES
1591 ¤Î»Ø¤¹¥á¥â¥êÎΰè¤Ë³ÊǼ¤¹¤ë¡£$NUM ¤Ï³ÊǼ¤¹¤ëÃͤοô¤Î¾å¸Â¤Ç¤¢¤ë¡£
1594 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_get_prop_values () ¤Ï¼ÂºÝ¤Ë¥á¥â¥ê¤Ë³ÊǼ¤µ
1595 ¤ì¤¿Ãͤοô¤òÊÖ¤¹¡£$POS ¤Î°ÌÃÖ¤Îʸ»ú¤¬ $KEY ¤ò¥¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£
1596 ¤ò»ý¤¿¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°Éô
1597 ÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1599 @latexonly \IPAlabel{mtext_get_prop_values} @endlatexonly */
1603 @c MERROR_RANGE, @c MERROR_SYMBOL
1606 mtext_get_prop (), mtext_put_prop (), mtext_put_prop_values (),
1607 mtext_push_prop (), mtext_pop_prop (), mtext_prop_range () */
1610 mtext_get_prop_values (MText *mt, int pos, MSymbol key,
1611 void **values, int num)
1614 MInterval *interval;
1619 M_CHECK_POS (mt, pos, -1);
1621 plist = get_plist_create (mt, key, 0);
1625 interval = find_interval (plist, pos);
1626 /* It is assured that INTERVAL is not NULL. */
1627 nprops = interval->nprops;
1628 if (nprops == 0 || num <= 0)
1630 if (nprops == 1 || num == 1)
1632 values[0] = interval->stack[nprops - 1]->val;
1637 num = nprops, offset = 0;
1639 offset = nprops - num;
1640 for (i = 0; i < num; i++)
1641 values[i] = interval->stack[offset + i]->val;
1648 @brief Get a list of text property keys at a position of an M-text.
1650 The mtext_get_prop_keys () function creates an array whose
1651 elements are the keys of text properties found at position $POS in
1652 M-text $MT, and sets *$KEYS to the address of the created array.
1653 The user is responsible to free the memory allocated for
1657 If the operation was successful, mtext_get_prop_keys () returns
1658 the length of the key list. Otherwise it returns -1 and assigns
1659 an error code to the external variable #merror_code.
1664 @brief M-text ¤Î»ØÄꤷ¤¿°ÌÃ֤Υƥ¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¥¡¼¤Î¥ê¥¹¥È¤òÆÀ¤ë.
1666 ´Ø¿ô mtext_get_prop_keys () ¤Ï¡¢M-text $MT Æâ¤Ç $POS ¤Î°ÌÃ֤ˤ¢¤ë
1667 ¤¹¤Ù¤Æ¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¥¡¼¤òÍ×ÁǤȤ¹¤ëÇÛÎó¤òºî¤ê¡¢¤½¤ÎÇÛÎó¤Î
1668 ¥¢¥É¥ì¥¹¤ò *$KEYS ¤ËÀßÄꤹ¤ë¡£¤³¤ÎÇÛÎó¤Î¤¿¤á¤Ë³ÎÊݤµ¤ì¤¿¥á¥â¥ê¤ò²ò
1669 Êü¤¹¤ë¤Î¤Ï¥æ¡¼¥¶¤ÎÀÕǤ¤Ç¤¢¤ë¡£
1672 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_get_prop_keys () ¤ÏÆÀ¤é¤ì¤¿¥ê¥¹¥È¤ÎŤµ¤òÊÖ
1673 ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
1682 mtext_get_prop (), mtext_put_prop (), mtext_put_prop_values (),
1683 mtext_get_prop_values (), mtext_push_prop (), mtext_pop_prop () */
1686 mtext_get_prop_keys (MText *mt, int pos, MSymbol **keys)
1691 M_CHECK_POS (mt, pos, -1);
1692 for (i = 0, plist = mt->plist; plist; i++, plist = plist->next);
1698 MTABLE_MALLOC (*keys, i, MERROR_TEXTPROP);
1699 for (i = 0, plist = mt->plist; plist; plist = plist->next)
1701 MInterval *interval = find_interval (plist, pos);
1703 if (interval->nprops)
1704 (*keys)[i++] = plist->key;
1712 @brief Set a text property.
1714 The mtext_put_prop () function sets a text property to the
1715 characters between $FROM (inclusive) and $TO (exclusive) in M-text
1716 $MT. $KEY and $VAL specify the key and the value of the text
1717 property. With this function,
1721 M-text: |<------------|-------- MT ---------|------------>|
1722 PROP : <------------------ OLD_VAL -------------------->
1729 M-text: |<------------|-------- MT ---------|------------>|
1730 PROP : <-- OLD_VAL-><-------- VAL -------><-- OLD_VAL-->
1734 If the operation was successful, mtext_put_prop () returns 0.
1735 Otherwise it returns -1 and assigns an error code to the external
1736 variable #merror_code. */
1739 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë.
1741 ´Ø¿ô mtext_put_prop () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë¤«¤é
1742 $TO ¡Ê´Þ¤Þ¤ì¤Ê¤¤¡Ë¤ÎÈϰϤÎʸ»ú¤Ë¡¢¥¡¼¤¬ $KEY ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¤è
1743 ¤¦¤Ê¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë¡£¤³¤Î´Ø¿ô¤Ë¤è¤Ã¤Æ
1748 M-text: |<------------|-------- MT ---------|------------>|
1749 PROP: <------------------ OLD_VAL -------------------->
1756 M-text: |<------------|-------- MT ---------|------------>|
1757 PROP: <-- OLD_VAL-><-------- VAL -------><-- OLD_VAL-->
1761 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_put_prop () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1
1762 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1764 @latexonly \IPAlabel{mtext_put_prop} @endlatexonly */
1768 @c MERROR_RANGE, @c MERROR_SYMBOL
1771 mtext_put_prop_values (), mtext_get_prop (),
1772 mtext_get_prop_values (), mtext_push_prop (),
1773 mtext_pop_prop (), mtext_prop_range () */
1776 mtext_put_prop (MText *mt, int from, int to, MSymbol key, void *val)
1779 MTextProperty *prop;
1780 MInterval *interval;
1782 M_CHECK_RANGE (mt, from, to, -1, 0);
1784 prepare_to_modify (mt, from, to, key, 0);
1785 plist = get_plist_create (mt, key, 1);
1786 interval = pop_all_properties (plist, from, to);
1787 prop = new_text_property (mt, from, to, key, val, 0);
1788 PUSH_PROP (interval, prop);
1789 M17N_OBJECT_UNREF (prop);
1791 maybe_merge_interval (plist, interval);
1793 maybe_merge_interval (plist, interval->prev);
1794 xassert (check_plist (plist, 0) == 0);
1801 @brief Set multiple text properties with the same key.
1803 The mtext_put_prop_values () function sets a text property to the
1804 characters between $FROM (inclusive) and $TO (exclusive) in M-text
1805 $MT. $KEY and $VALUES specify the key and the values of the text
1806 property. $NUM specifies the number of property values to be set.
1809 If the operation was successful, mtext_put_prop_values () returns
1810 0. Otherwise it returns -1 and assigns an error code to the
1811 external variable #merror_code. */
1814 @brief Ʊ¤¸¥¡¼¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÊ£¿ôÀßÄꤹ¤ë.
1816 ´Ø¿ô mtext_put_prop_values () ¤Ï¡¢M-Text $MT ¤Î$FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë
1817 ¤«¤é $TO ¡Ê´Þ¤Þ¤ì¤Ê¤¤¡Ë¤ÎÈϰϤÎʸ»ú¤Ë¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ
1818 ¤ë¡£¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¥¡¼¤Ï $KEY ¤Ë¤è¤Ã¤Æ¡¢ÃÍ(Ê£¿ô²Ä)¤Ï $VALUES
1819 ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ë¡£$NUM ¤ÏÀßÄꤵ¤ì¤ëÃͤθĿô¤Ç¤¢¤ë¡£
1822 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_put_prop_values () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±
1823 ¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1825 @latexonly \IPAlabel{mtext_put_prop_values} @endlatexonly */
1829 @c MERROR_RANGE, @c MERROR_SYMBOL
1832 mtext_put_prop (), mtext_get_prop (), mtext_get_prop_values (),
1833 mtext_push_prop (), mtext_pop_prop (), mtext_prop_range () */
1836 mtext_put_prop_values (MText *mt, int from, int to,
1837 MSymbol key, void **values, int num)
1840 MInterval *interval;
1843 M_CHECK_RANGE (mt, from, to, -1, 0);
1845 prepare_to_modify (mt, from, to, key, 0);
1846 plist = get_plist_create (mt, key, 1);
1847 interval = pop_all_properties (plist, from, to);
1850 PREPARE_INTERVAL_STACK (interval, num);
1851 for (i = 0; i < num; i++)
1854 = new_text_property (mt, from, to, key, values[i], 0);
1855 PUSH_PROP (interval, prop);
1856 M17N_OBJECT_UNREF (prop);
1860 maybe_merge_interval (plist, interval);
1862 maybe_merge_interval (plist, interval->prev);
1863 xassert (check_plist (plist, 0) == 0);
1870 @brief Push a text property.
1872 The mtext_push_prop () function pushes a text property whose key
1873 is $KEY and value is $VAL to the characters between $FROM
1874 (inclusive) and $TO (exclusive) in M-text $MT. With this
1879 M-text: |<------------|-------- MT ---------|------------>|
1880 PROP : <------------------ OLD_VAL -------------------->
1887 M-text: |<------------|-------- MT ---------|------------>|
1888 PROP : <------------------- OLD_VAL ------------------->
1889 PROP : <-------- VAL ------->
1893 If the operation was successful, mtext_push_prop () returns 0.
1894 Otherwise it returns -1 and assigns an error code to the external
1895 variable #merror_code. */
1898 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥×¥Ã¥·¥å¤¹¤ë.
1900 ´Ø¿ô mtext_push_prop () ¤Ï¡¢¥¡¼¤¬ $KEY ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥Æ¥¥¹¥È
1901 ¥×¥í¥Ñ¥Æ¥£¤ò¡¢M-text $MT Ãæ¤Î $FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë¤«¤é $TO ¡Ê´Þ¤Þ¤ì¤Ê
1902 ¤¤¡Ë¤ÎÈϰϤÎʸ»ú¤Ë¥×¥Ã¥·¥å¤¹¤ë¡£¤³¤Î´Ø¿ô¤Ë¤è¤Ã¤Æ
1906 M-text: |<------------|-------- MT ---------|------------>|
1907 PROP : <------------------ OLD_VAL -------------------->
1912 M-text: |<------------|-------- MT ---------|------------>|
1913 PROP : <------------------- OLD_VAL ------------------->
1914 PROP : <-------- VAL ------->
1918 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_push_prop () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
1919 -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1921 @latexonly \IPAlabel{mtext_push_prop} @endlatexonly */
1925 @c MERROR_RANGE, @c MERROR_SYMBOL
1928 mtext_put_prop (), mtext_put_prop_values (),
1929 mtext_get_prop (), mtext_get_prop_values (),
1930 mtext_pop_prop (), mtext_prop_range () */
1933 mtext_push_prop (MText *mt, int from, int to,
1934 MSymbol key, void *val)
1937 MInterval *head, *tail, *interval;
1938 MTextProperty *prop;
1939 int check_head, check_tail;
1941 M_CHECK_RANGE (mt, from, to, -1, 0);
1943 prepare_to_modify (mt, from, to, key, 0);
1944 plist = get_plist_create (mt, key, 1);
1946 /* Find an interval that covers the position FROM. */
1947 head = find_interval (plist, from);
1949 /* If the found interval starts before FROM, divide it at FROM. */
1950 if (head->start < from)
1952 divide_interval (plist, head, from);
1959 /* Find an interval that ends at TO. If TO is not at the end of an
1960 interval, make one that ends at TO. */
1961 if (head->end == to)
1966 else if (head->end > to)
1968 divide_interval (plist, head, to);
1974 tail = find_interval (plist, to);
1980 else if (tail->start == to)
1987 divide_interval (plist, tail, to);
1992 prop = new_text_property (mt, from, to, key, val, 0);
1994 /* Push PROP to the current values of intervals between HEAD and TAIL
1995 (both inclusive). */
1996 for (interval = head; ; interval = interval->next)
1998 PUSH_PROP (interval, prop);
1999 if (interval == tail)
2003 M17N_OBJECT_UNREF (prop);
2005 /* If there is a possibility that TAIL now has the same value as the
2006 next one, check it and concatenate them if necessary. */
2007 if (tail->next && check_tail)
2008 maybe_merge_interval (plist, tail);
2010 /* If there is a possibility that HEAD now has the same value as the
2011 previous one, check it and concatenate them if necessary. */
2012 if (head->prev && check_head)
2013 maybe_merge_interval (plist, head->prev);
2015 xassert (check_plist (plist, 0) == 0);
2022 @brief Pop a text property.
2024 The mtext_pop_prop () function removes the topmost text property
2025 whose key is $KEY from the characters between $FROM (inclusive)
2026 and and $TO (exclusive) in $MT.
2028 This function does nothing if characters in the region have no
2029 such text property. With this function,
2033 M-text: |<------------|-------- MT ---------|------------>|
2034 PROP : <------------------ OLD_VAL -------------------->
2041 M-text: |<------------|-------- MT ---------|------------>|
2042 PROP : <--OLD_VAL-->| |<--OLD_VAL-->|
2046 If the operation was successful, mtext_pop_prop () return 0.
2047 Otherwise it returns -1 and assigns an error code to the external
2048 variable #merror_code. */
2051 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥Ý¥Ã¥×¤¹¤ë.
2053 ´Ø¿ô mtext_pop_prop () ¤Ï¡¢¥¡¼¤¬ $KEY ¤Ç¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î
2054 ¤¦¤Á°ìÈÖ¾å¤Î¤â¤Î¤ò¡¢M-text $MT ¤Î $FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë¤«¤é $TO¡Ê´Þ¤Þ
2055 ¤ì¤Ê¤¤¡Ë¤ÎÈϰϤÎʸ»ú¤«¤é¼è¤ê½ü¤¯¡£
2057 »ØÄêÈϰϤÎʸ»ú¤¬¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï²¿
2058 ¤â¤·¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ë¤è¤Ã¤Æ¡¢
2062 M-text: |<------------|-------- MT ---------|------------>|
2063 PROP : <------------------ OLD_VAL -------------------->
2065 ¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
2068 M-text: |<------------|-------- MT ---------|------------>|
2069 PROP : <--OLD_VAL-->| |<--OLD_VAL-->|
2073 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_pop_prop () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1
2074 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2076 @latexonly \IPAlabel{mtext_pop_prop} @endlatexonly */
2080 @c MERROR_RANGE, @c MERROR_SYMBOL
2083 mtext_put_prop (), mtext_put_prop_values (),
2084 mtext_get_prop (), mtext_get_prop_values (),
2085 mtext_push_prop (), mtext_prop_range () */
2088 mtext_pop_prop (MText *mt, int from, int to, MSymbol key)
2091 MInterval *head, *tail;
2095 MERROR (MERROR_TEXTPROP, -1);
2096 M_CHECK_RANGE (mt, from, to, -1, 0);
2097 plist = get_plist_create (mt, key, 0);
2101 /* Find an interval that covers the position FROM. */
2102 head = find_interval (plist, from);
2104 && head->nprops == 0)
2105 /* No property to pop. */
2108 prepare_to_modify (mt, from, to, key, 0);
2110 /* If the found interval starts before FROM and has value(s), divide
2112 if (head->start < from)
2114 if (head->nprops > 0)
2116 divide_interval (plist, head, from);
2124 /* Pop the topmost text property from each interval following HEAD.
2125 Stop at an interval that ends after TO. */
2126 for (tail = head; tail && tail->end <= to; tail = tail->next)
2127 if (tail->nprops > 0)
2132 if (tail->start < to)
2134 if (tail->nprops > 0)
2136 divide_interval (plist, tail, to);
2145 to = plist->tail->start;
2147 /* If there is a possibility that HEAD now has the same text
2148 properties as the previous one, check it and concatenate them if
2150 if (head->prev && check_head)
2152 while (head && head->end <= to)
2153 head = maybe_merge_interval (plist, head);
2155 xassert (check_plist (plist, 0) == 0);
2162 @brief Find the range where the value of a text property is the same.
2164 The mtext_prop_range () function investigates the extent where all
2165 characters have the same value for a text property. It first
2166 finds the value of the property specified by $KEY of the character
2167 at $POS in M-text $MT. Then it checks if adjacent characters have
2168 the same value for the property $KEY. The beginning and the end
2169 of the found range are stored to the variable pointed to by $FROM
2170 and $TO. The character position stored in $FROM is inclusive but
2171 that in $TO is exclusive; this fashion is compatible with the
2172 range specification in the mtext_put_prop () function, etc.
2174 If $DEEPER is not 0, not only the topmost but also all the stacked
2175 properties whose key is $KEY are compared.
2177 If $FROM is @c NULL, the beginning of range is not searched for. If
2178 $TO is @c NULL, the end of range is not searched for.
2182 If the operation was successful, mtext_prop_range () returns the
2183 number of values the property $KEY has at pos. Otherwise it
2184 returns -1 and assigns an error code to the external variable @c
2188 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬Æ±¤¸Ãͤò¤È¤ëÈϰϤòÄ´¤Ù¤ë.
2190 ´Ø¿ô mtext_prop_range () ¤Ï¡¢»ØÄꤷ¤¿¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤ¬Æ±¤¸
2191 ¤Ç¤¢¤ëϢ³¤·¤¿Ê¸»ú¤ÎÈϰϤòÄ´¤Ù¤ë¡£¤Þ¤º M-text $MT ¤Î $POS ¤Î°ÌÃÖ¤Ë
2192 ¤¢¤ëʸ»ú¤Î¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥¡¼ $KEY ¤Ç»ØÄꤵ¤ì¤¿¤â¤ÎÃͤò¸«¤Ä¤±
2193 ¤ë¡£¤½¤·¤ÆÁ°¸å¤Îʸ»ú¤â $KEY ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤ¬Æ±¤¸¤Ç¤¢¤ë¤«¤É¤¦¤«¤ò
2194 Ä´¤Ù¤ë¡£¸«¤Ä¤±¤¿ÈϰϤκǽé¤ÈºÇ¸å¤ò¡¢¤½¤ì¤¾¤ì $FROM ¤È $TO ¤Ë¥Ý¥¤¥ó
2195 ¥È¤µ¤ì¤ëÊÑ¿ô¤ËÊݸ¤¹¤ë¡£$FROM ¤ËÊݸ¤µ¤ì¤ëʸ»ú¤Î°ÌÃ֤ϸ«¤Ä¤±¤¿ÈÏ°Ï
2196 ¤Ë´Þ¤Þ¤ì¤ë¤¬¡¢$TO ¤Ï´Þ¤Þ¤ì¤Ê¤¤¡£¡Ê$TO ¤ÎÁ°¤ÇƱ¤¸Ãͤò¤È¤ëÈϰϤϽª¤ï
2197 ¤ë¡£¡Ë¤³¤ÎÈÏ°Ï»ØÄêË¡¤Ï¡¢´Ø¿ô mtext_put_prop () ¤Ê¤É¤È¶¦Ä̤Ǥ¢¤ë¡£
2199 $DEEPER ¤¬ 0 ¤Ç¤Ê¤±¤ì¤Ð¡¢$KEY ¤È¤¤¤¦¥¡¼¤ò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á°ìÈÖ
2200 ¾å¤Î¤â¤Î¤À¤±¤Ç¤Ê¤¯¡¢¥¹¥¿¥Ã¥¯Ãæ¤Î¤¹¤Ù¤Æ¤Î¤â¤Î¤¬Èæ³Ó¤µ¤ì¤ë¡£
2202 $FROM ¤¬ @c NULL ¤Ê¤é¤Ð¡¢ÈϰϤλϤޤê¤Ïõº÷¤·¤Ê¤¤¡£$TO ¤¬ @c NULL
2203 ¤Ê¤é¤Ð¡¢ÈϰϤνª¤ê¤Ïõº÷¤·¤Ê¤¤¡£
2206 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_prop_range () ¤Ï $KEY ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤοô¤ò
2207 ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð-1 ¤òÊÖ¤·¡¢ ³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
2210 @latexonly \IPAlabel{mtext_prop_range} @endlatexonly */
2214 @c MERROR_RANGE, @c MERROR_SYMBOL
2217 mtext_put_prop (), mtext_put_prop_values (),
2218 mtext_get_prop (), mtext_get_prop_values (),
2219 mtext_pop_prop (), mtext_push_prop () */
2222 mtext_prop_range (MText *mt, MSymbol key, int pos,
2223 int *from, int *to, int deeper)
2226 MInterval *interval, *temp;
2230 M_CHECK_POS (mt, pos, -1);
2232 plist = get_plist_create (mt, key, 0);
2235 if (from) *from = 0;
2236 if (to) *to = mtext_nchars (mt);
2240 interval = find_interval (plist, pos);
2241 nprops = interval->nprops;
2242 if (deeper || ! nprops)
2244 if (from) *from = interval->start;
2245 if (to) *to = interval->end;
2246 return interval->nprops;
2249 val = nprops ? interval->stack[nprops - 1] : NULL;
2253 for (temp = interval;
2255 && (temp->prev->nprops
2257 && (val == temp->prev->stack[temp->prev->nprops - 1]))
2260 *from = temp->start;
2265 for (temp = interval;
2267 && (temp->next->nprops
2269 && val == temp->next->stack[temp->next->nprops - 1])
2279 @brief Create a text property.
2281 The mtext_property () function returns a newly allocated text
2282 property whose key is $KEY and value is $VAL. The created text
2283 property is not attached to any M-text, i.e. it is detached.
2285 $CONTROL_BITS must be 0 or logical OR of @c enum @c
2286 MTextPropertyControl. */
2289 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÀ¸À®¤¹¤ë.
2291 ´Ø¿ô mtext_property () ¤Ï $KEY ¤ò¥¡¼¡¢$VAL ¤òÃͤȤ¹¤ë¿·¤·¤¯³ä¤êÅö
2292 ¤Æ¤é¤ì¤¿¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÊÖ¤¹¡£À¸À®¤·¤¿¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¤¤«
2293 ¤Ê¤ë M-text ¤Ë¤âÉղ䵤ì¤Æ¤¤¤Ê¤¤¡¢¤¹¤Ê¤ï¤ÁʬΥ¤·¤Æ (detached) ¤¤¤ë¡£
2295 $CONTROL_BITS ¤Ï 0 ¤Ç¤¢¤ë¤« @c enum @c MTextPropertyControl ¤ÎÏÀÍý
2296 OR ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ */
2299 mtext_property (MSymbol key, void *val, int control_bits)
2301 return new_text_property (NULL, 0, 0, key, val, control_bits);
2305 @brief Return the M-text of a text property.
2307 The mtext_property_mtext () function returns the M-text to which
2308 text property $PROP is attached. If $PROP is currently detached,
2309 NULL is returned. */
2312 @brief ¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä M-text ¤òÊÖ¤¹.
2314 ´Ø¿ô mtext_property_mtext () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£$PROP ¤¬Éղäµ
2315 ¤ì¤Æ¤¤¤ë M-text ¤òÊÖ¤¹¡£¤½¤Î»þÅÀ¤Ç $PROP ¤¬Ê¬Î¥¤·¤Æ¤¤¤ì¤Ð NULL ¤ò
2319 mtext_property_mtext (MTextProperty *prop)
2325 @brief Return the key of a text property.
2327 The mtext_property_key () function returns the key (symbol) of
2328 text property $PROP. */
2331 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¥¡¼¤òÊÖ¤¹.
2333 ´Ø¿ô mtext_property_key () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤Î¥¡¼¡Ê¥·
2337 mtext_property_key (MTextProperty *prop)
2343 @brief Return the value of a text property.
2345 The mtext_property_value () function returns the value of text
2349 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹.
2351 ´Ø¿ô mtext_property_value () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤ÎÃͤòÊÖ
2355 mtext_property_value (MTextProperty *prop)
2361 @brief Return the start position of a text property.
2363 The mtext_property_start () function returns the start position of
2364 text property $PROP. The start position is a character position
2365 of an M-text where $PROP begins. If $PROP is detached, it returns
2369 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î³«»Ï°ÌÃÖ¤òÊÖ¤¹.
2371 ´Ø¿ô mtext_property_start () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤Î³«»Ï°Ì
2372 ÃÖ¤òÊÖ¤¹¡£³«»Ï°ÌÃÖ¤È¤Ï M-text Ãæ¤Ç $PROP ¤¬»Ï¤Þ¤ëʸ»ú°ÌÃ֤Ǥ¢¤ë¡£
2373 $PROP ¤¬Ê¬Î¥¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢-1 ¤òÊÖ¤¹¡£ */
2376 mtext_property_start (MTextProperty *prop)
2378 return (prop->mt ? prop->start : -1);
2382 @brief Return the end position of a text property.
2384 The mtext_property_end () function returns the end position of
2385 text property $PROP. The end position is a character position of
2386 an M-text where $PROP ends. If $PROP is detached, it returns
2390 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î½ªÎ»°ÌÃÖ¤òÊÖ¤¹.
2392 ´Ø¿ô mtext_property_end () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤Î½ªÎ»°ÌÃÖ
2393 ¤òÊÖ¤¹¡£½ªÎ»°ÌÃÖ¤È¤Ï M-text Ãæ¤Ç $PROP ¤¬½ª¤ëʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$PROP
2394 ¤¬Ê¬Î¥¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢-1 ¤òÊÖ¤¹¡£ */
2397 mtext_property_end (MTextProperty *prop)
2399 return (prop->mt ? prop->end : -1);
2403 @brief Get the topmost text property.
2405 The mtext_get_property () function searches the character at
2406 position $POS in M-text $MT for a text property whose key is $KEY.
2409 If a text property is found, mtext_get_property () returns it. If
2410 there are multiple text properties, it returns the topmost one.
2411 If no such property is found, it returns @c NULL without changing
2412 the external variable #merror_code.
2414 If an error is detected, mtext_get_property () returns @c NULL and
2415 assigns an error code to the external variable #merror_code. */
2418 @brief °ìÈÖ¾å¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÆÀ¤ë.
2420 ´Ø¿ô mtext_get_property () ¤Ï M-text $MT ¤Î°ÌÃÖ $POS ¤Îʸ»ú¤¬¥¡¼
2421 ¤¬ $KEY ¤Ç¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¤«¤É¤¦¤«¤òÄ´¤Ù¤ë¡£
2424 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_get_property () ¤Ï¤½¤ì¤òÊÖ¤¹¡£
2425 Ê£¿ô¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢°ìÈÖ¾å¤Î¤â¤Î¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢³°ÉôÊÑ¿ô
2426 #merror_code ¤òÊѤ¨¤ë¤³¤È¤Ê¤¯ @c NULL ¤òÊÖ¤¹¡£
2428 ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç mtext_get_property () ¤Ï @c NULL ¤òÊÖ¤·¡¢³°
2429 ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
2432 mtext_get_property (MText *mt, int pos, MSymbol key)
2435 MInterval *interval;
2437 M_CHECK_POS (mt, pos, NULL);
2439 plist = get_plist_create (mt, key, 0);
2443 interval = find_interval (plist, pos);
2444 if (! interval->nprops)
2446 return interval->stack[interval->nprops - 1];
2450 @brief Get multiple text properties.
2452 The mtext_get_properties () function searches the character at
2453 $POS in M-text $MT for properties whose key is $KEY. If such
2454 properties are found, they are stored in the memory area pointed
2455 to by $PROPS. $NUM limits the maximum number of stored
2459 If the operation was successful, mtext_get_properties () returns
2460 the number of actually stored properties. If the character at
2461 $POS does not have a property whose key is $KEY, the return value
2462 is 0. If an error is detected, mtext_get_properties () returns -1
2463 and assigns an error code to the external variable #merror_code. */
2466 @brief Ê£¿ô¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÆÀ¤ë.
2468 ´Ø¿ô mtext_get_properties () ¤Ï M-text $MT ¤Î°ÌÃÖ $POS ¤Îʸ»ú¤¬¥¡¼
2469 ¤¬ $KEY ¤Ç¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¤«¤É¤¦¤«¤òÄ´¤Ù¤ë¡£¤½¤Î¤è¤¦¤Ê
2470 ¥×¥í¥Ñ¥Æ¥£¤¬¤ß¤Ä¤«¤ì¤Ð¡¢$PROPS ¤¬»Ø¤¹¥á¥â¥êÎΰè¤ËÊݸ¤¹¤ë¡£$NUM ¤Ï
2471 Êݸ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¤Î¿ô¤Î¾å¸Â¤Ç¤¢¤ë¡£
2474 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_get_properties () ¤Ï¼ÂºÝ¤ËÊݸ¤·¤¿¥×¥í¥Ñ¥Æ¥£
2475 ¤Î¿ô¤òÊÖ¤¹¡£$POS ¤Î°ÌÃÖ¤Îʸ»ú¤¬¥¡¼¤¬ $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿
2476 ¤Ê¤±¤ì¤Ð¡¢0 ¤¬Ê֤롣¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ë¤Ï¡¢
2477 mtext_get_properties () ¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼
2478 ¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
2481 mtext_get_properties (MText *mt, int pos, MSymbol key,
2482 MTextProperty **props, int num)
2485 MInterval *interval;
2490 M_CHECK_POS (mt, pos, -1);
2492 plist = get_plist_create (mt, key, 0);
2496 interval = find_interval (plist, pos);
2497 /* It is assured that INTERVAL is not NULL. */
2498 nprops = interval->nprops;
2499 if (nprops == 0 || num <= 0)
2501 if (nprops == 1 || num == 1)
2503 props[0] = interval->stack[nprops - 1];
2508 num = nprops, offset = 0;
2510 offset = nprops - num;
2511 for (i = 0; i < num; i++)
2512 props[i] = interval->stack[offset + i];
2517 @brief Attach a text property to an M-text.
2519 The mtext_attach_property () function attaches text property $PROP
2520 to the range between $FROM and $TO in M-text $MT. If $PROP is
2521 already attached to an M-text, it is detached before attached to
2525 If the operation was successful, mtext_attach_property () returns
2526 0. Otherwise it returns -1 and assigns an error code to the
2527 external variable #merror_code. */
2530 @brief M-text¤Ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÉղ乤ë.
2532 ´Ø¿ô mtext_attach_property () ¤Ï¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ
2533 ¤Ç¤ÎÎΰè¤Ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤òÉղ乤롣¤â¤· $PROP ¤¬´û¤Ë
2534 M-text ¤ËÉղ䵤ì¤Æ¤¤¤ì¤Ð¡¢$MT ¤ËÉղ乤ëÁ°¤ËʬΥ¤µ¤ì¤ë¡£
2537 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mtext_attach_property () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±
2538 ¤ì¤Ð -1 ¤òÊÖ¤·¤Æ³°ÉôÊÑ¿ô#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
2542 mtext_attach_property (MText *mt, int from, int to, MTextProperty *prop)
2545 MInterval *interval;
2547 M_CHECK_RANGE (mt, from, to, -1, 0);
2549 M17N_OBJECT_REF (prop);
2551 mtext_detach_property (prop);
2552 prepare_to_modify (mt, from, to, prop->key, 0);
2553 plist = get_plist_create (mt, prop->key, 1);
2554 xassert (check_plist (plist, 0) == 0);
2555 interval = pop_all_properties (plist, from, to);
2556 xassert (check_plist (plist, 0) == 0);
2560 PUSH_PROP (interval, prop);
2561 M17N_OBJECT_UNREF (prop);
2562 xassert (check_plist (plist, 0) == 0);
2564 maybe_merge_interval (plist, interval);
2566 maybe_merge_interval (plist, interval->prev);
2567 xassert (check_plist (plist, 0) == 0);
2572 @brief Detach a text property from an M-text.
2574 The mtext_detach_property () function makes text property $PROP
2578 This function always returns 0. */
2581 @brief M-text ¤«¤é¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òʬΥ¤¹¤ë.
2583 ´Ø¿ô mtext_detach_property () ¤Ï¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤òʬΥ¤¹¤ë¡£
2586 ¤³¤Î´Ø¿ô¤Ï¾ï¤Ë 0 ¤òÊÖ¤¹¡£ */
2589 mtext_detach_property (MTextProperty *prop)
2592 int start = prop->start, end = prop->end;
2596 prepare_to_modify (prop->mt, start, end, prop->key, 0);
2597 plist = get_plist_create (prop->mt, prop->key, 0);
2599 detach_property (plist, prop, NULL);
2604 @brief Push a text property onto an M-text.
2606 The mtext_push_property () function pushes text property $PROP to
2607 the characters between $FROM (inclusive) and $TO (exclusive) in
2611 If the operation was successful, mtext_push_property () returns
2612 0. Otherwise it returns -1 and assigns an error code to the
2613 external variable #merror_code. */
2616 @brief M-text ¤Ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥×¥Ã¥·¥å¤¹¤ë.
2618 ´Ø¿ô mtext_push_property () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤ò¡¢
2619 M-text $MT Ãæ¤Î $FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë¤«¤é $TO ¡Ê´Þ¤Þ¤ì¤Ê¤¤¡Ë¤ÎÈϰϤÎ
2620 ʸ»ú¤Ë¥×¥Ã¥·¥å¤¹¤ë¡£
2623 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mtext_push_property () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±
2624 ¤ì¤Ð -1 ¤òÊÖ¤·¤Æ³°ÉôÊÑ¿ô#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
2628 mtext_push_property (MText *mt, int from, int to, MTextProperty *prop)
2631 MInterval *head, *tail, *interval;
2632 int check_head, check_tail;
2634 M_CHECK_RANGE (mt, from, to, -1, 0);
2636 M17N_OBJECT_REF (prop);
2638 mtext_detach_property (prop);
2639 prepare_to_modify (mt, from, to, prop->key, 0);
2640 plist = get_plist_create (mt, prop->key, 1);
2645 /* Find an interval that covers the position FROM. */
2646 head = find_interval (plist, from);
2648 /* If the found interval starts before FROM, divide it at FROM. */
2649 if (head->start < from)
2651 divide_interval (plist, head, from);
2658 /* Find an interval that ends at TO. If TO is not at the end of an
2659 interval, make one that ends at TO. */
2660 if (head->end == to)
2665 else if (head->end > to)
2667 divide_interval (plist, head, to);
2673 tail = find_interval (plist, to);
2679 else if (tail->start == to)
2686 divide_interval (plist, tail, to);
2691 /* Push PROP to the current values of intervals between HEAD and TAIL
2692 (both inclusive). */
2693 for (interval = head; ; interval = interval->next)
2695 PUSH_PROP (interval, prop);
2696 if (interval == tail)
2700 /* If there is a possibility that TAIL now has the same value as the
2701 next one, check it and concatenate them if necessary. */
2702 if (tail->next && check_tail)
2703 maybe_merge_interval (plist, tail);
2705 /* If there is a possibility that HEAD now has the same value as the
2706 previous one, check it and concatenate them if necessary. */
2707 if (head->prev && check_head)
2708 maybe_merge_interval (plist, head->prev);
2710 M17N_OBJECT_UNREF (prop);
2711 xassert (check_plist (plist, 0) == 0);
2716 @brief Symbol for specifying serializer functions.
2718 To serialize a text property, the user must supply a serializer
2719 function for that text property. This is done by giving a symbol
2720 property whose key is #Mtext_prop_serializer and value is a
2721 pointer to an appropriate serializer function.
2724 mtext_serialize (), #MTextPropSerializeFunc
2728 @brief ¥·¥ê¥¢¥é¥¤¥¶´Ø¿ô¤ò»ØÄꤹ¤ë¥·¥ó¥Ü¥ë.
2730 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥·¥ê¥¢¥é¥¤¥º¤¹¤ë¤¿¤á¤Ë¤Ï¡¢¤½¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ
2731 ¥Æ¥£ÍѤΥ·¥ê¥¢¥é¥¤¥¶´Ø¿ô¤òÍ¿¤¨¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¶ñÂÎŪ¤Ë¤Ï¡¢
2732 #Mtext_prop_serializer ¤ò¥¡¼¤È¤·¡¢Å¬Àڤʥ·¥ê¥¢¥é¥¤¥º´Ø¿ô¤Ø¤Î¥Ý¥¤
2733 ¥ó¥¿¤òÃͤȤ¹¤ë¥·¥ó¥Ü¥ë¥×¥í¥Ñ¥Æ¥£¤ò»ØÄꤹ¤ë¡£
2736 mtext_serialize (), #MTextPropSerializeFunc
2738 MSymbol Mtext_prop_serializer;
2741 @brief Symbol for specifying deserializer functions.
2743 To deserialize a text property, the user must supply a deserializer
2744 function for that text property. This is done by giving a symbol
2745 property whose key is #Mtext_prop_deserializer and value is a
2746 pointer to an appropriate deserializer function.
2749 mtext_deserialize (), #MTextPropSerializeFunc
2753 @brief ¥Ç¥·¥ê¥¢¥é¥¤¥¶´Ø¿ô¤ò»ØÄꤹ¤ë¥·¥ó¥Ü¥ë.
2755 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤¹¤ë¤¿¤á¤Ë¤Ï¡¢¤½¤Î¥Æ¥¥¹¥È¥×¥í
2756 ¥Ñ¥Æ¥£ÍѤΥǥ·¥ê¥¢¥é¥¤¥¶´Ø¿ô¤òÍ¿¤¨¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¶ñÂÎŪ¤Ë¤Ï¡¢
2757 #Mtext_prop_deserializer ¤ò¥¡¼¤È¤·¡¢Å¬Àڤʥǥ·¥ê¥¢¥é¥¤¥º´Ø¿ô¤Ø¤Î
2758 ¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥·¥ó¥Ü¥ë¥×¥í¥Ñ¥Æ¥£¤ò»ØÄꤹ¤ë¡£
2761 mtext_deserialize (), #MTextPropSerializeFunc
2763 MSymbol Mtext_prop_deserializer;
2766 @brief Serialize text properties in an M-text.
2768 The mtext_serialize () function serializes the text between $FROM
2769 and $TO in M-text $MT. The serialized result is an M-text in a
2770 form of XML. $PROPERTY_LIST limits the text properties to be
2771 serialized. Only those text properties whose key
2773 @li appears as the value of an element in $PROPERTY_LIST, and
2774 @li has the symbol property #Mtext_prop_serializer
2776 are serialized as a "property" element in the resulting XML
2779 The DTD of the generated XML is as follows:
2783 <!ELEMENT mtext (property*,body+)>
2784 <!ELEMENT property EMPTY>
2785 <!ELEMENT body (#PCDATA)>
2786 <!ATTLIST property key CDATA #REQUIRED>
2787 <!ATTLIST property value CDATA #REQUIRED>
2788 <!ATTLIST property from CDATA #REQUIRED>
2789 <!ATTLIST property to CDATA #REQUIRED>
2790 <!ATTLIST property control CDATA #REQUIRED>
2794 This function depends on the libxml2 library. If the m17n library
2795 is configured without libxml2, this function always fails.
2798 If the operation was successful, mtext_serialize () returns an
2799 M-text in the form of XML. Otherwise it returns @c NULL and assigns an
2800 error code to the external variable #merror_code.
2803 mtext_deserialize (), #Mtext_prop_serializer */
2806 @brief M-text Ãæ¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥·¥ê¥¢¥é¥¤¥º¤¹¤ë.
2808 ´Ø¿ô mtext_serialize () ¤Ï M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥
2809 ¥¹¥È¤ò¥·¥ê¥¢¥é¥¤¥º¤¹¤ë¡£¥·¥ê¥¢¥é¥¤¥º¤·¤¿·ë²Ì¤Ï XML ·Á¼°¤Î M-text ¤Ç
2810 ¤¢¤ë¡£ $PROPERTY_LIST ¤Ï¥·¥ê¥¢¥é¥¤¥º¤µ¤ì¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¸ÂÄê
2811 ¤¹¤ë¡£ÂоݤȤʤë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¡¢¤½¤Î¥¡¼¤¬
2813 @li $PROPERTY_LIST ¤ÎÍ×ÁǤÎÃͤȤ·¤Æ¸½¤ï¤ì¡¢¤«¤Ä
2814 @li ¥·¥ó¥Ü¥ë¥×¥í¥Ñ¥Æ¥£ #Mtext_prop_serializer ¤ò»ý¤Ä
2816 ¤â¤Î¤Î¤ß¤Ç¤¢¤ë¡£¤³¤Î¾ò·ï¤òËþ¤¿¤¹¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¡¢À¸À®¤µ¤ì¤ë
2817 XML ɽ¸½Ãæ¤Ç "property" Í×ÁǤ˥·¥ê¥¢¥é¥¤¥º¤µ¤ì¤ë¡£
2819 À¸À®¤µ¤ì¤ë XML ¤Î DTD ¤Ï°Ê²¼¤ÎÄ̤ê:
2823 <!ELEMENT mtext (property*,body+)>
2824 <!ELEMENT property EMPTY>
2825 <!ELEMENT body (#PCDATA)>
2826 <!ATTLIST property key CDATA #REQUIRED>
2827 <!ATTLIST property value CDATA #REQUIRED>
2828 <!ATTLIST property from CDATA #REQUIRED>
2829 <!ATTLIST property to CDATA #REQUIRED>
2830 <!ATTLIST property control CDATA #REQUIRED>
2834 ¤³¤Î´Ø¿ô¤Ï libxml2 ¥é¥¤¥Ö¥é¥ê¤Ë°Í¸¤¹¤ë¡£m17n ¥é¥¤¥Ö¥é¥ê¤¬libxml2
2835 ̵¤·¤ËÀßÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç¡¢¤³¤Î´Ø¿ô¤Ï¾ï¤Ë¼ºÇÔ¤¹¤ë¡£
2838 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mtext_serialize () ¤Ï XML ·Á¼°¤Ç M-text ¤òÊÖ¤¹¡£
2839 ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¤Æ³°ÉôÊÑ¿ô#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É
2843 mtext_deserialize (), #Mtext_prop_serializer */
2846 mtext_serialize (MText *mt, int from, int to, MPlist *property_list)
2850 MTextPropSerializeFunc func;
2857 M_CHECK_RANGE (mt, from, to, NULL, NULL);
2858 if (mt->format != MTEXT_FORMAT_US_ASCII
2859 && mt->format != MTEXT_FORMAT_UTF_8)
2860 mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
2861 if (MTEXT_DATA (mt)[mtext_nbytes (mt)] != 0)
2862 MTEXT_DATA (mt)[mtext_nbytes (mt)] = 0;
2863 doc = xmlParseMemory (XML_TEMPLATE, strlen (XML_TEMPLATE) + 1);
2864 node = xmlDocGetRootElement (doc);
2867 MPLIST_DO (pl, property_list)
2869 MSymbol key = MPLIST_VAL (pl);
2871 func = ((MTextPropSerializeFunc)
2872 msymbol_get_func (key, Mtext_prop_serializer));
2874 extract_text_properties (mt, from, to, key, plist);
2878 MPLIST_DO (pl, plist)
2880 MTextProperty *prop = MPLIST_VAL (pl);
2882 MPlist *serialized_plist;
2885 func = ((MTextPropSerializeFunc)
2886 msymbol_get_func (prop->key, Mtext_prop_serializer));
2887 serialized_plist = (func) (prop->val);
2888 if (! serialized_plist)
2891 mplist__serialize (work, serialized_plist, 0);
2892 child = xmlNewChild (node, NULL, (xmlChar *) "property", NULL);
2893 xmlSetProp (child, (xmlChar *) "key",
2894 (xmlChar *) MSYMBOL_NAME (prop->key));
2895 xmlSetProp (child, (xmlChar *) "value", (xmlChar *) MTEXT_DATA (work));
2896 sprintf (buf, "%d", prop->start - from);
2897 xmlSetProp (child, (xmlChar *) "from", (xmlChar *) buf);
2898 sprintf (buf, "%d", prop->end - from);
2899 xmlSetProp (child, (xmlChar *) "to", (xmlChar *) buf);
2900 sprintf (buf, "%d", prop->control.flag);
2901 xmlSetProp (child, (xmlChar *) "control", (xmlChar *) buf);
2902 xmlAddChild (node, xmlNewText ((xmlChar *) "\n"));
2904 M17N_OBJECT_UNREF (serialized_plist);
2906 M17N_OBJECT_UNREF (plist);
2908 if (from > 0 || to < mtext_nchars (mt))
2909 mtext_copy (work, 0, mt, from, to);
2912 M17N_OBJECT_UNREF (work);
2915 for (from = 0, to = mtext_nchars (mt); from <= to; from++)
2917 ptr = MTEXT_DATA (mt) + POS_CHAR_TO_BYTE (mt, from);
2918 xmlNewTextChild (node, NULL, (xmlChar *) "body", (xmlChar *) ptr);
2919 from = mtext_character (mt, from, to, 0);
2924 xmlDocDumpMemoryEnc (doc, (xmlChar **) &ptr, &n, "UTF-8");
2927 mtext__cat_data (work, ptr, n, MTEXT_FORMAT_UTF_8);
2929 #else /* not HAVE_XML2 */
2930 MERROR (MERROR_TEXTPROP, NULL);
2931 #endif /* not HAVE_XML2 */
2935 @brief Deserialize text properties in an M-text.
2937 The mtext_deserialize () function deserializes M-text $MT. $MT
2938 must be an XML having the following DTD.
2942 <!ELEMENT mtext (property*,body+)>
2943 <!ELEMENT property EMPTY>
2944 <!ELEMENT body (#PCDATA)>
2945 <!ATTLIST property key CDATA #REQUIRED>
2946 <!ATTLIST property value CDATA #REQUIRED>
2947 <!ATTLIST property from CDATA #REQUIRED>
2948 <!ATTLIST property to CDATA #REQUIRED>
2949 <!ATTLIST property control CDATA #REQUIRED>
2953 This function depends on the libxml2 library. If the m17n library
2954 is configured without libxml2, this function always fail.
2957 If the operation was successful, mtext_deserialize () returns the
2958 resulting M-text. Otherwise it returns @c NULL and assigns an error
2959 code to the external variable #merror_code.
2962 mtext_serialize (), #Mtext_prop_deserializer */
2965 @brief M-text Ãæ¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤¹¤ë.
2967 ´Ø¿ô mtext_deserialize () ¤Ï M-text $MT ¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤¹¤ë¡£$MT
2968 ¤Ï¼¡¤Î DTD ¤ò»ý¤Ä XML ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2972 <!ELEMENT mtext (property*,body+)>
2973 <!ELEMENT property EMPTY>
2974 <!ELEMENT body (#PCDATA)>
2975 <!ATTLIST property key CDATA #REQUIRED>
2976 <!ATTLIST property value CDATA #REQUIRED>
2977 <!ATTLIST property from CDATA #REQUIRED>
2978 <!ATTLIST property to CDATA #REQUIRED>
2979 <!ATTLIST property control CDATA #REQUIRED>
2983 ¤³¤Î´Ø¿ô¤Ï libxml2 ¥é¥¤¥Ö¥é¥ê¤Ë°Í¸¤¹¤ë¡£m17n ¥é¥¤¥Ö¥é¥ê¤¬libxml2
2984 ̵¤·¤ËÀßÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç¡¢¤³¤Î´Ø¿ô¤Ï¾ï¤Ë¼ºÇÔ¤¹¤ë¡£
2987 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mtext_serialize () ¤ÏÆÀ¤é¤ì¤¿ M-text ¤ò
2988 ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¤Æ³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼
2992 mtext_serialize (), #Mtext_prop_deserializer */
2995 mtext_deserialize (MText *mt)
3000 xmlXPathContextPtr context;
3001 xmlXPathObjectPtr result;
3002 xmlChar *body_str, *key_str, *val_str, *from_str, *to_str, *ctl_str;
3005 if (mt->format > MTEXT_FORMAT_UTF_8)
3006 MERROR (MERROR_TEXTPROP, NULL);
3007 doc = xmlParseMemory ((char *) MTEXT_DATA (mt), mtext_nbytes (mt));
3009 MERROR (MERROR_TEXTPROP, NULL);
3010 node = xmlDocGetRootElement (doc);
3014 MERROR (MERROR_TEXTPROP, NULL);
3016 if (xmlStrcmp (node->name, (xmlChar *) "mtext"))
3019 MERROR (MERROR_TEXTPROP, NULL);
3022 context = xmlXPathNewContext (doc);
3023 result = xmlXPathEvalExpression ((xmlChar *) "//body", context);
3024 if (xmlXPathNodeSetIsEmpty (result->nodesetval))
3027 MERROR (MERROR_TEXTPROP, NULL);
3029 for (i = 0, mt = mtext (); i < result->nodesetval->nodeNr; i++)
3032 mtext_cat_char (mt, 0);
3033 node = (xmlNodePtr) result->nodesetval->nodeTab[i];
3034 body_str = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
3037 mtext__cat_data (mt, body_str, strlen ((char *) body_str),
3038 MTEXT_FORMAT_UTF_8);
3043 result = xmlXPathEvalExpression ((xmlChar *) "//property", context);
3044 if (! xmlXPathNodeSetIsEmpty (result->nodesetval))
3045 for (i = 0; i < result->nodesetval->nodeNr; i++)
3048 MTextPropDeserializeFunc func;
3049 MTextProperty *prop;
3051 int from, to, control;
3054 key_str = xmlGetProp (result->nodesetval->nodeTab[i],
3056 val_str = xmlGetProp (result->nodesetval->nodeTab[i],
3057 (xmlChar *) "value");
3058 from_str = xmlGetProp (result->nodesetval->nodeTab[i],
3059 (xmlChar *) "from");
3060 to_str = xmlGetProp (result->nodesetval->nodeTab[i],
3062 ctl_str = xmlGetProp (result->nodesetval->nodeTab[i],
3063 (xmlChar *) "control");
3065 key = msymbol ((char *) key_str);
3066 func = ((MTextPropDeserializeFunc)
3067 msymbol_get_func (key, Mtext_prop_deserializer));
3070 plist = mplist__from_string (val_str, strlen ((char *) val_str));
3073 if (sscanf ((char *) from_str, "%d", &from) != 1
3074 || from < 0 || from >= mtext_nchars (mt))
3076 if (sscanf ((char *) to_str, "%d", &to) != 1
3077 || to <= from || to > mtext_nchars (mt))
3079 if (sscanf ((char *) ctl_str, "%d", &control) != 1
3080 || control < 0 || control > MTEXTPROP_CONTROL_MAX)
3082 val = (func) (plist);
3083 M17N_OBJECT_UNREF (plist);
3084 prop = mtext_property (key, val, control);
3085 if (key->managing_key)
3086 M17N_OBJECT_UNREF (val);
3087 mtext_push_property (mt, from, to, prop);
3088 M17N_OBJECT_UNREF (prop);
3096 xmlXPathFreeContext (context);
3099 #else /* not HAVE_XML2 */
3100 MERROR (MERROR_TEXTPROP, NULL);
3101 #endif /* not HAVE_XML2 */