1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
7 #include "plugin/item/item.h"
11 /* Internal constructor. */
13 coord_init_values(coord_t
* coord
, const znode
* node
, pos_in_node_t item_pos
,
14 pos_in_node_t unit_pos
, between_enum between
)
16 coord
->node
= (znode
*) node
;
17 coord_set_item_pos(coord
, item_pos
);
18 coord
->unit_pos
= unit_pos
;
19 coord
->between
= between
;
20 ON_DEBUG(coord
->plug_v
= 0);
21 ON_DEBUG(coord
->body_v
= 0);
23 /*ON_TRACE (TRACE_COORDS, "init coord %p node %p: %u %u %s\n", coord, node, item_pos, unit_pos, coord_tween_tostring (between)); */
26 /* after shifting of node content, coord previously set properly may become
27 invalid, try to "normalize" it. */
28 void coord_normalize(coord_t
* coord
)
33 assert("vs-683", node
);
35 coord_clear_iplug(coord
);
37 if (node_is_empty(node
)) {
38 coord_init_first_unit(coord
, node
);
39 } else if ((coord
->between
== AFTER_ITEM
)
40 || (coord
->between
== AFTER_UNIT
)) {
42 } else if (coord
->item_pos
== coord_num_items(coord
)
43 && coord
->between
== BEFORE_ITEM
) {
44 coord_dec_item_pos(coord
);
45 coord
->between
= AFTER_ITEM
;
46 } else if (coord
->unit_pos
== coord_num_units(coord
)
47 && coord
->between
== BEFORE_UNIT
) {
49 coord
->between
= AFTER_UNIT
;
50 } else if (coord
->item_pos
== coord_num_items(coord
)
51 && coord
->unit_pos
== 0 && coord
->between
== BEFORE_UNIT
) {
52 coord_dec_item_pos(coord
);
54 coord
->between
= AFTER_ITEM
;
58 /* Copy a coordinate. */
59 void coord_dup(coord_t
* coord
, const coord_t
* old_coord
)
61 assert("jmacd-9800", coord_check(old_coord
));
62 coord_dup_nocheck(coord
, old_coord
);
65 /* Copy a coordinate without check. Useful when old_coord->node is not
66 loaded. As in cbk_tree_lookup -> connect_znode -> connect_one_side */
67 void coord_dup_nocheck(coord_t
* coord
, const coord_t
* old_coord
)
69 coord
->node
= old_coord
->node
;
70 coord_set_item_pos(coord
, old_coord
->item_pos
);
71 coord
->unit_pos
= old_coord
->unit_pos
;
72 coord
->between
= old_coord
->between
;
73 coord
->iplugid
= old_coord
->iplugid
;
74 ON_DEBUG(coord
->plug_v
= old_coord
->plug_v
);
75 ON_DEBUG(coord
->body_v
= old_coord
->body_v
);
78 /* Initialize an invalid coordinate. */
79 void coord_init_invalid(coord_t
* coord
, const znode
* node
)
81 coord_init_values(coord
, node
, 0, 0, INVALID_COORD
);
84 void coord_init_first_unit_nocheck(coord_t
* coord
, const znode
* node
)
86 coord_init_values(coord
, node
, 0, 0, AT_UNIT
);
89 /* Initialize a coordinate to point at the first unit of the first item. If the node is
90 empty, it is positioned at the EMPTY_NODE. */
91 void coord_init_first_unit(coord_t
* coord
, const znode
* node
)
93 int is_empty
= node_is_empty(node
);
95 coord_init_values(coord
, node
, 0, 0, (is_empty
? EMPTY_NODE
: AT_UNIT
));
97 assert("jmacd-9801", coord_check(coord
));
100 /* Initialize a coordinate to point at the last unit of the last item. If the node is
101 empty, it is positioned at the EMPTY_NODE. */
102 void coord_init_last_unit(coord_t
* coord
, const znode
* node
)
104 int is_empty
= node_is_empty(node
);
106 coord_init_values(coord
, node
,
107 (is_empty
? 0 : node_num_items(node
) - 1), 0,
108 (is_empty
? EMPTY_NODE
: AT_UNIT
));
110 coord
->unit_pos
= coord_last_unit_pos(coord
);
111 assert("jmacd-9802", coord_check(coord
));
114 /* Initialize a coordinate to before the first item. If the node is empty, it is
115 positioned at the EMPTY_NODE. */
116 void coord_init_before_first_item(coord_t
* coord
, const znode
* node
)
118 int is_empty
= node_is_empty(node
);
120 coord_init_values(coord
, node
, 0, 0,
121 (is_empty
? EMPTY_NODE
: BEFORE_UNIT
));
123 assert("jmacd-9803", coord_check(coord
));
126 /* Initialize a coordinate to after the last item. If the node is empty, it is positioned
127 at the EMPTY_NODE. */
128 void coord_init_after_last_item(coord_t
* coord
, const znode
* node
)
130 int is_empty
= node_is_empty(node
);
132 coord_init_values(coord
, node
,
133 (is_empty
? 0 : node_num_items(node
) - 1), 0,
134 (is_empty
? EMPTY_NODE
: AFTER_ITEM
));
136 assert("jmacd-9804", coord_check(coord
));
139 /* Initialize a coordinate to after last unit in the item. Coord must be set
140 already to existing item */
141 void coord_init_after_item_end(coord_t
* coord
)
143 coord
->between
= AFTER_UNIT
;
144 coord
->unit_pos
= coord_last_unit_pos(coord
);
147 /* Initialize a coordinate to before the item. Coord must be set already to existing item */
148 void coord_init_before_item(coord_t
* coord
)
151 coord
->between
= BEFORE_ITEM
;
154 /* Initialize a coordinate to after the item. Coord must be set already to existing item */
155 void coord_init_after_item(coord_t
* coord
)
158 coord
->between
= AFTER_ITEM
;
161 /* Initialize a coordinate by 0s. Used in places where init_coord was used and
162 it was not clear how actually */
163 void coord_init_zero(coord_t
* coord
)
165 memset(coord
, 0, sizeof(*coord
));
168 /* Return the number of units at the present item. Asserts coord_is_existing_item(). */
169 unsigned coord_num_units(const coord_t
* coord
)
171 assert("jmacd-9806", coord_is_existing_item(coord
));
173 return item_plugin_by_coord(coord
)->b
.nr_units(coord
);
176 /* Returns true if the coord was initializewd by coord_init_invalid (). */
177 /* Audited by: green(2002.06.15) */
178 int coord_is_invalid(const coord_t
* coord
)
180 return coord
->between
== INVALID_COORD
;
183 /* Returns true if the coordinate is positioned at an existing item, not before or after
184 an item. It may be placed at, before, or after any unit within the item, whether
186 int coord_is_existing_item(const coord_t
* coord
)
188 switch (coord
->between
) {
198 return coord
->item_pos
< coord_num_items(coord
);
201 impossible("jmacd-9900", "unreachable coord: %p", coord
);
205 /* Returns true if the coordinate is positioned at an existing unit, not before or after a
207 /* Audited by: green(2002.06.15) */
208 int coord_is_existing_unit(const coord_t
* coord
)
210 switch (coord
->between
) {
220 return (coord
->item_pos
< coord_num_items(coord
)
221 && coord
->unit_pos
< coord_num_units(coord
));
224 impossible("jmacd-9902", "unreachable");
228 /* Returns true if the coordinate is positioned at the first unit of the first item. Not
229 true for empty nodes nor coordinates positioned before the first item. */
230 /* Audited by: green(2002.06.15) */
231 int coord_is_leftmost_unit(const coord_t
* coord
)
233 return (coord
->between
== AT_UNIT
&& coord
->item_pos
== 0
234 && coord
->unit_pos
== 0);
238 /* For assertions only, checks for a valid coordinate. */
239 int coord_check(const coord_t
* coord
)
241 if (coord
->node
== NULL
) {
244 if (znode_above_root(coord
->node
))
247 switch (coord
->between
) {
252 if (!node_is_empty(coord
->node
)) {
255 return coord
->item_pos
== 0 && coord
->unit_pos
== 0;
259 if (node_is_empty(coord
->node
) && (coord
->item_pos
== 0)
260 && (coord
->unit_pos
== 0))
266 /* before/after item should not set unit_pos. */
267 if (coord
->unit_pos
!= 0) {
273 if (coord
->item_pos
>= node_num_items(coord
->node
)) {
277 /* FIXME-VS: we are going to check unit_pos. This makes no sense when
278 between is set either AFTER_ITEM or BEFORE_ITEM */
279 if (coord
->between
== AFTER_ITEM
|| coord
->between
== BEFORE_ITEM
)
282 if (coord_is_iplug_set(coord
) &&
284 item_plugin_by_coord(coord
)->b
.nr_units(coord
) - 1) {
291 /* Adjust coordinate boundaries based on the number of items prior to coord_next/prev.
292 Returns 1 if the new position is does not exist. */
293 static int coord_adjust_items(coord_t
* coord
, unsigned items
, int is_next
)
295 /* If the node is invalid, leave it. */
296 if (coord
->between
== INVALID_COORD
) {
300 /* If the node is empty, set it appropriately. */
302 coord
->between
= EMPTY_NODE
;
303 coord_set_item_pos(coord
, 0);
308 /* If it was empty and it no longer is, set to BEFORE/AFTER_ITEM. */
309 if (coord
->between
== EMPTY_NODE
) {
310 coord
->between
= (is_next
? BEFORE_ITEM
: AFTER_ITEM
);
311 coord_set_item_pos(coord
, 0);
316 /* If the item_pos is out-of-range, set it appropriatly. */
317 if (coord
->item_pos
>= items
) {
318 coord
->between
= AFTER_ITEM
;
319 coord_set_item_pos(coord
, items
- 1);
321 /* If is_next, return 1 (can't go any further). */
328 /* Advances the coordinate by one unit to the right. If empty, no change. If
329 coord_is_rightmost_unit, advances to AFTER THE LAST ITEM. Returns 0 if new position is an
331 int coord_next_unit(coord_t
* coord
)
333 unsigned items
= coord_num_items(coord
);
335 if (coord_adjust_items(coord
, items
, 1) == 1) {
339 switch (coord
->between
) {
341 /* Now it is positioned at the same unit. */
342 coord
->between
= AT_UNIT
;
347 /* If it was at or after a unit and there are more units in this item,
348 advance to the next one. */
349 if (coord
->unit_pos
< coord_last_unit_pos(coord
)) {
350 coord
->unit_pos
+= 1;
351 coord
->between
= AT_UNIT
;
355 /* Otherwise, it is crossing an item boundary and treated as if it was
356 after the current item. */
357 coord
->between
= AFTER_ITEM
;
362 /* Check for end-of-node. */
363 if (coord
->item_pos
== items
- 1) {
367 coord_inc_item_pos(coord
);
369 coord
->between
= AT_UNIT
;
373 /* The adjust_items checks ensure that we are valid here. */
375 coord
->between
= AT_UNIT
;
380 /* Handled in coord_adjust_items(). */
384 impossible("jmacd-9902", "unreachable");
388 /* Advances the coordinate by one item to the right. If empty, no change. If
389 coord_is_rightmost_unit, advances to AFTER THE LAST ITEM. Returns 0 if new position is
391 int coord_next_item(coord_t
* coord
)
393 unsigned items
= coord_num_items(coord
);
395 if (coord_adjust_items(coord
, items
, 1) == 1) {
399 switch (coord
->between
) {
404 /* Check for end-of-node. */
405 if (coord
->item_pos
== items
- 1) {
406 coord
->between
= AFTER_ITEM
;
408 coord_clear_iplug(coord
);
412 /* Anywhere in an item, go to the next one. */
413 coord
->between
= AT_UNIT
;
414 coord_inc_item_pos(coord
);
419 /* The out-of-range check ensures that we are valid here. */
421 coord
->between
= AT_UNIT
;
425 /* Handled in coord_adjust_items(). */
429 impossible("jmacd-9903", "unreachable");
433 /* Advances the coordinate by one unit to the left. If empty, no change. If
434 coord_is_leftmost_unit, advances to BEFORE THE FIRST ITEM. Returns 0 if new position
435 is an existing unit. */
436 int coord_prev_unit(coord_t
* coord
)
438 unsigned items
= coord_num_items(coord
);
440 if (coord_adjust_items(coord
, items
, 0) == 1) {
444 switch (coord
->between
) {
447 if (coord
->unit_pos
> 0) {
448 coord
->unit_pos
-= 1;
449 coord
->between
= AT_UNIT
;
453 if (coord
->item_pos
== 0) {
454 coord
->between
= BEFORE_ITEM
;
458 coord_dec_item_pos(coord
);
459 coord
->unit_pos
= coord_last_unit_pos(coord
);
460 coord
->between
= AT_UNIT
;
464 /* What if unit_pos is out-of-range? */
466 coord
->unit_pos
<= coord_last_unit_pos(coord
));
467 coord
->between
= AT_UNIT
;
471 if (coord
->item_pos
== 0) {
475 coord_dec_item_pos(coord
);
479 coord
->between
= AT_UNIT
;
480 coord
->unit_pos
= coord_last_unit_pos(coord
);
488 impossible("jmacd-9904", "unreachable");
492 /* Advances the coordinate by one item to the left. If empty, no change. If
493 coord_is_leftmost_unit, advances to BEFORE THE FIRST ITEM. Returns 0 if new position
494 is an existing item. */
495 int coord_prev_item(coord_t
* coord
)
497 unsigned items
= coord_num_items(coord
);
499 if (coord_adjust_items(coord
, items
, 0) == 1) {
503 switch (coord
->between
) {
509 if (coord
->item_pos
== 0) {
510 coord
->between
= BEFORE_ITEM
;
515 coord_dec_item_pos(coord
);
517 coord
->between
= AT_UNIT
;
521 coord
->between
= AT_UNIT
;
530 impossible("jmacd-9905", "unreachable");
534 /* Calls either coord_init_first_unit or coord_init_last_unit depending on sideof argument. */
535 void coord_init_sideof_unit(coord_t
* coord
, const znode
* node
, sideof dir
)
537 assert("jmacd-9821", dir
== LEFT_SIDE
|| dir
== RIGHT_SIDE
);
538 if (dir
== LEFT_SIDE
) {
539 coord_init_first_unit(coord
, node
);
541 coord_init_last_unit(coord
, node
);
545 /* Calls either coord_is_before_leftmost or coord_is_after_rightmost depending on sideof
547 /* Audited by: green(2002.06.15) */
548 int coord_is_after_sideof_unit(coord_t
* coord
, sideof dir
)
550 assert("jmacd-9822", dir
== LEFT_SIDE
|| dir
== RIGHT_SIDE
);
551 if (dir
== LEFT_SIDE
) {
552 return coord_is_before_leftmost(coord
);
554 return coord_is_after_rightmost(coord
);
558 /* Calls either coord_next_unit or coord_prev_unit depending on sideof argument. */
559 /* Audited by: green(2002.06.15) */
560 int coord_sideof_unit(coord_t
* coord
, sideof dir
)
562 assert("jmacd-9823", dir
== LEFT_SIDE
|| dir
== RIGHT_SIDE
);
563 if (dir
== LEFT_SIDE
) {
564 return coord_prev_unit(coord
);
566 return coord_next_unit(coord
);
571 int coords_equal(const coord_t
* c1
, const coord_t
* c2
)
573 assert("nikita-2840", c1
!= NULL
);
574 assert("nikita-2841", c2
!= NULL
);
577 c1
->node
== c2
->node
&&
578 c1
->item_pos
== c2
->item_pos
&&
579 c1
->unit_pos
== c2
->unit_pos
&& c1
->between
== c2
->between
;
581 #endif /* REISER4_DEBUG */
583 /* If coord_is_after_rightmost return NCOORD_ON_THE_RIGHT, if coord_is_after_leftmost
584 return NCOORD_ON_THE_LEFT, otherwise return NCOORD_INSIDE. */
585 /* Audited by: green(2002.06.15) */
586 coord_wrt_node
coord_wrt(const coord_t
* coord
)
588 if (coord_is_before_leftmost(coord
)) {
589 return COORD_ON_THE_LEFT
;
592 if (coord_is_after_rightmost(coord
)) {
593 return COORD_ON_THE_RIGHT
;
599 /* Returns true if the coordinate is positioned after the last item or after the last unit
600 of the last item or it is an empty node. */
601 /* Audited by: green(2002.06.15) */
602 int coord_is_after_rightmost(const coord_t
* coord
)
604 assert("jmacd-7313", coord_check(coord
));
606 switch (coord
->between
) {
617 return (coord
->item_pos
== node_num_items(coord
->node
) - 1);
620 return ((coord
->item_pos
== node_num_items(coord
->node
) - 1) &&
621 coord
->unit_pos
== coord_last_unit_pos(coord
));
624 impossible("jmacd-9908", "unreachable");
628 /* Returns true if the coordinate is positioned before the first item or it is an empty
630 int coord_is_before_leftmost(const coord_t
* coord
)
632 /* FIXME-VS: coord_check requires node to be loaded whereas it is not
633 necessary to check if coord is set before leftmost
634 assert ("jmacd-7313", coord_check (coord)); */
635 switch (coord
->between
) {
647 return (coord
->item_pos
== 0) && (coord
->unit_pos
== 0);
650 impossible("jmacd-9908", "unreachable");
654 /* Returns true if the coordinate is positioned after a item, before a item, after the
655 last unit of an item, before the first unit of an item, or at an empty node. */
656 /* Audited by: green(2002.06.15) */
657 int coord_is_between_items(const coord_t
* coord
)
659 assert("jmacd-7313", coord_check(coord
));
661 switch (coord
->between
) {
672 return coord
->unit_pos
== 0;
675 return coord
->unit_pos
== coord_last_unit_pos(coord
);
678 impossible("jmacd-9908", "unreachable");
683 /* Returns true if the coordinates are positioned at adjacent units, regardless of
684 before-after or item boundaries. */
685 int coord_are_neighbors(coord_t
* c1
, coord_t
* c2
)
690 assert("nikita-1241", c1
!= NULL
);
691 assert("nikita-1242", c2
!= NULL
);
692 assert("nikita-1243", c1
->node
== c2
->node
);
693 assert("nikita-1244", coord_is_existing_unit(c1
));
694 assert("nikita-1245", coord_is_existing_unit(c2
));
697 switch (coord_compare(c1
, c2
)) {
698 case COORD_CMP_ON_LEFT
:
702 case COORD_CMP_ON_RIGHT
:
709 wrong_return_value("nikita-1246", "compare_coords()");
711 assert("vs-731", left
&& right
);
712 if (left
->item_pos
== right
->item_pos
) {
713 return left
->unit_pos
+ 1 == right
->unit_pos
;
714 } else if (left
->item_pos
+ 1 == right
->item_pos
) {
715 return (left
->unit_pos
== coord_last_unit_pos(left
))
716 && (right
->unit_pos
== 0);
721 #endif /* REISER4_DEBUG */
723 /* Assuming two coordinates are positioned in the same node, return COORD_CMP_ON_RIGHT,
724 COORD_CMP_ON_LEFT, or COORD_CMP_SAME depending on c1's position relative to c2. */
725 /* Audited by: green(2002.06.15) */
726 coord_cmp
coord_compare(coord_t
* c1
, coord_t
* c2
)
728 assert("vs-209", c1
->node
== c2
->node
);
729 assert("vs-194", coord_is_existing_unit(c1
)
730 && coord_is_existing_unit(c2
));
732 if (c1
->item_pos
> c2
->item_pos
)
733 return COORD_CMP_ON_RIGHT
;
734 if (c1
->item_pos
< c2
->item_pos
)
735 return COORD_CMP_ON_LEFT
;
736 if (c1
->unit_pos
> c2
->unit_pos
)
737 return COORD_CMP_ON_RIGHT
;
738 if (c1
->unit_pos
< c2
->unit_pos
)
739 return COORD_CMP_ON_LEFT
;
740 return COORD_CMP_SAME
;
743 /* If the coordinate is between items, shifts it to the right. Returns 0 on success and
744 non-zero if there is no position to the right. */
745 int coord_set_to_right(coord_t
* coord
)
747 unsigned items
= coord_num_items(coord
);
749 if (coord_adjust_items(coord
, items
, 1) == 1) {
753 switch (coord
->between
) {
759 coord
->between
= AT_UNIT
;
763 if (coord
->unit_pos
< coord_last_unit_pos(coord
)) {
764 coord
->unit_pos
+= 1;
765 coord
->between
= AT_UNIT
;
771 if (coord
->item_pos
== items
- 1) {
772 coord
->between
= AFTER_ITEM
;
776 coord_inc_item_pos(coord
);
777 coord
->between
= AT_UNIT
;
782 if (coord
->item_pos
== items
- 1) {
786 coord_inc_item_pos(coord
);
788 coord
->between
= AT_UNIT
;
798 impossible("jmacd-9920", "unreachable");
802 /* If the coordinate is between items, shifts it to the left. Returns 0 on success and
803 non-zero if there is no position to the left. */
804 int coord_set_to_left(coord_t
* coord
)
806 unsigned items
= coord_num_items(coord
);
808 if (coord_adjust_items(coord
, items
, 0) == 1) {
812 switch (coord
->between
) {
817 coord
->between
= AT_UNIT
;
821 coord
->between
= AT_UNIT
;
822 coord
->unit_pos
= coord_last_unit_pos(coord
);
826 if (coord
->unit_pos
> 0) {
827 coord
->unit_pos
-= 1;
828 coord
->between
= AT_UNIT
;
832 if (coord
->item_pos
== 0) {
833 coord
->between
= BEFORE_ITEM
;
837 coord
->unit_pos
= coord_last_unit_pos(coord
);
838 coord_dec_item_pos(coord
);
839 coord
->between
= AT_UNIT
;
844 if (coord
->item_pos
== 0) {
848 coord_dec_item_pos(coord
);
849 coord
->unit_pos
= coord_last_unit_pos(coord
);
850 coord
->between
= AT_UNIT
;
860 impossible("jmacd-9920", "unreachable");
864 static const char *coord_tween_tostring(between_enum n
)
868 return "before unit";
870 return "before item";
885 sprintf(buf
, "unknown: %i", n
);
891 void print_coord(const char *mes
, const coord_t
* coord
, int node
)
894 printk("%s: null\n", mes
);
897 printk("%s: item_pos = %d, unit_pos %d, tween=%s, iplug=%d\n",
898 mes
, coord
->item_pos
, coord
->unit_pos
,
899 coord_tween_tostring(coord
->between
), coord
->iplugid
);
903 item_utmost_child_real_block(const coord_t
* coord
, sideof side
,
904 reiser4_block_nr
* blk
)
906 return item_plugin_by_coord(coord
)->f
.utmost_child_real_block(coord
,
911 int item_utmost_child(const coord_t
* coord
, sideof side
, jnode
** child
)
913 return item_plugin_by_coord(coord
)->f
.utmost_child(coord
, side
, child
);
916 /* @count bytes of flow @f got written, update correspondingly f->length,
917 f->data and f->key */
918 void move_flow_forward(flow_t
* f
, unsigned count
)
923 set_key_offset(&f
->key
, get_key_offset(&f
->key
) + count
);
928 c-indentation-style: "K&R"