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