1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
8 #include "plugin/item/item.h"
12 /* Internal constructor. */
14 coord_init_values(coord_t
*coord
, const znode
* node
, pos_in_node_t item_pos
,
15 pos_in_node_t unit_pos
, between_enum between
)
17 coord
->node
= (znode
*) node
;
18 coord_set_item_pos(coord
, item_pos
);
19 coord
->unit_pos
= unit_pos
;
20 coord
->between
= between
;
21 ON_DEBUG(coord
->plug_v
= 0);
22 ON_DEBUG(coord
->body_v
= 0);
24 /*ON_TRACE (TRACE_COORDS, "init coord %p node %p: %u %u %s\n", coord,
25 node, item_pos, unit_pos, coord_tween_tostring (between)); */
28 /* after shifting of node content, coord previously set properly may become
29 invalid, try to "normalize" it. */
30 void coord_normalize(coord_t
*coord
)
35 assert("vs-683", node
);
37 coord_clear_iplug(coord
);
39 if (node_is_empty(node
))
40 coord_init_first_unit(coord
, node
);
41 else if ((coord
->between
== AFTER_ITEM
)
42 || (coord
->between
== AFTER_UNIT
))
44 else if (coord
->item_pos
== coord_num_items(coord
)
45 && coord
->between
== BEFORE_ITEM
) {
46 coord_dec_item_pos(coord
);
47 coord
->between
= AFTER_ITEM
;
48 } else if (coord
->unit_pos
== coord_num_units(coord
)
49 && coord
->between
== BEFORE_UNIT
) {
51 coord
->between
= AFTER_UNIT
;
52 } else if (coord
->item_pos
== coord_num_items(coord
)
53 && coord
->unit_pos
== 0 && coord
->between
== BEFORE_UNIT
) {
54 coord_dec_item_pos(coord
);
56 coord
->between
= AFTER_ITEM
;
60 /* Copy a coordinate. */
61 void coord_dup(coord_t
*coord
, const coord_t
*old_coord
)
63 assert("jmacd-9800", coord_check(old_coord
));
64 coord_dup_nocheck(coord
, old_coord
);
67 /* Copy a coordinate without check. Useful when old_coord->node is not
68 loaded. As in cbk_tree_lookup -> connect_znode -> connect_one_side */
69 void coord_dup_nocheck(coord_t
*coord
, const coord_t
*old_coord
)
71 coord
->node
= old_coord
->node
;
72 coord_set_item_pos(coord
, old_coord
->item_pos
);
73 coord
->unit_pos
= old_coord
->unit_pos
;
74 coord
->between
= old_coord
->between
;
75 coord
->iplugid
= old_coord
->iplugid
;
76 ON_DEBUG(coord
->plug_v
= old_coord
->plug_v
);
77 ON_DEBUG(coord
->body_v
= old_coord
->body_v
);
80 /* Initialize an invalid coordinate. */
81 void coord_init_invalid(coord_t
*coord
, const znode
* node
)
83 coord_init_values(coord
, node
, 0, 0, INVALID_COORD
);
86 void coord_init_first_unit_nocheck(coord_t
*coord
, const znode
* node
)
88 coord_init_values(coord
, node
, 0, 0, AT_UNIT
);
91 /* Initialize a coordinate to point at the first unit of the first item. If the
92 node is empty, it is positioned at the EMPTY_NODE. */
93 void coord_init_first_unit(coord_t
*coord
, const znode
* node
)
95 int is_empty
= node_is_empty(node
);
97 coord_init_values(coord
, node
, 0, 0, (is_empty
? EMPTY_NODE
: AT_UNIT
));
99 assert("jmacd-9801", coord_check(coord
));
102 /* Initialize a coordinate to point at the last unit of the last item. If the
103 node is empty, it is positioned at the EMPTY_NODE. */
104 void coord_init_last_unit(coord_t
*coord
, const znode
* node
)
106 int is_empty
= node_is_empty(node
);
108 coord_init_values(coord
, node
,
109 (is_empty
? 0 : node_num_items(node
) - 1), 0,
110 (is_empty
? EMPTY_NODE
: AT_UNIT
));
112 coord
->unit_pos
= coord_last_unit_pos(coord
);
113 assert("jmacd-9802", coord_check(coord
));
116 /* Initialize a coordinate to before the first item. If the node is empty, it is
117 positioned at the EMPTY_NODE. */
118 void coord_init_before_first_item(coord_t
*coord
, const znode
* node
)
120 int is_empty
= node_is_empty(node
);
122 coord_init_values(coord
, node
, 0, 0,
123 (is_empty
? EMPTY_NODE
: BEFORE_UNIT
));
125 assert("jmacd-9803", coord_check(coord
));
128 /* Initialize a coordinate to after the last item. If the node is empty, it is
129 positioned at the EMPTY_NODE. */
130 void coord_init_after_last_item(coord_t
*coord
, const znode
* node
)
132 int is_empty
= node_is_empty(node
);
134 coord_init_values(coord
, node
,
135 (is_empty
? 0 : node_num_items(node
) - 1), 0,
136 (is_empty
? EMPTY_NODE
: AFTER_ITEM
));
138 assert("jmacd-9804", coord_check(coord
));
141 /* Initialize a coordinate to after last unit in the item. Coord must be set
142 already to existing item */
143 void coord_init_after_item_end(coord_t
*coord
)
145 coord
->between
= AFTER_UNIT
;
146 coord
->unit_pos
= coord_last_unit_pos(coord
);
149 /* Initialize a coordinate to before the item. Coord must be set already to
151 void coord_init_before_item(coord_t
*coord
)
154 coord
->between
= BEFORE_ITEM
;
157 /* Initialize a coordinate to after the item. Coord must be set already to
159 void coord_init_after_item(coord_t
*coord
)
162 coord
->between
= AFTER_ITEM
;
165 /* Initialize a coordinate by 0s. Used in places where init_coord was used and
166 it was not clear how actually */
167 void coord_init_zero(coord_t
*coord
)
169 memset(coord
, 0, sizeof(*coord
));
172 /* Return the number of units at the present item.
173 Asserts coord_is_existing_item(). */
174 unsigned coord_num_units(const coord_t
*coord
)
176 assert("jmacd-9806", coord_is_existing_item(coord
));
178 return item_plugin_by_coord(coord
)->b
.nr_units(coord
);
181 /* Returns true if the coord was initializewd by coord_init_invalid (). */
182 /* Audited by: green(2002.06.15) */
183 int coord_is_invalid(const coord_t
*coord
)
185 return coord
->between
== INVALID_COORD
;
188 /* Returns true if the coordinate is positioned at an existing item, not before
189 or after an item. It may be placed at, before, or after any unit within the
190 item, whether existing or not. */
191 int coord_is_existing_item(const coord_t
*coord
)
193 switch (coord
->between
) {
203 return coord
->item_pos
< coord_num_items(coord
);
206 impossible("jmacd-9900", "unreachable coord: %p", coord
);
210 /* Returns true if the coordinate is positioned at an existing unit, not before
212 /* Audited by: green(2002.06.15) */
213 int coord_is_existing_unit(const coord_t
*coord
)
215 switch (coord
->between
) {
225 return (coord
->item_pos
< coord_num_items(coord
)
226 && coord
->unit_pos
< coord_num_units(coord
));
229 impossible("jmacd-9902", "unreachable");
233 /* Returns true if the coordinate is positioned at the first unit of the first
234 item. Not true for empty nodes nor coordinates positioned before the first
236 /* Audited by: green(2002.06.15) */
237 int coord_is_leftmost_unit(const coord_t
*coord
)
239 return (coord
->between
== AT_UNIT
&& coord
->item_pos
== 0
240 && coord
->unit_pos
== 0);
244 /* For assertions only, checks for a valid coordinate. */
245 int coord_check(const coord_t
*coord
)
247 if (coord
->node
== NULL
)
249 if (znode_above_root(coord
->node
))
252 switch (coord
->between
) {
257 if (!node_is_empty(coord
->node
))
259 return coord
->item_pos
== 0 && coord
->unit_pos
== 0;
263 if (node_is_empty(coord
->node
) && (coord
->item_pos
== 0)
264 && (coord
->unit_pos
== 0))
270 /* before/after item should not set unit_pos. */
271 if (coord
->unit_pos
!= 0)
276 if (coord
->item_pos
>= node_num_items(coord
->node
))
279 /* FIXME-VS: we are going to check unit_pos. This makes no sense when
280 between is set either AFTER_ITEM or BEFORE_ITEM */
281 if (coord
->between
== AFTER_ITEM
|| coord
->between
== BEFORE_ITEM
)
284 if (coord_is_iplug_set(coord
) &&
286 item_plugin_by_coord(coord
)->b
.nr_units(coord
) - 1)
292 /* Adjust coordinate boundaries based on the number of items prior to
293 coord_next/prev. Returns 1 if the new position is does not exist. */
294 static int coord_adjust_items(coord_t
*coord
, unsigned items
, int is_next
)
296 /* If the node is invalid, leave it. */
297 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
330 position is an existing unit. */
331 int coord_next_unit(coord_t
*coord
)
333 unsigned items
= coord_num_items(coord
);
335 if (coord_adjust_items(coord
, items
, 1) == 1)
338 switch (coord
->between
) {
340 /* Now it is positioned at the same unit. */
341 coord
->between
= AT_UNIT
;
346 /* If it was at or after a unit and there are more units in this
347 item, advance to the next one. */
348 if (coord
->unit_pos
< coord_last_unit_pos(coord
)) {
349 coord
->unit_pos
+= 1;
350 coord
->between
= AT_UNIT
;
354 /* Otherwise, it is crossing an item boundary and treated as if
355 it was after the current item. */
356 coord
->between
= AFTER_ITEM
;
361 /* Check for end-of-node. */
362 if (coord
->item_pos
== items
- 1)
365 coord_inc_item_pos(coord
);
367 coord
->between
= AT_UNIT
;
371 /* The adjust_items checks ensure that we are valid here. */
373 coord
->between
= AT_UNIT
;
378 /* Handled in coord_adjust_items(). */
382 impossible("jmacd-9902", "unreachable");
386 /* Advances the coordinate by one item to the right. If empty, no change. If
387 coord_is_rightmost_unit, advances to AFTER THE LAST ITEM. Returns 0 if new
388 position is an existing item. */
389 int coord_next_item(coord_t
*coord
)
391 unsigned items
= coord_num_items(coord
);
393 if (coord_adjust_items(coord
, items
, 1) == 1)
396 switch (coord
->between
) {
401 /* Check for end-of-node. */
402 if (coord
->item_pos
== items
- 1) {
403 coord
->between
= AFTER_ITEM
;
405 coord_clear_iplug(coord
);
409 /* Anywhere in an item, go to the next one. */
410 coord
->between
= AT_UNIT
;
411 coord_inc_item_pos(coord
);
416 /* The out-of-range check ensures that we are valid here. */
418 coord
->between
= AT_UNIT
;
422 /* Handled in coord_adjust_items(). */
426 impossible("jmacd-9903", "unreachable");
430 /* Advances the coordinate by one unit to the left. If empty, no change. If
431 coord_is_leftmost_unit, advances to BEFORE THE FIRST ITEM. Returns 0 if new
432 position is an existing unit. */
433 int coord_prev_unit(coord_t
*coord
)
435 unsigned items
= coord_num_items(coord
);
437 if (coord_adjust_items(coord
, items
, 0) == 1)
440 switch (coord
->between
) {
443 if (coord
->unit_pos
> 0) {
444 coord
->unit_pos
-= 1;
445 coord
->between
= AT_UNIT
;
449 if (coord
->item_pos
== 0) {
450 coord
->between
= BEFORE_ITEM
;
454 coord_dec_item_pos(coord
);
455 coord
->unit_pos
= coord_last_unit_pos(coord
);
456 coord
->between
= AT_UNIT
;
460 /* What if unit_pos is out-of-range? */
462 coord
->unit_pos
<= coord_last_unit_pos(coord
));
463 coord
->between
= AT_UNIT
;
467 if (coord
->item_pos
== 0)
470 coord_dec_item_pos(coord
);
474 coord
->between
= AT_UNIT
;
475 coord
->unit_pos
= coord_last_unit_pos(coord
);
483 impossible("jmacd-9904", "unreachable");
487 /* Advances the coordinate by one item to the left. If empty, no change. If
488 coord_is_leftmost_unit, advances to BEFORE THE FIRST ITEM. Returns 0 if new
489 position is an existing item. */
490 int coord_prev_item(coord_t
*coord
)
492 unsigned items
= coord_num_items(coord
);
494 if (coord_adjust_items(coord
, items
, 0) == 1)
497 switch (coord
->between
) {
503 if (coord
->item_pos
== 0) {
504 coord
->between
= BEFORE_ITEM
;
509 coord_dec_item_pos(coord
);
511 coord
->between
= AT_UNIT
;
515 coord
->between
= AT_UNIT
;
524 impossible("jmacd-9905", "unreachable");
528 /* Calls either coord_init_first_unit or coord_init_last_unit depending on
530 void coord_init_sideof_unit(coord_t
*coord
, const znode
* node
, sideof dir
)
532 assert("jmacd-9821", dir
== LEFT_SIDE
|| dir
== RIGHT_SIDE
);
533 if (dir
== LEFT_SIDE
) {
534 coord_init_first_unit(coord
, node
);
536 coord_init_last_unit(coord
, node
);
540 /* Calls either coord_is_before_leftmost or coord_is_after_rightmost depending
541 on sideof argument. */
542 /* Audited by: green(2002.06.15) */
543 int coord_is_after_sideof_unit(coord_t
*coord
, sideof dir
)
545 assert("jmacd-9822", dir
== LEFT_SIDE
|| dir
== RIGHT_SIDE
);
546 if (dir
== LEFT_SIDE
) {
547 return coord_is_before_leftmost(coord
);
549 return coord_is_after_rightmost(coord
);
553 /* Calls either coord_next_unit or coord_prev_unit depending on sideof argument.
555 /* Audited by: green(2002.06.15) */
556 int coord_sideof_unit(coord_t
*coord
, sideof dir
)
558 assert("jmacd-9823", dir
== LEFT_SIDE
|| dir
== RIGHT_SIDE
);
559 if (dir
== LEFT_SIDE
) {
560 return coord_prev_unit(coord
);
562 return coord_next_unit(coord
);
567 int coords_equal(const coord_t
*c1
, const coord_t
*c2
)
569 assert("nikita-2840", c1
!= NULL
);
570 assert("nikita-2841", c2
!= NULL
);
573 c1
->node
== c2
->node
&&
574 c1
->item_pos
== c2
->item_pos
&&
575 c1
->unit_pos
== c2
->unit_pos
&& c1
->between
== c2
->between
;
577 #endif /* REISER4_DEBUG */
579 /* If coord_is_after_rightmost return NCOORD_ON_THE_RIGHT, if
580 coord_is_after_leftmost return NCOORD_ON_THE_LEFT, otherwise return
582 /* Audited by: green(2002.06.15) */
583 coord_wrt_node
coord_wrt(const coord_t
*coord
)
585 if (coord_is_before_leftmost(coord
))
586 return COORD_ON_THE_LEFT
;
588 if (coord_is_after_rightmost(coord
))
589 return COORD_ON_THE_RIGHT
;
594 /* Returns true if the coordinate is positioned after the last item or after the
595 last unit of the last item or it is an empty node. */
596 /* Audited by: green(2002.06.15) */
597 int coord_is_after_rightmost(const coord_t
*coord
)
599 assert("jmacd-7313", coord_check(coord
));
601 switch (coord
->between
) {
612 return (coord
->item_pos
== node_num_items(coord
->node
) - 1);
615 return ((coord
->item_pos
== node_num_items(coord
->node
) - 1) &&
616 coord
->unit_pos
== coord_last_unit_pos(coord
));
619 impossible("jmacd-9908", "unreachable");
623 /* Returns true if the coordinate is positioned before the first item or it is
625 int coord_is_before_leftmost(const coord_t
*coord
)
627 /* FIXME-VS: coord_check requires node to be loaded whereas it is not
628 necessary to check if coord is set before leftmost
629 assert ("jmacd-7313", coord_check (coord)); */
630 switch (coord
->between
) {
642 return (coord
->item_pos
== 0) && (coord
->unit_pos
== 0);
645 impossible("jmacd-9908", "unreachable");
649 /* Returns true if the coordinate is positioned after a item, before a item,
650 after the last unit of an item, before the first unit of an item, or at an
652 /* Audited by: green(2002.06.15) */
653 int coord_is_between_items(const coord_t
*coord
)
655 assert("jmacd-7313", coord_check(coord
));
657 switch (coord
->between
) {
668 return coord
->unit_pos
== 0;
671 return coord
->unit_pos
== coord_last_unit_pos(coord
);
674 impossible("jmacd-9908", "unreachable");
679 /* Returns true if the coordinates are positioned at adjacent units, regardless
680 of before-after or item boundaries. */
681 int coord_are_neighbors(coord_t
*c1
, coord_t
*c2
)
686 assert("nikita-1241", c1
!= NULL
);
687 assert("nikita-1242", c2
!= NULL
);
688 assert("nikita-1243", c1
->node
== c2
->node
);
689 assert("nikita-1244", coord_is_existing_unit(c1
));
690 assert("nikita-1245", coord_is_existing_unit(c2
));
693 switch (coord_compare(c1
, c2
)) {
694 case COORD_CMP_ON_LEFT
:
698 case COORD_CMP_ON_RIGHT
:
705 wrong_return_value("nikita-1246", "compare_coords()");
707 assert("vs-731", left
&& right
);
708 if (left
->item_pos
== right
->item_pos
) {
709 return left
->unit_pos
+ 1 == right
->unit_pos
;
710 } else if (left
->item_pos
+ 1 == right
->item_pos
) {
711 return (left
->unit_pos
== coord_last_unit_pos(left
))
712 && (right
->unit_pos
== 0);
717 #endif /* REISER4_DEBUG */
719 /* Assuming two coordinates are positioned in the same node, return
720 COORD_CMP_ON_RIGHT, COORD_CMP_ON_LEFT, or COORD_CMP_SAME depending on c1's
721 position relative to c2. */
722 /* Audited by: green(2002.06.15) */
723 coord_cmp
coord_compare(coord_t
*c1
, coord_t
*c2
)
725 assert("vs-209", c1
->node
== c2
->node
);
726 assert("vs-194", coord_is_existing_unit(c1
)
727 && coord_is_existing_unit(c2
));
729 if (c1
->item_pos
> c2
->item_pos
)
730 return COORD_CMP_ON_RIGHT
;
731 if (c1
->item_pos
< c2
->item_pos
)
732 return COORD_CMP_ON_LEFT
;
733 if (c1
->unit_pos
> c2
->unit_pos
)
734 return COORD_CMP_ON_RIGHT
;
735 if (c1
->unit_pos
< c2
->unit_pos
)
736 return COORD_CMP_ON_LEFT
;
737 return COORD_CMP_SAME
;
740 /* If the coordinate is between items, shifts it to the right. Returns 0 on
741 success and non-zero if there is no position to the right. */
742 int coord_set_to_right(coord_t
*coord
)
744 unsigned items
= coord_num_items(coord
);
746 if (coord_adjust_items(coord
, items
, 1) == 1)
749 switch (coord
->between
) {
755 coord
->between
= AT_UNIT
;
759 if (coord
->unit_pos
< coord_last_unit_pos(coord
)) {
760 coord
->unit_pos
+= 1;
761 coord
->between
= AT_UNIT
;
767 if (coord
->item_pos
== items
- 1) {
768 coord
->between
= AFTER_ITEM
;
772 coord_inc_item_pos(coord
);
773 coord
->between
= AT_UNIT
;
778 if (coord
->item_pos
== items
- 1)
781 coord_inc_item_pos(coord
);
783 coord
->between
= AT_UNIT
;
793 impossible("jmacd-9920", "unreachable");
797 /* If the coordinate is between items, shifts it to the left. Returns 0 on
798 success and non-zero if there is no position to the left. */
799 int coord_set_to_left(coord_t
*coord
)
801 unsigned items
= coord_num_items(coord
);
803 if (coord_adjust_items(coord
, items
, 0) == 1)
806 switch (coord
->between
) {
811 coord
->between
= AT_UNIT
;
815 coord
->between
= AT_UNIT
;
816 coord
->unit_pos
= coord_last_unit_pos(coord
);
820 if (coord
->unit_pos
> 0) {
821 coord
->unit_pos
-= 1;
822 coord
->between
= AT_UNIT
;
826 if (coord
->item_pos
== 0) {
827 coord
->between
= BEFORE_ITEM
;
831 coord
->unit_pos
= coord_last_unit_pos(coord
);
832 coord_dec_item_pos(coord
);
833 coord
->between
= AT_UNIT
;
838 if (coord
->item_pos
== 0)
841 coord_dec_item_pos(coord
);
842 coord
->unit_pos
= coord_last_unit_pos(coord
);
843 coord
->between
= AT_UNIT
;
853 impossible("jmacd-9920", "unreachable");
857 static const char *coord_tween_tostring(between_enum n
)
861 return "before unit";
863 return "before item";
878 sprintf(buf
, "unknown: %i", n
);
884 void print_coord(const char *mes
, const coord_t
*coord
, int node
)
887 printk("%s: null\n", mes
);
890 printk("%s: item_pos = %d, unit_pos %d, tween=%s, iplug=%d\n",
891 mes
, coord
->item_pos
, coord
->unit_pos
,
892 coord_tween_tostring(coord
->between
), coord
->iplugid
);
896 item_utmost_child_real_block(const coord_t
*coord
, sideof side
,
897 reiser4_block_nr
* blk
)
899 return item_plugin_by_coord(coord
)->f
.utmost_child_real_block(coord
,
904 int item_utmost_child(const coord_t
*coord
, sideof side
, jnode
** child
)
906 return item_plugin_by_coord(coord
)->f
.utmost_child(coord
, side
, child
);
909 /* @count bytes of flow @f got written, update correspondingly f->length,
910 f->data and f->key */
911 void move_flow_forward(flow_t
*f
, unsigned count
)
916 set_key_offset(&f
->key
, get_key_offset(&f
->key
) + count
);
921 c-indentation-style: "K&R"