1 #include "smartcolsP.h"
2
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)3 static int walk_line(struct libscols_table *tb,
4 struct libscols_line *ln,
5 struct libscols_column *cl,
6 int (*callback)(struct libscols_table *,
7 struct libscols_line *,
8 struct libscols_column *,
9 void *),
10 void *data)
11 {
12 int rc = 0;
13
14 DBG(LINE, ul_debugobj(ln, " wall line"));
15
16 /* we list group children in __scols_print_tree() after tree root node */
17 if (is_group_member(ln) && is_last_group_member(ln) && has_group_children(ln))
18 tb->ngrpchlds_pending++;
19
20 if (has_groups(tb))
21 rc = scols_groups_update_grpset(tb, ln);
22 if (rc == 0)
23 rc = callback(tb, ln, cl, data);
24
25 /* children */
26 if (rc == 0 && has_children(ln)) {
27 struct list_head *p;
28
29 DBG(LINE, ul_debugobj(ln, " children walk"));
30
31 list_for_each(p, &ln->ln_branch) {
32 struct libscols_line *chld = list_entry(p,
33 struct libscols_line, ln_children);
34
35 rc = walk_line(tb, chld, cl, callback, data);
36 if (rc)
37 break;
38 }
39 }
40
41 DBG(LINE, ul_debugobj(ln, "<- walk line done [rc=%d]", rc));
42 return rc;
43 }
44
45 /* last line in the tree? */
scols_walk_is_last(struct libscols_table * tb,struct libscols_line * ln)46 int scols_walk_is_last(struct libscols_table *tb, struct libscols_line *ln)
47 {
48 if (tb->walk_last_done == 0)
49 return 0;
50 if (tb->ngrpchlds_pending > 0)
51 return 0;
52 if (has_children(ln))
53 return 0;
54 if (is_tree_root(ln) && !is_last_tree_root(tb, ln))
55 return 0;
56 if (is_group_member(ln) && (!is_last_group_member(ln) || has_group_children(ln)))
57 return 0;
58 if (is_child(ln)) {
59 struct libscols_line *parent = ln->parent;
60
61 if (!is_last_child(ln))
62 return 0;
63 while (parent) {
64 if (is_child(parent) && !is_last_child(parent))
65 return 0;
66 if (!parent->parent)
67 break;
68 parent = parent->parent;
69 }
70 if (is_tree_root(parent) && !is_last_tree_root(tb, parent))
71 return 0;
72 }
73 if (is_group_child(ln) && !is_last_group_child(ln))
74 return 0;
75
76 DBG(LINE, ul_debugobj(ln, "last in table"));
77 return 1;
78 }
79
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)80 int scols_walk_tree(struct libscols_table *tb,
81 struct libscols_column *cl,
82 int (*callback)(struct libscols_table *,
83 struct libscols_line *,
84 struct libscols_column *,
85 void *),
86 void *data)
87 {
88 int rc = 0;
89 struct libscols_line *ln;
90 struct libscols_iter itr;
91
92 assert(tb);
93 DBG(TAB, ul_debugobj(tb, ">> walk start"));
94
95 /* init */
96 tb->ngrpchlds_pending = 0;
97 tb->walk_last_tree_root = NULL;
98 tb->walk_last_done = 0;
99
100 if (has_groups(tb))
101 scols_groups_reset_state(tb);
102
103 /* set pointer to last tree root */
104 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
105 while (scols_table_next_line(tb, &itr, &ln) == 0) {
106 if (!tb->walk_last_tree_root)
107 tb->walk_last_tree_root = ln;
108 if (is_child(ln) || is_group_child(ln))
109 continue;
110 tb->walk_last_tree_root = ln;
111 }
112
113 /* walk */
114 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
115 while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) {
116 if (ln->parent || ln->parent_group)
117 continue;
118
119 if (tb->walk_last_tree_root == ln)
120 tb->walk_last_done = 1;
121 rc = walk_line(tb, ln, cl, callback, data);
122
123 /* walk group's children */
124 while (rc == 0 && tb->ngrpchlds_pending) {
125 struct libscols_group *gr = scols_grpset_get_printable_children(tb);
126 struct list_head *p;
127
128 DBG(LINE, ul_debugobj(ln, " walk group children [pending=%zu]", tb->ngrpchlds_pending));
129 if (!gr) {
130 DBG(LINE, ul_debugobj(ln, " *** ngrpchlds_pending counter invalid"));
131 tb->ngrpchlds_pending = 0;
132 break;
133 }
134
135 tb->ngrpchlds_pending--;
136
137 list_for_each(p, &gr->gr_children) {
138 struct libscols_line *chld =
139 list_entry(p, struct libscols_line, ln_children);
140
141 rc = walk_line(tb, chld, cl, callback, data);
142 if (rc)
143 break;
144 }
145 }
146 }
147
148 tb->ngrpchlds_pending = 0;
149 tb->walk_last_done = 0;
150 DBG(TAB, ul_debugobj(tb, "<< walk end [rc=%d]", rc));
151 return rc;
152 }
153