#include "smartcolsP.h"
static int walk_line(struct libscols_table *tb,
struct libscols_line *ln,
struct libscols_column *cl,
int (*callback)(struct libscols_table *,
struct libscols_line *,
struct libscols_column *,
void *),
void *data)
{
int rc = 0;
DBG(LINE, ul_debugobj(ln, " wall line"));
/* we list group children in __scols_print_tree() after tree root node */
if (is_group_member(ln) && is_last_group_member(ln) && has_group_children(ln))
tb->ngrpchlds_pending++;
if (has_groups(tb))
rc = scols_groups_update_grpset(tb, ln);
if (rc == 0)
rc = callback(tb, ln, cl, data);
/* children */
if (rc == 0 && has_children(ln)) {
struct list_head *p;
DBG(LINE, ul_debugobj(ln, " children walk"));
list_for_each(p, &ln->ln_branch) {
struct libscols_line *chld = list_entry(p,
struct libscols_line, ln_children);
rc = walk_line(tb, chld, cl, callback, data);
if (rc)
break;
}
}
DBG(LINE, ul_debugobj(ln, "<- walk line done [rc=%d]", rc));
return rc;
}
/* last line in the tree? */
int scols_walk_is_last(struct libscols_table *tb, struct libscols_line *ln)
{
if (tb->walk_last_done == 0)
return 0;
if (tb->ngrpchlds_pending > 0)
return 0;
if (has_children(ln))
return 0;
if (is_tree_root(ln) && !is_last_tree_root(tb, ln))
return 0;
if (is_group_member(ln) && (!is_last_group_member(ln) || has_group_children(ln)))
return 0;
if (is_child(ln)) {
struct libscols_line *parent = ln->parent;
if (!is_last_child(ln))
return 0;
while (parent) {
if (is_child(parent) && !is_last_child(parent))
return 0;
if (!parent->parent)
break;
parent = parent->parent;
}
if (is_tree_root(parent) && !is_last_tree_root(tb, parent))
return 0;
}
if (is_group_child(ln) && !is_last_group_child(ln))
return 0;
DBG(LINE, ul_debugobj(ln, "last in table"));
return 1;
}
int scols_walk_tree(struct libscols_table *tb,
struct libscols_column *cl,
int (*callback)(struct libscols_table *,
struct libscols_line *,
struct libscols_column *,
void *),
void *data)
{
int rc = 0;
struct libscols_line *ln;
struct libscols_iter itr;
assert(tb);
DBG(TAB, ul_debugobj(tb, ">> walk start"));
/* init */
tb->ngrpchlds_pending = 0;
tb->walk_last_tree_root = NULL;
tb->walk_last_done = 0;
if (has_groups(tb))
scols_groups_reset_state(tb);
/* set pointer to last tree root */
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (scols_table_next_line(tb, &itr, &ln) == 0) {
if (!tb->walk_last_tree_root)
tb->walk_last_tree_root = ln;
if (is_child(ln) || is_group_child(ln))
continue;
tb->walk_last_tree_root = ln;
}
/* walk */
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) {
if (ln->parent || ln->parent_group)
continue;
if (tb->walk_last_tree_root == ln)
tb->walk_last_done = 1;
rc = walk_line(tb, ln, cl, callback, data);
/* walk group's children */
while (rc == 0 && tb->ngrpchlds_pending) {
struct libscols_group *gr = scols_grpset_get_printable_children(tb);
struct list_head *p;
DBG(LINE, ul_debugobj(ln, " walk group children [pending=%zu]", tb->ngrpchlds_pending));
if (!gr) {
DBG(LINE, ul_debugobj(ln, " *** ngrpchlds_pending counter invalid"));
tb->ngrpchlds_pending = 0;
break;
}
tb->ngrpchlds_pending--;
list_for_each(p, &gr->gr_children) {
struct libscols_line *chld =
list_entry(p, struct libscols_line, ln_children);
rc = walk_line(tb, chld, cl, callback, data);
if (rc)
break;
}
}
}
tb->ngrpchlds_pending = 0;
tb->walk_last_done = 0;
DBG(TAB, ul_debugobj(tb, "<< walk end [rc=%d]", rc));
return rc;
}