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