1 /* textprop.c -- text property module.
2 Copyright (C) 2003, 2004
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., 59 Temple Place, Suite 330, Boston, MA
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 poistions 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 KEY is
1025 Mnil, we are going to delete text, thus both strongly and weakly
1026 volatile properties must be deleted. Otherwise we are going to
1027 modify a text property KEY, thus only strongly volatile properties
1028 whose key is not KEY must be deleted. */
1031 prepare_to_modify (MText *mt, int from, int to, MSymbol key)
1033 MTextPlist *plist = mt->plist, *prev = NULL;
1034 int mask_bits = MTEXTPROP_VOLATILE_STRONG;
1035 int deleting = (key == Mnil) && (from < to);
1038 mask_bits |= MTEXTPROP_VOLATILE_WEAK;
1041 if (plist->key != key
1042 && ! delete_properties (plist, from, to, mask_bits, deleting))
1045 plist = prev->next = free_textplist (plist);
1047 plist = mt->plist = free_textplist (plist);
1050 prev = plist, plist = plist->next;
1055 extract_text_properties (MText *mt, int from, int to, MSymbol key,
1059 MTextPlist *list = get_plist_create (mt, key, 0);
1060 MInterval *interval;
1064 interval = find_interval (list, from);
1065 if (interval->nprops == 0
1066 && interval->start <= from && interval->end >= to)
1069 while (interval && interval->start < to)
1071 if (interval->nprops == 0)
1072 top = mplist_find_by_key (top, Mnil);
1075 MPlist *current = top, *place;
1078 for (i = 0; i < interval->nprops; i++)
1080 MTextProperty *prop = interval->stack[i];
1082 place = mplist_find_by_value (current, prop);
1084 current = MPLIST_NEXT (place);
1087 place = mplist_find_by_value (top, prop);
1091 if (MPLIST_NEXT (place) == MPLIST_NEXT (current))
1094 mplist_push (current, Mt, prop);
1095 current = MPLIST_NEXT (current);
1099 interval = interval->next;
1104 #define XML_TEMPLATE "<?xml version=\"1.0\" ?>\n\
1105 <!DOCTYPE mtext [\n\
1106 <!ELEMENT mtext (property*,body+)>\n\
1107 <!ELEMENT property EMPTY>\n\
1108 <!ELEMENT body (#PCDATA)>\n\
1109 <!ATTLIST property key CDATA #REQUIRED>\n\
1110 <!ATTLIST property value CDATA #REQUIRED>\n\
1111 <!ATTLIST property from CDATA #REQUIRED>\n\
1112 <!ATTLIST property to CDATA #REQUIRED>\n\
1113 <!ATTLIST property control CDATA #REQUIRED>\n\
1119 /* for debugging... */
1123 dump_interval (MInterval *interval, int indent)
1125 char *prefix = (char *) alloca (indent + 1);
1128 memset (prefix, 32, indent);
1131 fprintf (stderr, "(interval %d-%d (%d)", interval->start, interval->end,
1133 for (i = 0; i < interval->nprops; i++)
1134 fprintf (stderr, "\n%s (%d %d/%d %d-%d 0x%x)",
1136 interval->stack[i]->control.ref_count,
1137 interval->stack[i]->attach_count,
1138 interval->stack[i]->start, interval->stack[i]->end,
1139 (unsigned) interval->stack[i]->val);
1140 fprintf (stderr, ")");
1144 dump_textplist (MTextPlist *plist, int indent)
1146 char *prefix = (char *) alloca (indent + 1);
1148 memset (prefix, 32, indent);
1151 fprintf (stderr, "(properties");
1153 fprintf (stderr, ")\n");
1156 fprintf (stderr, "\n");
1159 MInterval *interval = plist->head;
1161 fprintf (stderr, "%s (%s", prefix, msymbol_name (plist->key));
1164 fprintf (stderr, " (%d %d", interval->start, interval->end);
1165 if (interval->nprops > 0)
1169 for (i = 0; i < interval->nprops; i++)
1170 fprintf (stderr, " 0x%x", (int) interval->stack[i]->val);
1172 fprintf (stderr, ")");
1173 interval = interval->next;
1175 fprintf (stderr, ")\n");
1176 xassert (check_plist (plist, 0) == 0);
1177 plist = plist->next;
1188 M17N_OBJECT_ADD_ARRAY (text_property_table, "Text property");
1189 Mtext_prop_serializer = msymbol ("text-prop-serializer");
1190 Mtext_prop_deserializer = msymbol ("text-prop-deserializer");
1197 MIntervalPool *pool = interval_pool_root.next;
1201 MIntervalPool *next = pool->next;
1205 interval_pool_root.next = NULL;
1209 /** Free all plists. */
1212 mtext__free_plist (MText *mt){
1214 MTextPlist *plist = mt->plist;
1217 plist = free_textplist (plist);
1222 /** Extract intervals between FROM and TO of all properties (except
1223 for volatile ones) in PLIST, and make a new plist from them for
1227 mtext__copy_plist (MTextPlist *plist, int from, int to, MText *mt, int pos)
1229 MTextPlist *copy, *this;
1233 for (copy = NULL; plist && ! copy; plist = plist->next)
1234 copy = copy_single_property (plist, from, to, mt, pos);
1237 for (; plist; plist = plist->next)
1238 if ((this = copy_single_property (plist, from, to, mt, pos)))
1248 mtext__adjust_plist_for_delete (MText *mt, int pos, int len)
1253 if (len == 0 || pos == mt->nchars)
1255 if (len == mt->nchars)
1257 mtext__free_plist (mt);
1262 prepare_to_modify (mt, pos, to, Mnil);
1263 for (plist = mt->plist; plist; plist = plist->next)
1265 MInterval *interval = pop_all_properties (plist, pos, to);
1266 MInterval *prev = interval->prev, *next = interval->next;
1274 adjust_intervals (next, plist->tail, -len);
1280 next = maybe_merge_interval (plist, prev);
1281 plist->cache = next ? next : prev;
1282 free_interval (interval);
1283 xassert (check_plist (plist, 0) == 0);
1288 mtext__adjust_plist_for_insert (MText *mt, int pos, int nchars,
1291 MTextPlist *pl, *pl_last, *pl2, *p;
1293 MInterval *interval;
1295 if (mt->nchars == 0)
1297 mtext__free_plist (mt);
1301 if (pos > 0 && pos < mtext_nchars (mt))
1302 prepare_to_modify (mt, pos, pos, Mnil);
1304 for (pl_last = NULL, pl = mt->plist; pl; pl_last = pl, pl = pl->next)
1306 MInterval *interval, *prev, *next, *head, *tail;
1309 prev = NULL, next = pl->head;
1310 else if (pos == mtext_nchars (mt))
1311 prev = pl->tail, next = NULL;
1314 next = find_interval (pl, pos);
1315 if (next->start < pos)
1317 divide_interval (pl, next, pos);
1320 for (i = 0; i < next->nprops; i++)
1321 if (next->stack[i]->start < pos)
1322 split_property (next->stack[i], next);
1326 xassert (check_plist (pl, 0) == 0);
1327 for (p = NULL, pl2 = plist; pl2 && pl->key != pl2->key;
1328 p = pl2, pl2 = p->next);
1331 xassert (check_plist (pl2, pl2->head->start) == 0);
1333 p->next = pl2->next;
1335 plist = plist->next;
1343 head = tail = new_interval (pos, pos + nchars);
1356 adjust_intervals (next, pl->tail, nchars);
1358 xassert (check_plist (pl, 0) == 0);
1359 if (prev && prev->nprops > 0)
1361 for (interval = prev;
1362 interval->next != next && interval->next->nprops == 0;
1363 interval = interval->next)
1364 for (i = 0; i < interval->nprops; i++)
1366 MTextProperty *prop = interval->stack[i];
1368 if (prop->control.flag & MTEXTPROP_REAR_STICKY)
1369 PUSH_PROP (interval->next, prop);
1372 xassert (check_plist (pl, 0) == 0);
1373 if (next && next->nprops > 0)
1375 for (interval = next;
1376 interval->prev != prev && interval->prev->nprops == 0;
1377 interval = interval->prev)
1378 for (i = 0; i < interval->nprops; i++)
1380 MTextProperty *prop = interval->stack[i];
1382 if (prop->control.flag & MTEXTPROP_FRONT_STICKY)
1383 PUSH_PROP (interval->prev, prop);
1387 interval = prev ? prev : pl->head;
1388 pl->cache = interval;
1389 while (interval && interval->start <= pos + nchars)
1390 interval = maybe_merge_interval (pl, interval);
1391 xassert (check_plist (pl, 0) == 0);
1395 pl_last->next = plist;
1399 for (; plist; plist = plist->next)
1401 plist->cache = plist->head;
1404 if (plist->head->nprops)
1406 interval = new_interval (0, pos);
1407 interval->next = plist->head;
1408 plist->head->prev = interval;
1409 plist->head = interval;
1412 plist->head->start = 0;
1414 if (pos < mtext_nchars (mt))
1416 if (plist->tail->nprops)
1418 interval = new_interval (pos + nchars,
1419 mtext_nchars (mt) + nchars);
1420 interval->prev = plist->tail;
1421 plist->tail->next = interval;
1422 plist->tail = interval;
1425 plist->tail->end = mtext_nchars (mt) + nchars;
1427 xassert (check_plist (plist, 0) == 0);
1432 mtext__adjust_plist_for_change (MText *mt, int from, int to)
1436 prepare_to_modify (mt, from, to, Mnil);
1437 for (plist = mt->plist; plist; plist = plist->next)
1439 pop_all_properties (plist, from, to);
1440 xassert (check_plist (plist, 0) == 0);
1446 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1451 /*** @addtogroup m17nTextProperty */
1456 @brief Get the value of the topmost text property.
1458 The mtext_get_prop () function searches the character at $POS in
1459 M-text $MT for the text property whose key is $KEY.
1462 If a text property is found, mtext_get_prop () returns the value
1463 of the property. If the property has multiple values, it returns
1464 the topmost one. If no such property is found, it returns @c NULL
1465 without changing the external variable #merror_code.
1467 If an error is detected, mtext_get_prop () returns @c NULL and
1468 assigns an error code to the external variable #merror_code.
1470 @note If @c NULL is returned without an error, there are two
1473 @li the character at $POS does not have a property whose key is $KEY, or
1475 @li the character does have such a property and its value is @c NULL.
1477 If you need to distinguish these two cases, use the
1478 mtext_get_prop_values () function instead. */
1481 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î°ìÈÖ¾å¤ÎÃͤòÆÀ¤ë.
1483 ´Ø¿ô mtext_get_prop () ¤Ï¡¢M-text $MT Æâ¤Î°ÌÃÖ $POS ¤Ë¤¢¤ëʸ»ú¤Î¥Æ
1484 ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥¡¼¤¬ $KEY ¤Ç¤¢¤ë¤â¤Î¤òõ¤¹¡£
1487 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬¤ß¤Ä¤«¤ì¤Ð¡¢mtext_get_prop () ¤Ï¤½¤Î¥×¥í¥Ñ¥Æ¥£
1488 ¤ÎÃͤòÊÖ¤¹¡£Ãͤ¬Ê£¿ô¸ºß¤¹¤ë¤È¤¤Ï¡¢°ìÈÖ¾å¤ÎÃͤòÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±
1489 ¤ì¤Ð³°ÉôÊÑ¿ô #merror_code ¤òÊѹ¹¤¹¤ë¤³¤È¤Ê¤¯ @c NULL ¤òÊÖ¤¹¡£
1491 ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç mtext_get_prop () ¤Ï @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ
1492 ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1494 @note ¥¨¥é¡¼¤Ê¤·¤Ç @c NULL ¤¬ÊÖ¤µ¤ì¤¿¾ì¹ç¤Ë¤ÏÆó¤Ä¤Î²ÄǽÀ¤¬¤¢¤ë¡£
1496 @li $POS ¤Î°ÌÃÖ¤Îʸ»ú¤Ï $KEY ¤ò¥¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤¡£
1498 @li ¤½¤Îʸ»ú¤Ï¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤ¬ @c NULL ¤Ç¤¢¤ë¡£
1500 ¤³¤ÎÆó¤Ä¤ò¶èÊ̤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢´Ø¿ô mtext_get_prop_values ()
1501 ¤òÂå¤ï¤ê¤Ë»ÈÍѤ¹¤ë¤³¤È¡£
1503 @latexonly \IPAlabel{mtext_get_prop} @endlatexonly */
1507 @c MERROR_RANGE, @c MERROR_SYMBOL
1510 mtext_get_prop_values (), mtext_put_prop (), mtext_put_prop_values (),
1511 mtext_push_prop (), mtext_pop_prop (), mtext_prop_range () */
1514 mtext_get_prop (MText *mt, int pos, MSymbol key)
1517 MInterval *interval;
1520 M_CHECK_POS (mt, pos, NULL);
1522 plist = get_plist_create (mt, key, 0);
1526 interval = find_interval (plist, pos);
1527 val = (interval->nprops
1528 ? interval->stack[interval->nprops - 1]->val : NULL);
1535 @brief Get multiple values of a text property.
1537 The mtext_get_prop_values () function searches the character at
1538 $POS in M-text $MT for the property whose key is $KEY. If such
1539 a property is found, its values are stored in the memory area
1540 pointed to by $VALUES. $NUM limits the maximum number of stored
1544 If the operation was successful, mtext_get_prop_values () returns
1545 the number of actually stored values. If the character at $POS
1546 does not have a property whose key is $KEY, the return value is
1547 0. If an error is detected, mtext_get_prop_values () returns -1 and
1548 assigns an error code to the external variable #merror_code. */
1551 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊ£¿ô¸ÄÆÀ¤ë.
1553 ´Ø¿ô mtext_get_prop_values () ¤Ï¡¢M-text $MT Æâ¤Ç $POS ¤È¤¤¤¦°ÌÃÖ
1554 ¤Ë¤¢¤ëʸ»ú¤Î¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥¡¼¤¬ $KEY ¤Ç¤¢¤ë¤â¤Î¤òõ¤¹¡£¤â¤·¤½
1555 ¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤¬»ý¤ÄÃÍ (Ê£¿ô²Ä) ¤ò $VALUES
1556 ¤Î»Ø¤¹¥á¥â¥êÎΰè¤Ë³ÊǼ¤¹¤ë¡£$NUM ¤Ï³ÊǼ¤¹¤ëÃͤοô¤Î¾å¸Â¤Ç¤¢¤ë¡£
1559 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_get_prop_values () ¤Ï¼ÂºÝ¤Ë¥á¥â¥ê¤Ë³ÊǼ¤µ
1560 ¤ì¤¿Ãͤοô¤òÊÖ¤¹¡£$POS ¤Î°ÌÃÖ¤Îʸ»ú¤¬ $KEY ¤ò¥¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£
1561 ¤ò»ý¤¿¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°Éô
1562 ÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1564 @latexonly \IPAlabel{mtext_get_prop_values} @endlatexonly */
1568 @c MERROR_RANGE, @c MERROR_SYMBOL
1571 mtext_get_prop (), mtext_put_prop (), mtext_put_prop_values (),
1572 mtext_push_prop (), mtext_pop_prop (), mtext_prop_range () */
1575 mtext_get_prop_values (MText *mt, int pos, MSymbol key,
1576 void **values, int num)
1579 MInterval *interval;
1584 M_CHECK_POS (mt, pos, -1);
1586 plist = get_plist_create (mt, key, 0);
1590 interval = find_interval (plist, pos);
1591 /* It is assured that INTERVAL is not NULL. */
1592 nprops = interval->nprops;
1593 if (nprops == 0 || num <= 0)
1595 if (nprops == 1 || num == 1)
1597 values[0] = interval->stack[nprops - 1]->val;
1602 num = nprops, offset = 0;
1604 offset = nprops - num;
1605 for (i = 0; i < num; i++)
1606 values[i] = interval->stack[offset + i]->val;
1613 @brief Get a list of text property keys at a position of an M-text.
1615 The mtext_get_prop_keys () function creates an array whose
1616 elements are the keys of text properties found at position $POS in
1617 M-text $MT, and sets *$KEYS to the address of the created array.
1618 The user is responsible to free the memory allocated for
1622 If the operation was successful, mtext_get_prop_keys () returns
1623 the length of the key list. Otherwise it returns -1 and assigns
1624 an error code to the external variable #merror_code.
1629 @brief M-text ¤Î»ØÄꤷ¤¿°ÌÃ֤Υƥ¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¥¡¼¤Î¥ê¥¹¥È¤òÆÀ¤ë.
1631 ´Ø¿ô mtext_get_prop_keys () ¤Ï¡¢M-text $MT Æâ¤Ç $POS ¤Î°ÌÃ֤ˤ¢¤ë
1632 ¤¹¤Ù¤Æ¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¥¡¼¤òÍ×ÁǤȤ¹¤ëÇÛÎó¤òºî¤ê¡¢¤½¤ÎÇÛÎó¤Î
1633 ¥¢¥É¥ì¥¹¤ò *$KEYS ¤ËÀßÄꤹ¤ë¡£¤³¤ÎÇÛÎó¤Î¤¿¤á¤Ë³ÎÊݤµ¤ì¤¿¥á¥â¥ê¤ò²ò
1634 Êü¤¹¤ë¤Î¤Ï¥æ¡¼¥¶¤ÎÀÕǤ¤Ç¤¢¤ë¡£
1637 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_get_prop_keys () ¤ÏÆÀ¤é¤ì¤¿¥ê¥¹¥È¤ÎŤµ¤òÊÖ
1638 ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
1647 mtext_get_prop (), mtext_put_prop (), mtext_put_prop_values (),
1648 mtext_get_prop_values (), mtext_push_prop (), mtext_pop_prop () */
1651 mtext_get_prop_keys (MText *mt, int pos, MSymbol **keys)
1656 M_CHECK_POS (mt, pos, -1);
1657 for (i = 0, plist = mt->plist; plist; i++, plist = plist->next);
1663 MTABLE_MALLOC (*keys, i, MERROR_TEXTPROP);
1664 for (i = 0, plist = mt->plist; plist; plist = plist->next)
1666 MInterval *interval = find_interval (plist, pos);
1668 if (interval->nprops)
1669 (*keys)[i++] = plist->key;
1677 @brief Set a text property.
1679 The mtext_put_prop () function sets a text property to the
1680 characters between $FROM (inclusive) and $TO (exclusive) in M-text
1681 $MT. $KEY and $VAL specify the key and the value of the text
1682 property. With this function,
1686 M-text: |<------------|-------- MT ---------|------------>|
1687 PROP : <------------------ OLD_VAL -------------------->
1694 M-text: |<------------|-------- MT ---------|------------>|
1695 PROP : <-- OLD_VAL-><-------- VAL -------><-- OLD_VAL-->
1699 If the operation was successful, mtext_put_prop () returns 0.
1700 Otherwise it returns -1 and assigns an error code to the external
1701 variable #merror_code. */
1704 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë.
1706 ´Ø¿ô mtext_put_prop () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë¤«¤é
1707 $TO ¡Ê´Þ¤Þ¤ì¤Ê¤¤¡Ë¤ÎÈϰϤÎʸ»ú¤Ë¡¢¥¡¼¤¬ $KEY ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¤è
1708 ¤¦¤Ê¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë¡£¤³¤Î´Ø¿ô¤Ë¤è¤Ã¤Æ
1713 M-text: |<------------|-------- MT ---------|------------>|
1714 PROP: <------------------ OLD_VAL -------------------->
1721 M-text: |<------------|-------- MT ---------|------------>|
1722 PROP: <-- OLD_VAL-><-------- VAL -------><-- OLD_VAL-->
1726 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mtext_put_prop () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1
1727 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1729 @latexonly \IPAlabel{mtext_put_prop} @endlatexonly */
1733 @c MERROR_RANGE, @c MERROR_SYMBOL
1736 mtext_put_prop_values (), mtext_get_prop (),
1737 mtext_get_prop_values (), mtext_push_prop (),
1738 mtext_pop_prop (), mtext_prop_range () */
1741 mtext_put_prop (MText *mt, int from, int to, MSymbol key, void *val)
1744 MTextProperty *prop;
1745 MInterval *interval;
1747 M_CHECK_RANGE (mt, from, to, -1, 0);
1749 prepare_to_modify (mt, from, to, key);
1750 plist = get_plist_create (mt, key, 1);
1751 interval = pop_all_properties (plist, from, to);
1752 prop = new_text_property (mt, from, to, key, val, 0);
1753 PUSH_PROP (interval, prop);
1754 M17N_OBJECT_UNREF (prop);
1756 maybe_merge_interval (plist, interval);
1758 maybe_merge_interval (plist, interval->prev);
1759 xassert (check_plist (plist, 0) == 0);
1766 @brief Set multiple text properties with the same key.
1768 The mtext_put_prop_values () function sets a text property to the
1769 characters between $FROM (inclusive) and $TO (exclusive) in M-text
1770 $MT. $KEY and $VALUES specify the key and the values of the text
1771 property. $NUM specifies the number of property values to be set.
1774 If the operation was successful, mtext_put_prop_values () returns
1775 0. Otherwise it returns -1 and assigns an error code to the
1776 external variable #merror_code. */
1779 @brief Ʊ¤¸¥¡¼¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÊ£¿ôÀßÄꤹ¤ë.
1781 ´Ø¿ô mtext_put_prop_values () ¤Ï¡¢M-Text $MT ¤Î$FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë
1782 ¤«¤é $TO ¡Ê´Þ¤Þ¤ì¤Ê¤¤¡Ë¤ÎÈϰϤÎʸ»ú¤Ë¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ
1783 ¤ë¡£¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¥¡¼¤Ï $KEY ¤Ë¤è¤Ã¤Æ¡¢ÃÍ(Ê£¿ô²Ä)¤Ï $VALUES
1784 ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ë¡£$NUM ¤ÏÀßÄꤵ¤ì¤ëÃͤθĿô¤Ç¤¢¤ë¡£
1787 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_put_prop_values () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±
1788 ¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1790 @latexonly \IPAlabel{mtext_put_prop_values} @endlatexonly */
1794 @c MERROR_RANGE, @c MERROR_SYMBOL
1797 mtext_put_prop (), mtext_get_prop (), mtext_get_prop_values (),
1798 mtext_push_prop (), mtext_pop_prop (), mtext_prop_range () */
1801 mtext_put_prop_values (MText *mt, int from, int to,
1802 MSymbol key, void **values, int num)
1805 MInterval *interval;
1808 M_CHECK_RANGE (mt, from, to, -1, 0);
1810 prepare_to_modify (mt, from, to, key);
1811 plist = get_plist_create (mt, key, 1);
1812 interval = pop_all_properties (plist, from, to);
1815 PREPARE_INTERVAL_STACK (interval, num);
1816 for (i = 0; i < num; i++)
1819 = new_text_property (mt, from, to, key, values[i], 0);
1820 PUSH_PROP (interval, prop);
1821 M17N_OBJECT_UNREF (prop);
1825 maybe_merge_interval (plist, interval);
1827 maybe_merge_interval (plist, interval->prev);
1828 xassert (check_plist (plist, 0) == 0);
1835 @brief Push a text property.
1837 The mtext_push_prop () function pushes a text property whose key
1838 is $KEY and value is $VAL to the characters between $FROM
1839 (inclusive) and $TO (exclusive) in M-text $MT. With this
1844 M-text: |<------------|-------- MT ---------|------------>|
1845 PROP : <------------------ OLD_VAL -------------------->
1852 M-text: |<------------|-------- MT ---------|------------>|
1853 PROP : <------------------- OLD_VAL ------------------->
1854 PROP : <-------- VAL ------->
1858 If the operation was successful, mtext_push_prop () returns 0.
1859 Otherwise it returns -1 and assigns an error code to the external
1860 variable #merror_code. */
1863 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥×¥Ã¥·¥å¤¹¤ë.
1865 ´Ø¿ô mtext_push_prop () ¤Ï¡¢¥¡¼¤¬ $KEY ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥Æ¥¥¹¥È
1866 ¥×¥í¥Ñ¥Æ¥£¤ò¡¢M-text $MT Ãæ¤Î $FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë¤«¤é $TO ¡Ê´Þ¤Þ¤ì¤Ê
1867 ¤¤¡Ë¤ÎÈϰϤÎʸ»ú¤Ë¥×¥Ã¥·¥å¤¹¤ë¡£¤³¤Î´Ø¿ô¤Ë¤è¤Ã¤Æ
1871 M-text: |<------------|-------- MT ---------|------------>|
1872 PROP : <------------------ OLD_VAL -------------------->
1877 M-text: |<------------|-------- MT ---------|------------>|
1878 PROP : <------------------- OLD_VAL ------------------->
1879 PROP : <-------- VAL ------->
1883 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_push_prop () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
1884 -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1886 @latexonly \IPAlabel{mtext_push_prop} @endlatexonly */
1890 @c MERROR_RANGE, @c MERROR_SYMBOL
1893 mtext_put_prop (), mtext_put_prop_values (),
1894 mtext_get_prop (), mtext_get_prop_values (),
1895 mtext_pop_prop (), mtext_prop_range () */
1898 mtext_push_prop (MText *mt, int from, int to,
1899 MSymbol key, void *val)
1902 MInterval *head, *tail, *interval;
1903 MTextProperty *prop;
1904 int check_head, check_tail;
1906 M_CHECK_RANGE (mt, from, to, -1, 0);
1908 prepare_to_modify (mt, from, to, key);
1909 plist = get_plist_create (mt, key, 1);
1911 /* Find an interval that covers the position FROM. */
1912 head = find_interval (plist, from);
1914 /* If the found interval starts before FROM, divide it at FROM. */
1915 if (head->start < from)
1917 divide_interval (plist, head, from);
1924 /* Find an interval that ends at TO. If TO is not at the end of an
1925 interval, make one that ends at TO. */
1926 if (head->end == to)
1931 else if (head->end > to)
1933 divide_interval (plist, head, to);
1939 tail = find_interval (plist, to);
1945 else if (tail->start == to)
1952 divide_interval (plist, tail, to);
1957 prop = new_text_property (mt, from, to, key, val, 0);
1959 /* Push PROP to the current values of intervals between HEAD and TAIL
1960 (both inclusive). */
1961 for (interval = head; ; interval = interval->next)
1963 PUSH_PROP (interval, prop);
1964 if (interval == tail)
1968 M17N_OBJECT_UNREF (prop);
1970 /* If there is a possibility that TAIL now has the same value as the
1971 next one, check it and concatenate them if necessary. */
1972 if (tail->next && check_tail)
1973 maybe_merge_interval (plist, tail);
1975 /* If there is a possibility that HEAD now has the same value as the
1976 previous one, check it and concatenate them if necessary. */
1977 if (head->prev && check_head)
1978 maybe_merge_interval (plist, head->prev);
1980 xassert (check_plist (plist, 0) == 0);
1987 @brief Pop a text property.
1989 The mtext_pop_prop () function removes the topmost text property
1990 whose key is $KEY from the characters between $FROM (inclusive)
1991 and and $TO (exclusive) in $MT.
1993 This function does nothing if characters in the region have no
1994 such text property. With this function,
1998 M-text: |<------------|-------- MT ---------|------------>|
1999 PROP : <------------------ OLD_VAL -------------------->
2006 M-text: |<------------|-------- MT ---------|------------>|
2007 PROP : <--OLD_VAL-->| |<--OLD_VAL-->|
2011 If the operation was successful, mtext_pop_prop () return 0.
2012 Otherwise it returns -1 and assigns an error code to the external
2013 variable #merror_code. */
2016 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥Ý¥Ã¥×¤¹¤ë.
2018 ´Ø¿ô mtext_pop_prop () ¤Ï¡¢¥¡¼¤¬ $KEY ¤Ç¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î
2019 ¤¦¤Á°ìÈÖ¾å¤Î¤â¤Î¤ò¡¢M-text $MT ¤Î $FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë¤«¤é $TO¡Ê´Þ¤Þ
2020 ¤ì¤Ê¤¤¡Ë¤ÎÈϰϤÎʸ»ú¤«¤é¼è¤ê½ü¤¯¡£
2022 »ØÄêÈϰϤÎʸ»ú¤¬¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï²¿
2023 ¤â¤·¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ë¤è¤Ã¤Æ¡¢
2027 M-text: |<------------|-------- MT ---------|------------>|
2028 PROP : <------------------ OLD_VAL -------------------->
2030 ¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
2033 M-text: |<------------|-------- MT ---------|------------>|
2034 PROP : <--OLD_VAL-->| |<--OLD_VAL-->|
2038 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_pop_prop () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1
2039 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2041 @latexonly \IPAlabel{mtext_pop_prop} @endlatexonly */
2045 @c MERROR_RANGE, @c MERROR_SYMBOL
2048 mtext_put_prop (), mtext_put_prop_values (),
2049 mtext_get_prop (), mtext_get_prop_values (),
2050 mtext_push_prop (), mtext_prop_range () */
2053 mtext_pop_prop (MText *mt, int from, int to, MSymbol key)
2056 MInterval *head, *tail;
2060 MERROR (MERROR_TEXTPROP, -1);
2061 M_CHECK_RANGE (mt, from, to, -1, 0);
2062 plist = get_plist_create (mt, key, 0);
2066 /* Find an interval that covers the position FROM. */
2067 head = find_interval (plist, from);
2069 && head->nprops == 0)
2070 /* No property to pop. */
2073 prepare_to_modify (mt, from, to, key);
2075 /* If the found interval starts before FROM and has value(s), divide
2077 if (head->start < from)
2079 if (head->nprops > 0)
2081 divide_interval (plist, head, from);
2089 /* Pop the topmost text property from each interval following HEAD.
2090 Stop at an interval that ends after TO. */
2091 for (tail = head; tail && tail->end <= to; tail = tail->next)
2092 if (tail->nprops > 0)
2097 if (tail->start < to)
2099 if (tail->nprops > 0)
2101 divide_interval (plist, tail, to);
2110 to = plist->tail->start;
2112 /* If there is a possibility that HEAD now has the same text
2113 properties as the previous one, check it and concatenate them if
2115 if (head->prev && check_head)
2117 while (head && head->end <= to)
2118 head = maybe_merge_interval (plist, head);
2120 xassert (check_plist (plist, 0) == 0);
2127 @brief Find the range where the value of a text property is the same.
2129 The mtext_prop_range () function investigates the extent where all
2130 characters have the same value for a text property. It first
2131 finds the value of the property specified by $KEY of the character
2132 at $POS in M-text $MT. Then it checks if adjacent characters have
2133 the same value for the property $KEY. The beginning and the end
2134 of the found range are stored to the variable pointed to by $FROM
2135 and $TO. The character position stored in $FROM is inclusive but
2136 that in $TO is exclusive; this fashion is compatible with the
2137 range specification in the mtext_put_prop () function, etc.
2139 If $DEEPER is not 0, not only the topmost but also all the stacked
2140 properties whose key is $KEY are compared.
2142 If $FROM is @c NULL, the beginning of range is not searched for. If
2143 $TO is @c NULL, the end of range is not searched for.
2147 If the operation was successful, mtext_prop_range () returns the
2148 number of values the property $KEY has at pos. Otherwise it
2149 returns -1 and assigns an error code to the external variable @c
2153 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬Æ±¤¸Ãͤò¤È¤ëÈϰϤòÄ´¤Ù¤ë.
2155 ´Ø¿ô mtext_prop_range () ¤Ï¡¢»ØÄꤷ¤¿¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤ¬Æ±¤¸
2156 ¤Ç¤¢¤ëϢ³¤·¤¿Ê¸»ú¤ÎÈϰϤòÄ´¤Ù¤ë¡£¤Þ¤º M-text $MT ¤Î $POS ¤Î°ÌÃÖ¤Ë
2157 ¤¢¤ëʸ»ú¤Î¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥¡¼ $KEY ¤Ç»ØÄꤵ¤ì¤¿¤â¤ÎÃͤò¸«¤Ä¤±
2158 ¤ë¡£¤½¤·¤ÆÁ°¸å¤Îʸ»ú¤â $KEY ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤ¬Æ±¤¸¤Ç¤¢¤ë¤«¤É¤¦¤«¤ò
2159 Ä´¤Ù¤ë¡£¸«¤Ä¤±¤¿ÈϰϤκǽé¤ÈºÇ¸å¤ò¡¢¤½¤ì¤¾¤ì $FROM ¤È $TO ¤Ë¥Ý¥¤¥ó
2160 ¥È¤µ¤ì¤ëÊÑ¿ô¤ËÊݸ¤¹¤ë¡£$FROM ¤ËÊݸ¤µ¤ì¤ëʸ»ú¤Î°ÌÃ֤ϸ«¤Ä¤±¤¿ÈÏ°Ï
2161 ¤Ë´Þ¤Þ¤ì¤ë¤¬¡¢$TO ¤Ï´Þ¤Þ¤ì¤Ê¤¤¡£¡Ê$TO ¤ÎÁ°¤ÇƱ¤¸Ãͤò¤È¤ëÈϰϤϽª¤ï
2162 ¤ë¡£¡Ë¤³¤ÎÈÏ°Ï»ØÄêË¡¤Ï¡¢´Ø¿ô mtext_put_prop () ¤Ê¤É¤È¶¦Ä̤Ǥ¢¤ë¡£
2164 $DEEPER ¤¬ 0 ¤Ç¤Ê¤±¤ì¤Ð¡¢$KEY ¤È¤¤¤¦¥¡¼¤ò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á°ìÈÖ
2165 ¾å¤Î¤â¤Î¤À¤±¤Ç¤Ê¤¯¡¢¥¹¥¿¥Ã¥¯Ãæ¤Î¤¹¤Ù¤Æ¤Î¤â¤Î¤¬Èæ³Ó¤µ¤ì¤ë¡£
2167 $FROM ¤¬ @c NULL ¤Ê¤é¤Ð¡¢ÈϰϤλϤޤê¤Ïõº÷¤·¤Ê¤¤¡£$TO ¤¬ @c NULL
2168 ¤Ê¤é¤Ð¡¢ÈϰϤνª¤ê¤Ïõº÷¤·¤Ê¤¤¡£
2171 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_prop_range () ¤Ï $KEY ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤοô¤ò
2172 ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð-1 ¤òÊÖ¤·¡¢ ³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
2175 @latexonly \IPAlabel{mtext_prop_range} @endlatexonly */
2179 @c MERROR_RANGE, @c MERROR_SYMBOL
2182 mtext_put_prop (), mtext_put_prop_values (),
2183 mtext_get_prop (), mtext_get_prop_values (),
2184 mtext_pop_prop (), mtext_push_prop () */
2187 mtext_prop_range (MText *mt, MSymbol key, int pos,
2188 int *from, int *to, int deeper)
2191 MInterval *interval, *temp;
2195 M_CHECK_POS (mt, pos, -1);
2197 plist = get_plist_create (mt, key, 0);
2200 if (from) *from = 0;
2201 if (to) *to = mtext_nchars (mt);
2205 interval = find_interval (plist, pos);
2206 nprops = interval->nprops;
2207 if (deeper || ! nprops)
2209 if (from) *from = interval->start;
2210 if (to) *to = interval->end;
2211 return interval->nprops;
2214 val = nprops ? interval->stack[nprops - 1] : NULL;
2218 for (temp = interval;
2220 && (temp->prev->nprops
2222 && (val == temp->prev->stack[temp->prev->nprops - 1]))
2225 *from = temp->start;
2230 for (temp = interval;
2232 && (temp->next->nprops
2234 && val == temp->next->stack[temp->next->nprops - 1])
2244 @brief Create a text property.
2246 The mtext_property () function returns a newly allocated text
2247 property whose key is $KEY and value is $VAL. The created text
2248 property is not attached to any M-text, i.e. it is detached.
2250 $CONTROL_BITS must be 0 or logical OR of @c enum @c
2251 MTextPropertyControl. */
2254 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÀ¸À®¤¹¤ë.
2256 ´Ø¿ô mtext_property () ¤Ï $KEY ¤ò¥¡¼¡¢$VAL ¤òÃͤȤ¹¤ë¿·¤·¤¯³ä¤êÅö
2257 ¤Æ¤é¤ì¤¿¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÊÖ¤¹¡£À¸À®¤·¤¿¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¤¤«
2258 ¤Ê¤ë M-text ¤Ë¤âÉղ䵤ì¤Æ¤¤¤Ê¤¤¡¢¤¹¤Ê¤ï¤ÁʬΥ¤·¤Æ (detached) ¤¤¤ë¡£
2260 $CONTROL_BITS ¤Ï 0 ¤Ç¤¢¤ë¤« @c enum @c MTextPropertyControl ¤ÎÏÀÍý
2261 OR ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ */
2264 mtext_property (MSymbol key, void *val, int control_bits)
2266 return new_text_property (NULL, 0, 0, key, val, control_bits);
2270 @brief Return the M-text of a text property.
2272 The mtext_property_mtext () function returns the M-text to which
2273 text property $PROP is attached. If $PROP is currently detached,
2274 NULL is returned. */
2277 @brief ¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä M-text ¤òÊÖ¤¹.
2279 ´Ø¿ô mtext_property_mtext () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£$PROP ¤¬Éղäµ
2280 ¤ì¤Æ¤¤¤ë M-text ¤òÊÖ¤¹¡£¤½¤Î»þÅÀ¤Ç $PROP ¤¬Ê¬Î¥¤·¤Æ¤¤¤ì¤Ð NULL ¤ò
2284 mtext_property_mtext (MTextProperty *prop)
2290 @brief Return the key of a text property.
2292 The mtext_property_key () function returns the key (symbol) of
2293 text property $PROP. */
2296 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¥¡¼¤òÊÖ¤¹.
2298 ´Ø¿ô mtext_property_key () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤Î¥¡¼¡Ê¥·
2302 mtext_property_key (MTextProperty *prop)
2308 @brief Return the value of a text property.
2310 The mtext_property_value () function returns the value of text
2314 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹.
2316 ´Ø¿ô mtext_property_value () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤ÎÃͤòÊÖ
2320 mtext_property_value (MTextProperty *prop)
2326 @brief Return the start position of a text property.
2328 The mtext_property_start () function returns the start position of
2329 text property $PROP. The start position is a character position
2330 of an M-text where $PROP begins. If $PROP is detached, it returns
2334 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î³«»Ï°ÌÃÖ¤òÊÖ¤¹.
2336 ´Ø¿ô mtext_property_start () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤Î³«»Ï°Ì
2337 ÃÖ¤òÊÖ¤¹¡£³«»Ï°ÌÃÖ¤È¤Ï M-text Ãæ¤Ç $PROP ¤¬»Ï¤Þ¤ëʸ»ú°ÌÃ֤Ǥ¢¤ë¡£
2338 $PROP ¤¬Ê¬Î¥¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢-1 ¤òÊÖ¤¹¡£ */
2341 mtext_property_start (MTextProperty *prop)
2343 return (prop->mt ? prop->start : -1);
2347 @brief Return the end position of a text property.
2349 The mtext_property_end () function returns the end position of
2350 text property $PROP. The end position is a character position of
2351 an M-text where $PROP ends. If $PROP is detached, it returns
2355 @brief ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î½ªÎ»°ÌÃÖ¤òÊÖ¤¹.
2357 ´Ø¿ô mtext_property_end () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤Î½ªÎ»°ÌÃÖ
2358 ¤òÊÖ¤¹¡£½ªÎ»°ÌÃÖ¤È¤Ï M-text Ãæ¤Ç $PROP ¤¬½ª¤ëʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$PROP
2359 ¤¬Ê¬Î¥¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢-1 ¤òÊÖ¤¹¡£ */
2362 mtext_property_end (MTextProperty *prop)
2364 return (prop->mt ? prop->end : -1);
2368 @brief Get the topmost text property.
2370 The mtext_get_property () function searches the character at
2371 position $POS in M-text $MT for a text property whose key is $KEY.
2374 If a text property is found, mtext_get_property () returns it. If
2375 there are multiple text properties, it returns the topmost one.
2376 If no such property is found, it returns @c NULL without changing
2377 the external variable #merror_code.
2379 If an error is detected, mtext_get_property () returns @c NULL and
2380 assigns an error code to the external variable #merror_code. */
2383 @brief °ìÈÖ¾å¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÆÀ¤ë.
2385 ´Ø¿ô mtext_get_property () ¤Ï M-text $MT ¤Î°ÌÃÖ $POS ¤Îʸ»ú¤¬¥¡¼
2386 ¤¬ $KEY ¤Ç¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¤«¤É¤¦¤«¤òÄ´¤Ù¤ë¡£
2389 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤ì¤Ð¡¢mtext_get_property () ¤Ï¤½¤ì¤òÊÖ¤¹¡£
2390 Ê£¿ô¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢°ìÈÖ¾å¤Î¤â¤Î¤òÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢³°ÉôÊÑ¿ô
2391 #merror_code ¤òÊѤ¨¤ë¤³¤È¤Ê¤¯ @c NULL ¤òÊÖ¤¹¡£
2393 ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç mtext_get_property () ¤Ï @c NULL ¤òÊÖ¤·¡¢³°
2394 ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
2397 mtext_get_property (MText *mt, int pos, MSymbol key)
2400 MInterval *interval;
2402 M_CHECK_POS (mt, pos, NULL);
2404 plist = get_plist_create (mt, key, 0);
2408 interval = find_interval (plist, pos);
2409 if (! interval->nprops)
2411 return interval->stack[interval->nprops - 1];
2415 @brief Get multiple text properties.
2417 The mtext_get_properties () function searches the character at
2418 $POS in M-text $MT for properties whose key is $KEY. If such
2419 properties are found, they are stored in the memory area pointed
2420 to by $PROPS. $NUM limits the maximum number of stored
2424 If the operation was successful, mtext_get_properties () returns
2425 the number of actually stored properties. If the character at
2426 $POS does not have a property whose key is $KEY, the return value
2427 is 0. If an error is detected, mtext_get_properties () returns -1
2428 and assigns an error code to the external variable #merror_code. */
2431 @brief Ê£¿ô¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÆÀ¤ë.
2433 ´Ø¿ô mtext_get_properties () ¤Ï M-text $MT ¤Î°ÌÃÖ $POS ¤Îʸ»ú¤¬¥¡¼
2434 ¤¬ $KEY ¤Ç¤¢¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¤«¤É¤¦¤«¤òÄ´¤Ù¤ë¡£¤½¤Î¤è¤¦¤Ê
2435 ¥×¥í¥Ñ¥Æ¥£¤¬¤ß¤Ä¤«¤ì¤Ð¡¢$PROPS ¤¬»Ø¤¹¥á¥â¥êÎΰè¤ËÊݸ¤¹¤ë¡£$NUM ¤Ï
2436 Êݸ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¤Î¿ô¤Î¾å¸Â¤Ç¤¢¤ë¡£
2439 ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mtext_get_properties () ¤Ï¼ÂºÝ¤ËÊݸ¤·¤¿¥×¥í¥Ñ¥Æ¥£
2440 ¤Î¿ô¤òÊÖ¤¹¡£$POS ¤Î°ÌÃÖ¤Îʸ»ú¤¬¥¡¼¤¬ $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿
2441 ¤Ê¤±¤ì¤Ð¡¢0 ¤¬Ê֤롣¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ë¤Ï¡¢
2442 mtext_get_properties () ¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼
2443 ¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
2446 mtext_get_properties (MText *mt, int pos, MSymbol key,
2447 MTextProperty **props, int num)
2450 MInterval *interval;
2455 M_CHECK_POS (mt, pos, -1);
2457 plist = get_plist_create (mt, key, 0);
2461 interval = find_interval (plist, pos);
2462 /* It is assured that INTERVAL is not NULL. */
2463 nprops = interval->nprops;
2464 if (nprops == 0 || num <= 0)
2466 if (nprops == 1 || num == 1)
2468 props[0] = interval->stack[nprops - 1];
2473 num = nprops, offset = 0;
2475 offset = nprops - num;
2476 for (i = 0; i < num; i++)
2477 props[i] = interval->stack[offset + i];
2482 @brief Attach a text property to an M-text.
2484 The mtext_attach_property () function attaches text property $PROP
2485 to the range between $FROM and $TO in M-text $MT. If $PROP is
2486 already attached to an M-text, it is detached before attached to
2490 If the operation was successful, mtext_attach_property () returns
2491 0. Otherwise it returns -1 and assigns an error code to the
2492 external variable #merror_code. */
2495 @brief M-text¤Ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òÉղ乤ë.
2497 ´Ø¿ô mtext_attach_property () ¤Ï¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ
2498 ¤Ç¤ÎÎΰè¤Ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤òÉղ乤롣¤â¤· $PROP ¤¬´û¤Ë
2499 M-text ¤ËÉղ䵤ì¤Æ¤¤¤ì¤Ð¡¢$MT ¤ËÉղ乤ëÁ°¤ËʬΥ¤µ¤ì¤ë¡£
2502 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mtext_attach_property () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±
2503 ¤ì¤Ð -1 ¤òÊÖ¤·¤Æ³°ÉôÊÑ¿ô#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
2507 mtext_attach_property (MText *mt, int from, int to, MTextProperty *prop)
2510 MInterval *interval;
2512 M_CHECK_RANGE (mt, from, to, -1, 0);
2514 M17N_OBJECT_REF (prop);
2516 mtext_detach_property (prop);
2517 prepare_to_modify (mt, from, to, prop->key);
2518 plist = get_plist_create (mt, prop->key, 1);
2519 xassert (check_plist (plist, 0) == 0);
2520 interval = pop_all_properties (plist, from, to);
2521 xassert (check_plist (plist, 0) == 0);
2525 PUSH_PROP (interval, prop);
2526 M17N_OBJECT_UNREF (prop);
2527 xassert (check_plist (plist, 0) == 0);
2529 maybe_merge_interval (plist, interval);
2531 maybe_merge_interval (plist, interval->prev);
2532 xassert (check_plist (plist, 0) == 0);
2537 @brief Detach a text property from an M-text.
2539 The mtext_detach_property () function makes text property $PROP
2543 This function always returns 0. */
2546 @brief M-text ¤«¤é¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤òʬΥ¤¹¤ë.
2548 ´Ø¿ô mtext_detach_property () ¤Ï¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤òʬΥ¤¹¤ë¡£
2551 ¤³¤Î´Ø¿ô¤Ï¾ï¤Ë 0 ¤òÊÖ¤¹¡£ */
2554 mtext_detach_property (MTextProperty *prop)
2557 int start = prop->start, end = prop->end;
2561 prepare_to_modify (prop->mt, start, end, prop->key);
2562 plist = get_plist_create (prop->mt, prop->key, 0);
2564 detach_property (plist, prop, NULL);
2569 @brief Push a text property onto an M-text.
2571 The mtext_push_property () function pushes text property $PROP to
2572 the characters between $FROM (inclusive) and $TO (exclusive) in
2576 If the operation was successful, mtext_push_property () returns
2577 0. Otherwise it returns -1 and assigns an error code to the
2578 external variable #merror_code. */
2581 @brief M-text ¤Ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥×¥Ã¥·¥å¤¹¤ë.
2583 ´Ø¿ô mtext_push_property () ¤Ï¡¢¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£ $PROP ¤ò¡¢
2584 M-text $MT Ãæ¤Î $FROM ¡Ê´Þ¤Þ¤ì¤ë¡Ë¤«¤é $TO ¡Ê´Þ¤Þ¤ì¤Ê¤¤¡Ë¤ÎÈϰϤÎ
2585 ʸ»ú¤Ë¥×¥Ã¥·¥å¤¹¤ë¡£
2588 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mtext_push_property () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±
2589 ¤ì¤Ð -1 ¤òÊÖ¤·¤Æ³°ÉôÊÑ¿ô#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
2593 mtext_push_property (MText *mt, int from, int to, MTextProperty *prop)
2596 MInterval *head, *tail, *interval;
2597 int check_head, check_tail;
2599 M_CHECK_RANGE (mt, from, to, -1, 0);
2601 M17N_OBJECT_REF (prop);
2603 mtext_detach_property (prop);
2604 prepare_to_modify (mt, from, to, prop->key);
2605 plist = get_plist_create (mt, prop->key, 1);
2610 /* Find an interval that covers the position FROM. */
2611 head = find_interval (plist, from);
2613 /* If the found interval starts before FROM, divide it at FROM. */
2614 if (head->start < from)
2616 divide_interval (plist, head, from);
2623 /* Find an interval that ends at TO. If TO is not at the end of an
2624 interval, make one that ends at TO. */
2625 if (head->end == to)
2630 else if (head->end > to)
2632 divide_interval (plist, head, to);
2638 tail = find_interval (plist, to);
2644 else if (tail->start == to)
2651 divide_interval (plist, tail, to);
2656 /* Push PROP to the current values of intervals between HEAD and TAIL
2657 (both inclusive). */
2658 for (interval = head; ; interval = interval->next)
2660 PUSH_PROP (interval, prop);
2661 if (interval == tail)
2665 /* If there is a possibility that TAIL now has the same value as the
2666 next one, check it and concatenate them if necessary. */
2667 if (tail->next && check_tail)
2668 maybe_merge_interval (plist, tail);
2670 /* If there is a possibility that HEAD now has the same value as the
2671 previous one, check it and concatenate them if necessary. */
2672 if (head->prev && check_head)
2673 maybe_merge_interval (plist, head->prev);
2675 M17N_OBJECT_UNREF (prop);
2676 xassert (check_plist (plist, 0) == 0);
2681 @brief Symbol for specifying serializer functions.
2683 To serialize a text property, the user must supply a serializer
2684 function for that text property. This is done by giving a symbol
2685 property whose key is #Mtext_prop_serializer and value is a
2686 pointer to an appropriate serializer function.
2689 mtext_serialize (), #MTextPropSerializeFunc
2693 @brief ¥·¥ê¥¢¥é¥¤¥¶´Ø¿ô¤ò»ØÄꤹ¤ë¥·¥ó¥Ü¥ë.
2695 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥·¥ê¥¢¥é¥¤¥º¤¹¤ë¤¿¤á¤Ë¤Ï¡¢¤½¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ
2696 ¥Æ¥£ÍѤΥ·¥ê¥¢¥é¥¤¥¶´Ø¿ô¤òÍ¿¤¨¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¶ñÂÎŪ¤Ë¤Ï¡¢
2697 #Mtext_prop_serializer ¤ò¥¡¼¤È¤·¡¢Å¬Àڤʥ·¥ê¥¢¥é¥¤¥º´Ø¿ô¤Ø¤Î¥Ý¥¤
2698 ¥ó¥¿¤òÃͤȤ¹¤ë¥·¥ó¥Ü¥ë¥×¥í¥Ñ¥Æ¥£¤ò»ØÄꤹ¤ë¡£
2701 mtext_serialize (), #MTextPropSerializeFunc
2703 MSymbol Mtext_prop_serializer;
2706 @brief Symbol for specifying deserializer functions.
2708 To deserialize a text property, the user must supply a deserializer
2709 function for that text property. This is done by giving a symbol
2710 property whose key is #Mtext_prop_deserializer and value is a
2711 pointer to an appropriate deserializer function.
2714 mtext_deserialize (), #MTextPropSerializeFunc
2718 @brief ¥Ç¥·¥ê¥¢¥é¥¤¥¶´Ø¿ô¤ò»ØÄꤹ¤ë¥·¥ó¥Ü¥ë.
2720 ¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤¹¤ë¤¿¤á¤Ë¤Ï¡¢¤½¤Î¥Æ¥¥¹¥È¥×¥í
2721 ¥Ñ¥Æ¥£ÍѤΥǥ·¥ê¥¢¥é¥¤¥¶´Ø¿ô¤òÍ¿¤¨¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¶ñÂÎŪ¤Ë¤Ï¡¢
2722 #Mtext_prop_deserializer ¤ò¥¡¼¤È¤·¡¢Å¬Àڤʥǥ·¥ê¥¢¥é¥¤¥º´Ø¿ô¤Ø¤Î
2723 ¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥·¥ó¥Ü¥ë¥×¥í¥Ñ¥Æ¥£¤ò»ØÄꤹ¤ë¡£
2726 mtext_deserialize (), #MTextPropSerializeFunc
2728 MSymbol Mtext_prop_deserializer;
2731 @brief Serialize text properties in an M-text.
2733 The mtext_serialize () function serializes the text between $FROM
2734 and $TO in M-text $MT. The serialized result is an M-text in a
2735 form of XML. $PROPERTY_LIST limits the text properties to be
2736 serialized. Only those text properties whose key
2738 @li appears as the value of an element in $PROPERTY_LIST, and
2739 @li has the symbol property #Mtext_prop_serializer
2741 are serialized as a "property" element in the resulting XML
2744 The DTD of the generated XML is as follows:
2748 <!ELEMENT mtext (property*,body+)>
2749 <!ELEMENT property EMPTY>
2750 <!ELEMENT body (#PCDATA)>
2751 <!ATTLIST property key CDATA #REQUIRED>
2752 <!ATTLIST property value CDATA #REQUIRED>
2753 <!ATTLIST property from CDATA #REQUIRED>
2754 <!ATTLIST property to CDATA #REQUIRED>
2755 <!ATTLIST property control CDATA #REQUIRED>
2759 This function depends on the libxml2 library. If the m17n library
2760 is configured without libxml2, this function always fails.
2763 If the operation was successful, mtext_serialize () returns an
2764 M-text in the form of XML. Otherwise it returns @c NULL and assigns an
2765 error code to the external variable #merror_code.
2768 mtext_deserialize (), #Mtext_prop_serializer */
2771 @brief M-text Ãæ¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥·¥ê¥¢¥é¥¤¥º¤¹¤ë.
2773 ´Ø¿ô mtext_serialize () ¤Ï M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥
2774 ¥¹¥È¤ò¥·¥ê¥¢¥é¥¤¥º¤¹¤ë¡£¥·¥ê¥¢¥é¥¤¥º¤·¤¿·ë²Ì¤Ï XML ·Á¼°¤Î M-text ¤Ç
2775 ¤¢¤ë¡£ $PROPERTY_LIST ¤Ï¥·¥ê¥¢¥é¥¤¥º¤µ¤ì¤ë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¸ÂÄê
2776 ¤¹¤ë¡£ÂоݤȤʤë¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¡¢¤½¤Î¥¡¼¤¬
2778 @li $PROPERTY_LIST ¤ÎÍ×ÁǤÎÃͤȤ·¤Æ¸½¤ï¤ì¡¢¤«¤Ä
2779 @li ¥·¥ó¥Ü¥ë¥×¥í¥Ñ¥Æ¥£ #Mtext_prop_serializer ¤ò»ý¤Ä
2781 ¤â¤Î¤Î¤ß¤Ç¤¢¤ë¡£¤³¤Î¾ò·ï¤òËþ¤¿¤¹¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ï¡¢À¸À®¤µ¤ì¤ë
2782 XML ɽ¸½Ãæ¤Ç "property" Í×ÁǤ˥·¥ê¥¢¥é¥¤¥º¤µ¤ì¤ë¡£
2784 À¸À®¤µ¤ì¤ë XML ¤Î DTD ¤Ï°Ê²¼¤ÎÄ̤ê:
2788 <!ELEMENT mtext (property*,body+)>
2789 <!ELEMENT property EMPTY>
2790 <!ELEMENT body (#PCDATA)>
2791 <!ATTLIST property key CDATA #REQUIRED>
2792 <!ATTLIST property value CDATA #REQUIRED>
2793 <!ATTLIST property from CDATA #REQUIRED>
2794 <!ATTLIST property to CDATA #REQUIRED>
2795 <!ATTLIST property control CDATA #REQUIRED>
2799 ¤³¤Î´Ø¿ô¤Ï libxml2 ¥é¥¤¥Ö¥é¥ê¤Ë°Í¸¤¹¤ë¡£m17n ¥é¥¤¥Ö¥é¥ê¤¬libxml2
2800 ̵¤·¤ËÀßÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç¡¢¤³¤Î´Ø¿ô¤Ï¾ï¤Ë¼ºÇÔ¤¹¤ë¡£
2803 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mtext_serialize () ¤Ï XML ·Á¼°¤Ç M-text ¤òÊÖ¤¹¡£
2804 ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¤Æ³°ÉôÊÑ¿ô#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É
2808 mtext_deserialize (), #Mtext_prop_serializer */
2811 mtext_serialize (MText *mt, int from, int to, MPlist *property_list)
2815 MTextPropSerializeFunc func;
2822 M_CHECK_RANGE (mt, from, to, NULL, NULL);
2823 doc = xmlParseMemory (XML_TEMPLATE, strlen (XML_TEMPLATE) + 1);
2824 node = xmlDocGetRootElement (doc);
2827 MPLIST_DO (pl, property_list)
2829 MSymbol key = MPLIST_VAL (pl);
2831 func = (MTextPropSerializeFunc) msymbol_get (key, Mtext_prop_serializer);
2833 extract_text_properties (mt, from, to, key, plist);
2837 MPLIST_DO (pl, plist)
2839 MTextProperty *prop = MPLIST_VAL (pl);
2841 MPlist *serialized_plist;
2844 func = (MTextPropSerializeFunc) msymbol_get (prop->key,
2845 Mtext_prop_serializer);
2846 serialized_plist = (func) (prop->val);
2847 if (! serialized_plist)
2850 mplist__serialize (work, serialized_plist);
2851 child = xmlNewChild (node, NULL, (xmlChar *) "property", NULL);
2852 xmlSetProp (child, (xmlChar *) "key",
2853 (xmlChar *) MSYMBOL_NAME (prop->key));
2854 xmlSetProp (child, (xmlChar *) "value", (xmlChar *) MTEXT_DATA (work));
2855 sprintf (buf, "%d", prop->start - from);
2856 xmlSetProp (child, (xmlChar *) "from", (xmlChar *) buf);
2857 sprintf (buf, "%d", prop->end - from);
2858 xmlSetProp (child, (xmlChar *) "to", (xmlChar *) buf);
2859 sprintf (buf, "%d", prop->control.flag);
2860 xmlSetProp (child, (xmlChar *) "control", (xmlChar *) buf);
2861 xmlAddChild (node, xmlNewText ((xmlChar *) "\n"));
2863 M17N_OBJECT_UNREF (serialized_plist);
2865 M17N_OBJECT_UNREF (plist);
2867 if (from > 0 || to < mtext_nchars (mt))
2868 mtext_copy (work, 0, mt, from, to);
2871 M17N_OBJECT_UNREF (work);
2874 for (from = 0, to = mtext_nchars (mt); from <= to; from++)
2876 ptr = MTEXT_DATA (mt) + POS_CHAR_TO_BYTE (mt, from);
2877 xmlNewTextChild (node, NULL, (xmlChar *) "body", (xmlChar *) ptr);
2878 from = mtext_character (mt, from, to, 0);
2883 xmlDocDumpMemoryEnc (doc, (xmlChar **) &ptr, &n, "UTF-8");
2886 mtext__cat_data (work, ptr, n, MTEXT_FORMAT_UTF_8);
2888 #else /* not HAVE_XML2 */
2889 MERROR (MERROR_TEXTPROP, NULL);
2890 #endif /* not HAVE_XML2 */
2894 @brief Deserialize text properties in an M-text.
2896 The mtext_deserialize () function deserializes M-text $MT. $MT
2897 must be an XML having the followng DTD.
2901 <!ELEMENT mtext (property*,body+)>
2902 <!ELEMENT property EMPTY>
2903 <!ELEMENT body (#PCDATA)>
2904 <!ATTLIST property key CDATA #REQUIRED>
2905 <!ATTLIST property value CDATA #REQUIRED>
2906 <!ATTLIST property from CDATA #REQUIRED>
2907 <!ATTLIST property to CDATA #REQUIRED>
2908 <!ATTLIST property control CDATA #REQUIRED>
2912 This function depends on the libxml2 library. If the m17n library
2913 is configured without libxml2, this function always fail.
2916 If the operation was successful, mtext_deserialize () returns the
2917 resulting M-text. Otherwise it returns @c NULL and assigns an error
2918 code to the external variable #merror_code.
2921 mtext_serialize (), #Mtext_prop_deserializer */
2924 @brief M-text Ãæ¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤¹¤ë.
2926 ´Ø¿ô mtext_deserialize () ¤Ï M-text $MT ¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤¹¤ë¡£$MT
2927 ¤Ï¼¡¤Î DTD ¤ò»ý¤Ä XML ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2931 <!ELEMENT mtext (property*,body+)>
2932 <!ELEMENT property EMPTY>
2933 <!ELEMENT body (#PCDATA)>
2934 <!ATTLIST property key CDATA #REQUIRED>
2935 <!ATTLIST property value CDATA #REQUIRED>
2936 <!ATTLIST property from CDATA #REQUIRED>
2937 <!ATTLIST property to CDATA #REQUIRED>
2938 <!ATTLIST property control CDATA #REQUIRED>
2942 ¤³¤Î´Ø¿ô¤Ï libxml2 ¥é¥¤¥Ö¥é¥ê¤Ë°Í¸¤¹¤ë¡£m17n ¥é¥¤¥Ö¥é¥ê¤¬libxml2
2943 ̵¤·¤ËÀßÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç¡¢¤³¤Î´Ø¿ô¤Ï¾ï¤Ë¼ºÇÔ¤¹¤ë¡£
2946 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢mtext_serialize () ¤ÏÆÀ¤é¤ì¤¿ M-text ¤ò
2947 ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¤Æ³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼
2951 mtext_serialize (), #Mtext_prop_deserializer */
2954 mtext_deserialize (MText *mt)
2959 xmlXPathContextPtr context;
2960 xmlXPathObjectPtr result;
2961 xmlChar *body_str, *key_str, *val_str, *from_str, *to_str, *ctl_str;
2964 if (mt->format > MTEXT_FORMAT_UTF_8)
2965 MERROR (MERROR_TEXTPROP, NULL);
2966 doc = xmlParseMemory ((char *) MTEXT_DATA (mt), mtext_nbytes (mt));
2968 MERROR (MERROR_TEXTPROP, NULL);
2969 node = xmlDocGetRootElement (doc);
2973 MERROR (MERROR_TEXTPROP, NULL);
2975 if (xmlStrcmp (node->name, (xmlChar *) "mtext"))
2978 MERROR (MERROR_TEXTPROP, NULL);
2981 context = xmlXPathNewContext (doc);
2982 result = xmlXPathEvalExpression ((xmlChar *) "//body", context);
2983 if (xmlXPathNodeSetIsEmpty (result->nodesetval))
2986 MERROR (MERROR_TEXTPROP, NULL);
2988 for (i = 0, mt = mtext (); i < result->nodesetval->nodeNr; i++)
2991 mtext_cat_char (mt, 0);
2992 node = (xmlNodePtr) result->nodesetval->nodeTab[i];
2993 body_str = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
2996 mtext__cat_data (mt, body_str, strlen ((char *) body_str),
2997 MTEXT_FORMAT_UTF_8);
3002 result = xmlXPathEvalExpression ((xmlChar *) "//property", context);
3003 if (! xmlXPathNodeSetIsEmpty (result->nodesetval))
3004 for (i = 0; i < result->nodesetval->nodeNr; i++)
3007 MTextPropDeserializeFunc func;
3008 MTextProperty *prop;
3010 int from, to, control;
3013 key_str = xmlGetProp (result->nodesetval->nodeTab[i],
3015 val_str = xmlGetProp (result->nodesetval->nodeTab[i],
3016 (xmlChar *) "value");
3017 from_str = xmlGetProp (result->nodesetval->nodeTab[i],
3018 (xmlChar *) "from");
3019 to_str = xmlGetProp (result->nodesetval->nodeTab[i],
3021 ctl_str = xmlGetProp (result->nodesetval->nodeTab[i],
3022 (xmlChar *) "control");
3024 key = msymbol ((char *) key_str);
3025 func = ((MTextPropDeserializeFunc)
3026 msymbol_get (key, Mtext_prop_deserializer));
3029 plist = mplist__from_string (val_str, strlen ((char *) val_str));
3032 if (sscanf ((char *) from_str, "%d", &from) != 1
3033 || from < 0 || from >= mtext_nchars (mt))
3035 if (sscanf ((char *) to_str, "%d", &to) != 1
3036 || to <= from || to > mtext_nchars (mt))
3038 if (sscanf ((char *) ctl_str, "%d", &control) != 1
3039 || control < 0 || control > MTEXTPROP_CONTROL_MAX)
3041 val = (func) (plist);
3042 M17N_OBJECT_UNREF (plist);
3043 prop = mtext_property (key, val, control);
3044 if (key->managing_key)
3045 M17N_OBJECT_UNREF (val);
3046 mtext_push_property (mt, from, to, prop);
3047 M17N_OBJECT_UNREF (prop);
3055 xmlXPathFreeContext (context);
3058 #else /* not HAVE_XML2 */
3059 MERROR (MERROR_TEXTPROP, NULL);
3060 #endif /* not HAVE_XML2 */