1 /*
2   Copyright 2020 Northern.tech AS
3 
4   This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 3.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
18 
19   To the extent this program is licensed as part of the Enterprise
20   versions of CFEngine, the applicable Commercial Open Source License
21   (COSL) may apply to this file if you as a licensee so wish it. See
22   included file COSL.txt.
23 */
24 
25 #include <platform.h>
26 #include <set.h>
27 #include <string.h> // strlen()
28 
29 #include <alloc.h>
30 #include <string_lib.h>
31 #include <buffer.h>
32 
TYPED_SET_DEFINE(String,char *,StringHash_untyped,StringEqual_untyped,free)33 TYPED_SET_DEFINE(String, char *,
34                  StringHash_untyped, StringEqual_untyped, free)
35 
36 Set *SetNew(MapHashFn element_hash_fn,
37             MapKeyEqualFn element_equal_fn,
38             MapDestroyDataFn element_destroy_fn)
39 {
40     return MapNew(element_hash_fn, element_equal_fn, element_destroy_fn, NULL);
41 }
42 
SetDestroy(Set * set)43 void SetDestroy(Set *set)
44 {
45     MapDestroy(set);
46 }
47 
SetAdd(Set * set,void * element)48 void SetAdd(Set *set, void *element)
49 {
50     assert(set != NULL);
51     MapInsert(set, element, element);
52 }
53 
SetContains(const Set * set,const void * element)54 bool SetContains(const Set *set, const void *element)
55 {
56     assert(set != NULL);
57     return MapHasKey(set, element);
58 }
59 
SetRemove(Set * set,const void * element)60 bool SetRemove(Set *set, const void *element)
61 {
62     assert(set != NULL);
63     return MapRemove(set, element);
64 }
65 
SetClear(Set * set)66 void SetClear(Set *set)
67 {
68     assert(set != NULL);
69     MapClear(set);
70 }
71 
SetSize(const Set * set)72 size_t SetSize(const Set *set)
73 {
74     assert(set != NULL);
75     return MapSize(set);
76 }
77 
SetIsEqual(const Set * set1,const Set * set2)78 bool SetIsEqual(const Set *set1, const Set *set2)
79 {
80     assert(set1 != NULL);
81     assert(set2 != NULL);
82     return MapContainsSameKeys(set1, set2);
83 }
84 
SetIteratorInit(Set * set)85 SetIterator SetIteratorInit(Set *set)
86 {
87     assert(set != NULL);
88     return MapIteratorInit(set);
89 }
90 
SetIteratorNext(SetIterator * i)91 void *SetIteratorNext(SetIterator *i)
92 {
93     MapKeyValue *kv = MapIteratorNext(i);
94     return kv ? kv->key : NULL;
95 }
96 
SetJoin(Set * set,Set * otherset,SetElementCopyFn copy_function)97 void SetJoin(Set *set, Set *otherset, SetElementCopyFn copy_function)
98 {
99     assert(set != NULL);
100     assert(otherset != NULL);
101     if (set == otherset)
102         return;
103 
104     SetIterator si = SetIteratorInit(otherset);
105     void *ptr = NULL;
106 
107     for (ptr = SetIteratorNext(&si); ptr != NULL; ptr = SetIteratorNext(&si))
108     {
109         if (copy_function != NULL)
110         {
111             ptr = copy_function(ptr);
112         }
113         SetAdd(set, ptr);
114     }
115 }
116 
StringSetToBuffer(StringSet * set,const char delimiter)117 Buffer *StringSetToBuffer(StringSet *set, const char delimiter)
118 {
119     assert(set != NULL);
120 
121     Buffer *buf = BufferNew();
122     StringSetIterator it = StringSetIteratorInit(set);
123     const char *element = NULL;
124     int pos = 0;
125     int size = StringSetSize(set);
126     char minibuf[2];
127 
128     minibuf[0] = delimiter;
129     minibuf[1] = '\0';
130 
131     while ((element = StringSetIteratorNext(&it)))
132     {
133         BufferAppend(buf, element, strlen(element));
134         if (pos < size-1)
135         {
136             BufferAppend(buf, minibuf, sizeof(char));
137         }
138 
139         pos++;
140     }
141 
142     return buf;
143 }
144 
StringSetAddSplit(StringSet * set,const char * str,char delimiter)145 void StringSetAddSplit(StringSet *set, const char *str, char delimiter)
146 {
147     assert(set != NULL);
148     if (str) // TODO: remove this inconsistency, add assert(str)
149     {
150         const char *prev = str;
151         const char *cur = str;
152 
153         while (*cur != '\0')
154         {
155             if (*cur == delimiter)
156             {
157                 size_t len = cur - prev;
158                 if (len > 0)
159                 {
160                     StringSetAdd(set, xstrndup(prev, len));
161                 }
162                 else
163                 {
164                     StringSetAdd(set, xstrdup(""));
165                 }
166                 prev = cur + 1;
167             }
168 
169             cur++;
170         }
171 
172         if (cur > prev)
173         {
174             StringSetAdd(set, xstrndup(prev, cur - prev));
175         }
176     }
177 }
178 
StringSetFromString(const char * str,char delimiter)179 StringSet *StringSetFromString(const char *str, char delimiter)
180 {
181     StringSet *set = StringSetNew();
182 
183     StringSetAddSplit(set, str, delimiter);
184 
185     return set;
186 }
187 
StringSetToJson(const StringSet * set)188 JsonElement *StringSetToJson(const StringSet *set)
189 {
190     assert(set != NULL);
191 
192     JsonElement *arr = JsonArrayCreate(StringSetSize(set));
193     StringSetIterator it = StringSetIteratorInit((StringSet *)set);
194     const char *el = NULL;
195 
196     while ((el = StringSetIteratorNext(&it)))
197     {
198         JsonArrayAppendString(arr, el);
199     }
200 
201     return arr;
202 }
203