Line data Source code
1 : #include "referencegraph.h"
2 : #include <kdb.h>
3 : #include <kdbease.h>
4 : #include <kdbhelper.h>
5 : #include <stdlib.h>
6 :
7 : struct _RefGraph
8 : {
9 : KeySet * inner;
10 : KeySet * leaves;
11 : };
12 :
13 12 : RefGraph * rgNew (void)
14 : {
15 12 : RefGraph * graph = elektraCalloc (sizeof (struct _RefGraph));
16 12 : graph->inner = ksNew (0, KS_END);
17 12 : graph->leaves = ksNew (0, KS_END);
18 12 : return graph;
19 : }
20 :
21 8 : RefGraph * rgDup (const RefGraph * source)
22 : {
23 8 : RefGraph * graph = elektraCalloc (sizeof (struct _RefGraph));
24 8 : graph->inner = ksDup (source->inner);
25 8 : graph->leaves = ksDup (source->leaves);
26 8 : return graph;
27 : }
28 :
29 26 : bool rgHasLeaf (const RefGraph * graph)
30 : {
31 26 : return ksGetSize (graph->leaves) > 0;
32 : }
33 :
34 116 : bool rgContains (const RefGraph * graph, const char * nodeName)
35 : {
36 116 : return ksLookupByName (graph->inner, nodeName, 0) != NULL;
37 : }
38 :
39 26 : bool rgEmpty (const RefGraph * graph)
40 : {
41 26 : return ksGetSize (graph->inner) == 0 && ksGetSize (graph->leaves) == 0;
42 : }
43 :
44 52 : bool rgAddEdge (RefGraph * graph, const char * fromNode, const char * toNode)
45 : {
46 52 : Key * node = ksLookupByName (graph->leaves, fromNode, KDB_O_POP);
47 52 : if (node != NULL)
48 : {
49 40 : keySetMeta (node, "last", "#0");
50 40 : keySetMeta (node, "#0", toNode);
51 :
52 40 : ksAppendKey (graph->inner, node);
53 40 : return true;
54 : }
55 :
56 12 : node = ksLookupByName (graph->inner, fromNode, 0);
57 12 : if (node == NULL)
58 : {
59 : return false;
60 : }
61 :
62 12 : Key * lastKey = keyDup (keyGetMeta (node, "last"));
63 12 : if (elektraArrayIncName (lastKey) < 0)
64 : {
65 12 : keyDel (lastKey);
66 12 : return false;
67 : }
68 :
69 0 : keySetMeta (node, "last", keyName (lastKey));
70 0 : keySetMeta (node, keyName (lastKey), toNode);
71 0 : keyDel (lastKey);
72 :
73 0 : return true;
74 : }
75 :
76 114 : void rgAddNode (RefGraph * graph, const char * nodeName)
77 : {
78 114 : Key * node = keyNew (nodeName, KEY_END);
79 114 : ksAppendKey (graph->leaves, node);
80 114 : }
81 :
82 0 : const char * rgGetEdge (RefGraph * graph, const char * fromNode, int index)
83 : {
84 0 : Key * node = ksLookupByName (graph->inner, fromNode, 0);
85 0 : if (node == NULL)
86 : {
87 : return NULL;
88 : }
89 :
90 : char elem[ELEKTRA_MAX_ARRAY_SIZE];
91 0 : elektraWriteArrayNumber (elem, index);
92 :
93 0 : const Key * k = keyGetMeta (node, elem);
94 0 : return k == NULL ? NULL : keyString (k);
95 : }
96 :
97 16 : void rgRemoveLeaves (RefGraph * graph)
98 : {
99 16 : KeySet * newLeaves = ksNew (0, KS_END);
100 16 : KeySet * newInner = ksNew (0, KS_END);
101 :
102 : Key * cur;
103 62 : while ((cur = ksPop (graph->inner)) != NULL)
104 : {
105 30 : const char * last = keyString (keyGetMeta (cur, "last"));
106 30 : last++;
107 60 : while (*last == '_')
108 : {
109 0 : last++;
110 : }
111 30 : long size = strtol (last, NULL, 10);
112 :
113 : char elem[ELEKTRA_MAX_ARRAY_SIZE];
114 30 : for (int i = 0; i < size; ++i)
115 : {
116 0 : elektraWriteArrayNumber (elem, i);
117 0 : const Key * toNode = keyGetMeta (cur, elem);
118 0 : if (ksLookupByName (graph->leaves, keyString (toNode), 0) != NULL)
119 : {
120 0 : keySetMeta (cur, elem, NULL);
121 : }
122 : }
123 :
124 : int write = 0;
125 0 : for (int read = 0; read < size; ++read, ++write)
126 : {
127 0 : elektraWriteArrayNumber (elem, read);
128 :
129 : const Key * toNode;
130 0 : while ((toNode = keyGetMeta (cur, elem)) == NULL && read < size)
131 : {
132 0 : read++;
133 : }
134 :
135 0 : if (read >= size)
136 : {
137 : break;
138 : }
139 :
140 0 : elektraWriteArrayNumber (elem, write);
141 0 : keySetMeta (cur, elem, keyString (toNode));
142 : }
143 30 : elektraWriteArrayNumber (elem, write);
144 30 : keySetMeta (cur, "last", elem);
145 :
146 30 : if (write == 0)
147 : {
148 30 : ksAppendKey (newLeaves, cur);
149 : }
150 : else
151 : {
152 0 : ksAppendKey (newInner, cur);
153 : }
154 :
155 30 : keyDel (cur);
156 : }
157 :
158 16 : ksClear (graph->leaves);
159 16 : ksAppend (graph->leaves, newLeaves);
160 16 : ksClear (graph->inner);
161 16 : ksAppend (graph->inner, newInner);
162 :
163 16 : ksDel (newLeaves);
164 16 : ksDel (newInner);
165 16 : }
166 :
167 20 : void rgDel (RefGraph * graph)
168 : {
169 20 : ksDel (graph->inner);
170 20 : ksDel (graph->leaves);
171 20 : elektraFree (graph);
172 20 : }
|