1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
4  *
5  * This library is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "evolution-data-server-config.h"
19 
20 #include <stdio.h>
21 #include <string.h>
22 
23 #include "camel-named-flags.h"
24 
G_DEFINE_BOXED_TYPE(CamelNamedFlags,camel_named_flags,camel_named_flags_copy,camel_named_flags_free)25 G_DEFINE_BOXED_TYPE (CamelNamedFlags,
26 		camel_named_flags,
27 		camel_named_flags_copy,
28 		camel_named_flags_free)
29 
30 /**
31  * camel_named_flags_new:
32  *
33  * Creates a new #CamelNamedFlags.
34  *
35  * Returns: (transfer full): A newly allocated #CamelNamedFlags.
36  *    Free it with camel_named_flags_free() when done with it.
37  *
38  * Since: 3.24
39  **/
40 CamelNamedFlags *
41 camel_named_flags_new (void)
42 {
43 	return (CamelNamedFlags *) g_ptr_array_new_with_free_func (g_free);
44 }
45 
46 /**
47  * camel_named_flags_new_sized:
48  * @reserve_size: an array size to reserve
49  *
50  * Created a new #CamelNamedFlags, which has reserved @reserve_size
51  * elements. This value doesn't influence the camel_named_flags_get_length(),
52  * which returns zero on the array returned from this function.
53  *
54  * Returns: (transfer full): A newly allocated #CamelNameValueArray.
55  *    Free it with camel_named_flags_free() when done with it.
56  *
57  * See: camel_name_value_array_new, camel_name_value_array_copy
58  *
59  * Since: 3.24
60  **/
61 CamelNamedFlags *
camel_named_flags_new_sized(guint reserve_size)62 camel_named_flags_new_sized (guint reserve_size)
63 {
64 	return (CamelNamedFlags *) g_ptr_array_new_full (reserve_size, g_free);
65 }
66 
67 /**
68  * camel_named_flags_copy:
69  * @named_flags: (nullable): a #CamelNamedFlags
70  *
71  * Creates a copy of the @named_flags and returns it.
72  *
73  * Returns: (transfer full): A newly allocated #CamelNamedFlags.
74  *    Free it with camel_named_flags_free() when done with it.
75  *
76  * Since: 3.24
77  **/
78 CamelNamedFlags *
camel_named_flags_copy(const CamelNamedFlags * named_flags)79 camel_named_flags_copy (const CamelNamedFlags *named_flags)
80 {
81 	const GPtrArray *src = (const GPtrArray *) named_flags;
82 	GPtrArray *arr;
83 	guint ii;
84 
85 	if (!src)
86 		return NULL;
87 
88 	arr = (GPtrArray *) camel_named_flags_new_sized (src->len);
89 	for (ii = 0; ii < src->len; ii++) {
90 		const gchar *name = g_ptr_array_index (src, ii);
91 
92 		if (name && *name)
93 			g_ptr_array_add (arr, g_strdup (name));
94 	}
95 
96 	return (CamelNamedFlags *) arr;
97 }
98 
99 /**
100  * camel_named_flags_free:
101  * @named_flags: (nullable): a #CamelNamedFlags, or %NULL
102  *
103  * Frees memory associated iwth the @named_flags. Does nothing,
104  * if @named_flags is %NULL.
105  *
106  * Since: 3.24
107  **/
108 void
camel_named_flags_free(CamelNamedFlags * named_flags)109 camel_named_flags_free (CamelNamedFlags *named_flags)
110 {
111 	if (named_flags)
112 		g_ptr_array_unref ((GPtrArray *) named_flags);
113 }
114 
115 static guint
camel_named_flags_find(const CamelNamedFlags * named_flags,const gchar * name)116 camel_named_flags_find (const CamelNamedFlags *named_flags,
117 			const gchar *name)
118 {
119 	GPtrArray *arr = (GPtrArray *) named_flags;
120 	guint ii;
121 
122 	g_return_val_if_fail (named_flags != NULL, (guint) -1);
123 	g_return_val_if_fail (name != NULL, (guint) -1);
124 
125 	for (ii = 0; ii < arr->len; ii++) {
126 		const gchar *nm = g_ptr_array_index (arr, ii);
127 
128 		if (g_strcmp0 (nm, name) == 0)
129 			return ii;
130 	}
131 
132 	return (guint) -1;
133 }
134 
135 /**
136  * camel_named_flags_insert:
137  * @named_flags: a #CamelNamedFlags
138  * @name: name of the flag
139  *
140  * Inserts a flag named @name into the @named_flags, if it is not included
141  * already (comparing case sensitively), or does nothing otherwise.
142  *
143  * Returns: %TRUE the flag named @name was inserted; %FALSE otherwise.
144  *
145  * Since: 3.24
146  **/
147 gboolean
camel_named_flags_insert(CamelNamedFlags * named_flags,const gchar * name)148 camel_named_flags_insert (CamelNamedFlags *named_flags,
149 			  const gchar *name)
150 {
151 	GPtrArray *arr = (GPtrArray *) named_flags;
152 	guint index;
153 
154 	g_return_val_if_fail (named_flags != NULL, FALSE);
155 	g_return_val_if_fail (name != NULL, FALSE);
156 
157 	index = camel_named_flags_find (named_flags, name);
158 
159 	/* already there */
160 	if (index != (guint) -1)
161 		return FALSE;
162 
163 	g_ptr_array_add (arr, g_strdup (name));
164 
165 	return TRUE;
166 }
167 
168 /**
169  * camel_named_flags_remove:
170  * @named_flags: a #CamelNamedFlags
171  * @name: name of the flag
172  *
173  * Removes a flag named @name from the @named_flags.
174  *
175  * Returns: %TRUE when the @named_flags contained a flag named @name,
176  *    comparing case sensitively, and it was removed; %FALSE otherwise.
177  *
178  * Since: 3.24
179  **/
180 gboolean
camel_named_flags_remove(CamelNamedFlags * named_flags,const gchar * name)181 camel_named_flags_remove (CamelNamedFlags *named_flags,
182 			  const gchar *name)
183 {
184 	GPtrArray *arr = (GPtrArray *) named_flags;
185 	guint index;
186 
187 	g_return_val_if_fail (named_flags != NULL, FALSE);
188 	g_return_val_if_fail (name != NULL, FALSE);
189 
190 	index = camel_named_flags_find (named_flags, name);
191 
192 	/* not there */
193 	if (index == (guint) -1)
194 		return FALSE;
195 
196 	g_ptr_array_remove_index (arr, index);
197 
198 	return TRUE;
199 }
200 
201 /**
202  * camel_named_flags_contains:
203  * @named_flags: a #CamelNamedFlags
204  * @name: name of the flag
205  *
206  * Returns: Whether the @named_flags contains a flag named @name,
207  *    comparing case sensitively.
208  *
209  * Since: 3.24
210  **/
211 gboolean
camel_named_flags_contains(const CamelNamedFlags * named_flags,const gchar * name)212 camel_named_flags_contains (const CamelNamedFlags *named_flags,
213 			    const gchar *name)
214 {
215 	g_return_val_if_fail (named_flags != NULL, FALSE);
216 	g_return_val_if_fail (name != NULL, FALSE);
217 
218 	return camel_named_flags_find (named_flags, name) != (guint) -1;
219 }
220 
221 /**
222  * camel_named_flags_clear:
223  * @named_flags: a #CamelNamedFlags
224  *
225  * Removes all the elements of the array.
226  *
227  * Since: 3.24
228  **/
229 void
camel_named_flags_clear(CamelNamedFlags * named_flags)230 camel_named_flags_clear (CamelNamedFlags *named_flags)
231 {
232 	GPtrArray *arr = (GPtrArray *) named_flags;
233 
234 	g_return_if_fail (named_flags != NULL);
235 
236 	if (arr->len)
237 		g_ptr_array_remove_range (arr, 0, arr->len);
238 }
239 
240 /**
241  * camel_named_flags_get_length:
242  * @named_flags: (nullable): a #CamelNamedFlags
243  *
244  * Returns: Length of the array, aka how many named flags are stored there.
245  *
246  * Since: 3.24
247  **/
248 guint
camel_named_flags_get_length(const CamelNamedFlags * named_flags)249 camel_named_flags_get_length (const CamelNamedFlags *named_flags)
250 {
251 	const GPtrArray *arr = (const GPtrArray *) named_flags;
252 
253 	if (!named_flags)
254 		return 0;
255 
256 	return arr->len;
257 }
258 
259 /**
260  * camel_named_flags_get:
261  * @named_flags: a #CamelNamedFlags
262  * @index: an index of an element
263  *
264  * Returns: (transfer none) (nullable): Name of the flag in at the given @index,
265  *   or %NULL on error.
266  *
267  * Since: 3.24
268  **/
269 const gchar *
camel_named_flags_get(const CamelNamedFlags * named_flags,guint index)270 camel_named_flags_get (const CamelNamedFlags *named_flags,
271 		       guint index)
272 {
273 	const GPtrArray *arr = (const GPtrArray *) named_flags;
274 
275 	g_return_val_if_fail (named_flags != NULL, NULL);
276 
277 	if (index >= camel_named_flags_get_length (named_flags))
278 		return NULL;
279 
280 	return g_ptr_array_index (arr, index);
281 }
282 
283 /**
284  * camel_named_flags_equal:
285  * @named_flags_a: (nullable): the first #CamelNamedFlags
286  * @named_flags_b: (nullable): the second #CamelNamedFlags
287  *
288  * Compares content of the two #CamelNamedFlags and returns whether
289  * they equal. Note this is an expensive operation for large sets.
290  *
291  * Returns: Whether the two #CamelNamedFlags have the same content.
292  *
293  * Since: 3.24
294  **/
295 gboolean
camel_named_flags_equal(const CamelNamedFlags * named_flags_a,const CamelNamedFlags * named_flags_b)296 camel_named_flags_equal (const CamelNamedFlags *named_flags_a,
297 			 const CamelNamedFlags *named_flags_b)
298 {
299 	guint ii, len;
300 
301 	if (named_flags_a == named_flags_b)
302 		return TRUE;
303 
304 	if (!named_flags_a || !named_flags_b)
305 		return camel_named_flags_get_length (named_flags_a) == camel_named_flags_get_length (named_flags_b);
306 
307 	len = camel_named_flags_get_length (named_flags_a);
308 	if (len != camel_named_flags_get_length (named_flags_b))
309 		return FALSE;
310 
311 	for (ii = 0; ii < len; ii++) {
312 		if (!camel_named_flags_contains (named_flags_a, camel_named_flags_get (named_flags_b, ii)))
313 			return FALSE;
314 	}
315 
316 	return TRUE;
317 }
318