1/***************************************************************************
2 * CVSID: $Id$
3 *
4 * property.c : HalProperty methods
5 *
6 * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7 * Copyright (C) 2004 Novell, Inc.
8 *
9 * Licensed under the Academic Free License version 2.1
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24 *
25 **************************************************************************/
26
27#ifdef HAVE_CONFIG_H
28#  include <config.h>
29#endif
30
31#include <string.h>
32#include <glib.h>
33
34#include "logger.h"
35#include "property.h"
36
37struct _HalProperty {
38	char *key;
39
40	int type;
41	union {
42		char *str_value;
43		dbus_int32_t int_value;
44 		dbus_uint64_t uint64_value;
45		dbus_bool_t bool_value;
46		double double_value;
47		GSList *strlist_value;
48	} v;
49	gboolean readonly;
50	gboolean persistence;
51	gboolean callout;
52};
53
54void
55hal_property_free (HalProperty *prop)
56{
57
58	g_free (prop->key);
59
60	if (prop->type == HAL_PROPERTY_TYPE_STRING) {
61		g_free (prop->v.str_value);
62	} else if (prop->type == HAL_PROPERTY_TYPE_STRLIST) {
63		GSList *i;
64		for (i = prop->v.strlist_value; i != NULL; i = g_slist_next (i)) {
65			g_free (i->data);
66		}
67		g_slist_free (prop->v.strlist_value);
68	}
69
70	g_free (prop);
71}
72
73HalProperty *
74hal_property_new_string (const char *key, const char *value)
75{
76	HalProperty *prop;
77	char *endchar;
78	gboolean validated = TRUE;
79
80	prop = g_new0 (HalProperty, 1);
81
82	prop->type = HAL_PROPERTY_TYPE_STRING;
83	prop->key = g_strdup (key);
84	prop->v.str_value = g_strdup (value != NULL ? value : "");
85
86	while (!g_utf8_validate (prop->v.str_value, -1,
87				 (const char **) &endchar)) {
88		validated = FALSE;
89		*endchar = '?';
90	}
91
92	if (!validated) {
93		HAL_WARNING (("Key '%s' has invalid UTF-8 string '%s'",
94			      key, prop->v.str_value));
95	}
96
97	return prop;
98}
99
100HalProperty *
101hal_property_new_int (const char *key, dbus_int32_t value)
102{
103	HalProperty *prop;
104
105	prop = g_new0 (HalProperty, 1);
106
107	prop->type = HAL_PROPERTY_TYPE_INT32;
108	prop->key = g_strdup (key);
109	prop->v.int_value = value;
110
111	return prop;
112}
113
114HalProperty *
115hal_property_new_uint64 (const char *key, dbus_uint64_t value)
116{
117	HalProperty *prop;
118
119	prop = g_new0 (HalProperty, 1);
120
121	prop->type = HAL_PROPERTY_TYPE_UINT64;
122	prop->key = g_strdup (key);
123	prop->v.uint64_value = value;
124
125	return prop;
126}
127
128HalProperty *
129hal_property_new_bool (const char *key, dbus_bool_t value)
130{
131	HalProperty *prop;
132
133	prop = g_new0 (HalProperty, 1);
134
135	prop->type = HAL_PROPERTY_TYPE_BOOLEAN;
136	prop->key = g_strdup (key);
137	prop->v.bool_value = value;
138
139	return prop;
140}
141
142HalProperty *
143hal_property_new_double (const char *key, double value)
144{
145	HalProperty *prop;
146
147	prop = g_new0 (HalProperty, 1);
148
149	prop->type = HAL_PROPERTY_TYPE_DOUBLE;
150	prop->key = g_strdup (key);
151	prop->v.double_value = value;
152
153	return prop;
154}
155
156const char *
157hal_property_get_key (HalProperty *prop)
158{
159	g_return_val_if_fail (prop != NULL, NULL);
160
161	return prop->key;
162}
163
164int
165hal_property_get_type (HalProperty *prop)
166{
167	g_return_val_if_fail (prop != NULL, HAL_PROPERTY_TYPE_INVALID);
168
169	return prop->type;
170}
171
172const char *
173hal_property_get_string (HalProperty *prop)
174{
175	g_return_val_if_fail (prop != NULL, NULL);
176	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_STRING, NULL);
177
178	return prop->v.str_value;
179}
180
181dbus_int32_t
182hal_property_get_int (HalProperty *prop)
183{
184	g_return_val_if_fail (prop != NULL, -1);
185	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_INT32, -1);
186
187	return prop->v.int_value;
188}
189
190dbus_uint64_t
191hal_property_get_uint64 (HalProperty *prop)
192{
193	g_return_val_if_fail (prop != NULL, -1);
194	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_UINT64, -1);
195
196	return prop->v.uint64_value;
197}
198
199dbus_bool_t
200hal_property_get_bool (HalProperty *prop)
201{
202	g_return_val_if_fail (prop != NULL, FALSE);
203	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_BOOLEAN, FALSE);
204
205	return prop->v.bool_value;
206}
207
208char *
209hal_property_to_string (HalProperty *prop)
210{
211	g_return_val_if_fail (prop != NULL, NULL);
212
213	switch (prop->type) {
214	case HAL_PROPERTY_TYPE_STRING:
215		return g_strdup (prop->v.str_value);
216	case HAL_PROPERTY_TYPE_INT32:
217		return g_strdup_printf ("%d", prop->v.int_value);
218	case HAL_PROPERTY_TYPE_UINT64:
219		return g_strdup_printf ("%llu", (long long unsigned int) prop->v.uint64_value);
220	case HAL_PROPERTY_TYPE_BOOLEAN:
221		/* FIXME: Maybe use 1 and 0 here instead? */
222		return g_strdup (prop->v.bool_value ? "true" : "false");
223	case HAL_PROPERTY_TYPE_DOUBLE:
224		return g_strdup_printf ("%f", prop->v.double_value);
225	case HAL_PROPERTY_TYPE_STRLIST:
226	{
227		GSList *iter;
228		guint i;
229		char buf[256];
230
231		i = 0;
232		buf[0] = '\0';
233		for (iter = hal_property_get_strlist (prop);
234		     iter != NULL && i < sizeof(buf);
235		     iter = g_slist_next (iter)) {
236			guint len;
237			const char *str;
238
239			str = (const char *) iter->data;
240			len = strlen (str);
241			strncpy (buf + i, str, sizeof(buf) - i);
242			i += len;
243
244			if (g_slist_next (iter) != NULL && i < sizeof(buf)) {
245				buf[i] = '\t';
246				i++;
247			}
248		}
249		return g_strdup (buf);
250	}
251
252	default:
253		return NULL;
254	}
255}
256
257double
258hal_property_get_double (HalProperty *prop)
259{
260	g_return_val_if_fail (prop != NULL, -1.0);
261	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_DOUBLE, -1.0);
262
263	return prop->v.double_value;
264}
265
266void
267hal_property_set_string (HalProperty *prop, const char *value)
268{
269	char *endchar;
270	gboolean validated = TRUE;
271
272	g_return_if_fail (prop != NULL);
273	g_return_if_fail (prop->type == HAL_PROPERTY_TYPE_STRING ||
274			  prop->type == HAL_PROPERTY_TYPE_INVALID);
275
276	prop->type = HAL_PROPERTY_TYPE_STRING;
277	if (prop->v.str_value != NULL)
278		g_free (prop->v.str_value);
279	prop->v.str_value = g_strdup (value);
280
281	while (!g_utf8_validate (prop->v.str_value, -1,
282				 (const char **) &endchar)) {
283		validated = FALSE;
284		*endchar = '?';
285	}
286
287	if (!validated) {
288		HAL_WARNING (("Key '%s' has invalid UTF-8 string '%s'",
289			      prop->key, value));
290	}
291}
292
293void
294hal_property_set_int (HalProperty *prop, dbus_int32_t value)
295{
296	g_return_if_fail (prop != NULL);
297	g_return_if_fail (prop->type == HAL_PROPERTY_TYPE_INT32 ||
298			  prop->type == HAL_PROPERTY_TYPE_INVALID);
299
300	prop->type = HAL_PROPERTY_TYPE_INT32;
301	prop->v.int_value = value;
302}
303
304void
305hal_property_set_uint64 (HalProperty *prop, dbus_uint64_t value)
306{
307	g_return_if_fail (prop != NULL);
308	g_return_if_fail (prop->type == HAL_PROPERTY_TYPE_UINT64 ||
309			  prop->type == HAL_PROPERTY_TYPE_INVALID);
310
311	prop->type = HAL_PROPERTY_TYPE_UINT64;
312	prop->v.uint64_value = value;
313}
314
315void
316hal_property_set_bool (HalProperty *prop, dbus_bool_t value)
317{
318	g_return_if_fail (prop != NULL);
319	g_return_if_fail (prop->type == HAL_PROPERTY_TYPE_BOOLEAN ||
320			  prop->type == HAL_PROPERTY_TYPE_INVALID);
321
322	prop->type = HAL_PROPERTY_TYPE_BOOLEAN;
323	prop->v.bool_value = value;
324}
325
326void
327hal_property_set_double (HalProperty *prop, double value)
328{
329	g_return_if_fail (prop != NULL);
330	g_return_if_fail (prop->type == HAL_PROPERTY_TYPE_DOUBLE ||
331			  prop->type == HAL_PROPERTY_TYPE_INVALID);
332
333	prop->type = HAL_PROPERTY_TYPE_DOUBLE;
334	prop->v.double_value = value;
335}
336
337void
338hal_property_set_attribute (HalProperty *prop,
339			    enum PropertyAttribute attr,
340			    gboolean val)
341{
342	g_return_if_fail (prop != NULL);
343
344	switch (attr) {
345	case READONLY:
346		prop->readonly = val;
347		break;
348	case PERSISTENCE:
349		prop->persistence = val;
350		break;
351	case CALLOUT:
352		prop->callout = val;
353		break;
354	}
355}
356
357gboolean
358hal_property_get_attribute (HalProperty *prop,
359			    enum PropertyAttribute attr)
360{
361	g_return_val_if_fail (prop != NULL, -1);
362
363	switch (attr) {
364	case READONLY:
365		return prop->readonly;
366	case PERSISTENCE:
367		return prop->persistence;
368	case CALLOUT:
369		return prop->callout;
370	default:
371		return -1;
372	}
373}
374
375HalProperty *
376hal_property_new_strlist (const char *key)
377{
378	HalProperty *prop;
379
380	prop = g_new0 (HalProperty, 1);
381
382	prop->type = HAL_PROPERTY_TYPE_STRLIST;
383	prop->key = g_strdup (key);
384	prop->v.strlist_value = NULL;
385
386	return prop;
387}
388
389GSList *
390hal_property_get_strlist (HalProperty *prop)
391{
392	g_return_val_if_fail (prop != NULL, NULL);
393	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_STRLIST, NULL);
394
395	return prop->v.strlist_value;
396}
397
398gboolean
399hal_property_strlist_append (HalProperty *prop, const char *value)
400{
401	g_return_val_if_fail (prop != NULL, FALSE);
402	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_STRLIST, FALSE);
403
404	prop->v.strlist_value = g_slist_append (prop->v.strlist_value, g_strdup (value));
405
406	return TRUE;
407}
408
409gboolean
410hal_property_strlist_prepend (HalProperty *prop, const char *value)
411{
412	g_return_val_if_fail (prop != NULL, FALSE);
413	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_STRLIST, FALSE);
414
415	prop->v.strlist_value = g_slist_prepend (prop->v.strlist_value, g_strdup (value));
416
417	return TRUE;
418}
419
420gboolean
421hal_property_strlist_remove_elem (HalProperty *prop, guint index)
422{
423	GSList *elem;
424
425	g_return_val_if_fail (prop != NULL, FALSE);
426	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_STRLIST, FALSE);
427
428	if (prop->v.strlist_value == NULL)
429		return FALSE;
430
431	elem = g_slist_nth (prop->v.strlist_value, index);
432	if (elem == NULL)
433		return FALSE;
434
435	g_free (elem->data);
436	prop->v.strlist_value = g_slist_delete_link (prop->v.strlist_value, elem);
437	return TRUE;
438}
439
440
441gboolean
442hal_property_strlist_add (HalProperty  *prop, const char *value)
443{
444	GSList *elem;
445
446	g_return_val_if_fail (prop != NULL, FALSE);
447	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_STRLIST, FALSE);
448
449	for (elem = prop->v.strlist_value; elem != NULL; elem = g_slist_next (elem)) {
450		if (strcmp (elem->data, value) == 0) {
451			return FALSE;
452		}
453	}
454
455	return hal_property_strlist_append (prop, value);
456}
457
458gboolean
459hal_property_strlist_remove (HalProperty *prop, const char *value)
460{
461	guint i;
462	GSList *elem;
463
464	g_return_val_if_fail (prop != NULL, FALSE);
465	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_STRLIST, FALSE);
466
467	for (elem = prop->v.strlist_value, i = 0; elem != NULL; elem = g_slist_next (elem), i++) {
468		if (strcmp (elem->data, value) == 0) {
469			return hal_property_strlist_remove_elem (prop, i);
470		}
471	}
472
473	return FALSE;
474}
475
476gboolean
477hal_property_strlist_clear (HalProperty *prop)
478{
479	GSList *elem;
480
481	g_return_val_if_fail (prop != NULL, FALSE);
482	g_return_val_if_fail (prop->type == HAL_PROPERTY_TYPE_STRLIST, FALSE);
483
484	for (elem = prop->v.strlist_value; elem != NULL; elem = g_slist_next (elem)) {
485		g_free (elem->data);
486	}
487	g_slist_free (prop->v.strlist_value);
488
489	return FALSE;
490}
491