Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include <kdb.h>
10 :
11 : // for keySetComment
12 : #include <kdbextension.h>
13 :
14 : #include <stdlib.h>
15 :
16 : /**A functional access to keys.
17 : *
18 : * Instead of writing your own loop you can write
19 : * a function working with a key and pass it to
20 : * this method.
21 : *
22 : * The function will be executed for all keys in
23 : * the keyset.
24 : *
25 : * @param ks the keyset to work with
26 : * @param func the function to execute on every key of the keyset
27 : * @return the sum of all return values
28 : * @retval -1 if any function returned -1, the execution will stop there, but
29 : * ksCurrent() will tell you where it stopped.
30 : * @see ksFilter()
31 : */
32 0 : int ksForEach (KeySet * ks, int (*func) (Key * k))
33 : {
34 0 : int ret = 0;
35 : Key * current;
36 :
37 0 : cursor_t cursor = ksGetCursor (ks);
38 0 : ksRewind (ks);
39 0 : while ((current = ksNext (ks)) != 0)
40 : {
41 0 : int rc = func (current);
42 0 : if (rc == -1) return -1;
43 0 : ret += rc;
44 : }
45 0 : ksSetCursor (ks, cursor);
46 0 : return ret;
47 : }
48 :
49 :
50 : /**Filter a keyset.
51 : *
52 : * filter is executed for every key in the keyset result. When it returns 0,
53 : * the key will be dropped, when it returns 1 it will be ksAppendKey()ed to result,
54 : * when it returns -1 the processing will be stopped. You can use ksCurrent()
55 : * on input to see where the problem was. Because of this input is not const,
56 : * apart from ksCurrent() the input will not be changed. The keys that have
57 : * been in result before will stay untouched.
58 : *
59 : * @param result is the keyset where keys are added.
60 : * @param input is the keyset the filter works on.
61 : * @param filter is the function to execute on every key of the keyset to decide if
62 : * it should be ksAppendKey()ed to the result.
63 : * @return the number of keys added on success
64 : * @retval 0 when nothing was done
65 : * @retval -1 when filter returned an error (-1), ksCurrent() of input will
66 : * be the problematic key.
67 : * @see ksForEach()
68 : **/
69 0 : int ksFilter (KeySet * result, KeySet * input, int (*filter) (Key * k))
70 : {
71 0 : int ret = 0;
72 : Key * current;
73 :
74 0 : cursor_t cursor = ksGetCursor (input);
75 0 : ksRewind (input);
76 0 : while ((current = ksNext (input)) != 0)
77 : {
78 0 : int rc = filter (current);
79 0 : if (rc == -1)
80 : return -1;
81 0 : else if (rc != 0)
82 : {
83 0 : ++ret;
84 0 : ksAppendKey (result, keyDup (current));
85 : }
86 : }
87 0 : ksSetCursor (input, cursor);
88 0 : return ret;
89 : }
90 :
91 :
92 : Key * global_a;
93 :
94 0 : int add_string (Key * check)
95 : {
96 0 : return keySetString (check, "string");
97 : }
98 0 : int add_comment (Key * check)
99 : {
100 0 : return keySetMeta (check, "comment", "comment");
101 : }
102 0 : int has_a (Key * check)
103 : {
104 0 : return keyName (check)[5] == 'a';
105 : }
106 0 : int below_a (Key * check)
107 : {
108 0 : return keyIsBelow (global_a, check);
109 : }
110 0 : int direct_below_a (Key * check)
111 : {
112 0 : return keyIsDirectBelow (global_a, check);
113 : }
114 :
115 0 : int sum_helper (Key * check)
116 : {
117 0 : return atoi (keyValue (check));
118 : }
119 0 : int below_30 (Key * check)
120 : {
121 0 : return atoi (keyValue (check)) < 30;
122 : }
123 0 : int find_80 (Key * check)
124 : {
125 0 : int n = atoi (keyValue (check));
126 0 : return n > 70 ? -1 : 1;
127 : }
128 :
129 0 : int main (void)
130 : {
131 : KeySet * out;
132 0 : KeySet * ks = ksNew (64, keyNew ("user/a/1", KEY_END), keyNew ("user/a/2", KEY_END), keyNew ("user/a/b/1", KEY_END),
133 : keyNew ("user/a/b/2", KEY_END), keyNew ("user/ab/2", KEY_END), keyNew ("user/b/1", KEY_END),
134 : keyNew ("user/b/2", KEY_END), KS_END);
135 0 : KeySet * values = 0;
136 0 : KeySet * values_below_30 = 0;
137 :
138 0 : global_a = keyNew ("user/a", KEY_END);
139 :
140 0 : ksForEach (ks, add_string);
141 0 : ksForEach (ks, add_comment);
142 :
143 0 : out = ksNew (0, KS_END);
144 0 : ksFilter (out, ks, has_a);
145 0 : ksDel (out);
146 :
147 0 : out = ksNew (0, KS_END);
148 0 : ksFilter (out, ks, below_a);
149 0 : ksDel (out);
150 :
151 0 : out = ksNew (0, KS_END);
152 0 : ksFilter (out, ks, direct_below_a);
153 0 : ksDel (out);
154 :
155 0 : ksDel (ks);
156 0 : keyDel (global_a);
157 0 : global_a = 0;
158 :
159 0 : values = ksNew (64, keyNew ("user/a", KEY_VALUE, "40", KEY_END), keyNew ("user/b", KEY_VALUE, "20", KEY_END),
160 : keyNew ("user/c", KEY_VALUE, "80", KEY_END), keyNew ("user/d", KEY_VALUE, "24", KEY_END),
161 : keyNew ("user/e", KEY_VALUE, "32", KEY_END), keyNew ("user/f", KEY_VALUE, "12", KEY_END),
162 : keyNew ("user/g", KEY_VALUE, "43", KEY_END), KS_END);
163 :
164 : /* add together */
165 0 : ksForEach (values, sum_helper);
166 :
167 0 : values_below_30 = ksNew (0, KS_END);
168 0 : ksFilter (values_below_30, values, below_30);
169 0 : ksForEach (values_below_30, sum_helper);
170 :
171 0 : ksForEach (values, find_80);
172 0 : ksCurrent (values); /* here is user/c */
173 0 : ksLookupByName (values, "user/c", 0); /* should find the same */
174 0 : ksDel (values);
175 0 : ksDel (values_below_30);
176 : }
|