Update the go-menu when disabling browser in AE.
[gmpc.git] / src / config1.c
blob2e6a7eb792a691ea716ae69b704fcd1695205435
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2011 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpc.wikia.com/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
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.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <glib.h>
24 #include <glib/gstdio.h>
25 #ifndef WIN32
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #endif
29 #include "config1.h"
31 #define LOG_DOMAIN "Config"
33 typedef enum _ConfigNodeType
35 TYPE_CATEGORY,
36 TYPE_ITEM,
37 TYPE_ITEM_MULTIPLE
38 } ConfigNodeType;
39 /**
40 * A config node
41 * 24byte large
43 typedef struct _config_node
45 struct _config_node *next;
46 struct _config_node *prev;
47 struct _config_node *parent;
48 gchar *name;
49 ConfigNodeType type;
50 /* Save some extra memory by using a union
51 * It is actually effective because we build a resonable large tree using this
53 union
55 /* TYPE_CATEGORY */
56 struct _config_node *children;
57 gchar *value; /* TYPE_ITEM* */
59 } config_node;
61 typedef struct _config_obj
63 gchar *url;
64 /* GMutex *lock;*/
65 config_node *root;
66 int total_size;
67 guint save_timeout;
68 } _config_obj;
70 static void __int_cfg_set_single_value_as_string(config_obj * cfg, const char *class, const char *sclass,
71 const char *ssclass, const char *key, const char *value);
72 static gboolean cfg_save_real(config_obj *);
73 static void __int_cfg_remove_node(config_obj *, config_node *);
74 static config_node *cfg_get_class_multiple(config_obj * cfg, config_node * root, const char *class);
75 static void __int_cfg_do_special_cleanup(config_obj * cfg, config_node * node);
76 static config_node *cfg_add_class(config_obj *, config_node *, const char *);
77 static config_node *cfg_new_node(void);
78 static void cfg_add_child(config_node *, config_node *);
79 static void cfg_save_delayed(config_obj * cfg);
81 static void cfg_open_parse_file(config_obj * cfgo, FILE * fp)
83 char buffer[1024];
84 int len = 0;
85 int c, version = 0;
86 config_node *cur = NULL;
87 config_node *multiple = NULL;
88 int firstchar = 0;
89 while ((c = fgetc(fp)) != EOF)
91 if (c == '2' && !firstchar)
93 version = 2;
95 firstchar = 1;
96 if (c == '[')
98 len = 0;
99 c = fgetc(fp);
100 while (c != ']' && c != EOF && len < 1023)
102 buffer[len] = c;
103 len++;
104 c = fgetc(fp);
106 buffer[len] = '\0';
107 if (len > 0 && len < 256)
109 // printf("add class: %s -> %s\n", buffer, (cur )?cur->name:"");
110 cur = cfg_add_class(cfgo, (version < 2) ? NULL : cur, buffer);
111 } else if (len == 0)
113 if (version < 2)
115 cur = NULL;
116 } else if (cur)
118 cur = cur->parent;
121 /* seek end of line */
122 while (c != EOF && c != '\n')
123 c = fgetc(fp);
125 if (cur && c == '{')
127 len = 0;
128 c = fgetc(fp);
129 while (c != '}' && c != EOF && len < 1023)
131 buffer[len] = c;
132 len++;
133 c = fgetc(fp);
135 buffer[len] = '\0';
136 if (len > 0 && len < 256)
138 config_node *child = cfg_new_node();
139 child->type = TYPE_ITEM_MULTIPLE;
140 child->name = g_strndup(buffer, len);
141 child->parent = cur;
142 child->children = NULL;
143 cfg_add_child(cur, child);
144 multiple = child;
145 cfgo->total_size += len + sizeof(config_node);
148 if (len == 0)
150 multiple = NULL;
152 /* seek end of line */
153 while (c != EOF && c != '\n')
154 c = fgetc(fp);
157 /* next, ignore commants and there must be a category */
158 else if (cur && (c == '#' || c == '/' || c == '\n' || c == ';'))
160 while (c != EOF && c != '\n')
161 c = fgetc(fp);
162 } else if (cur)
164 config_node *new = NULL;
165 len = 0;
166 while (c != '=' && c != EOF)
168 buffer[len] = c;
169 len++;
170 c = fgetc(fp);
172 if (len < 256 && len > 0)
174 int quote = 0;
176 /* write key name */
177 new = cfg_new_node();
178 new->parent = cur;
179 new->type = TYPE_ITEM;
180 new->name = g_strndup(buffer, len);
181 cfgo->total_size += len + sizeof(config_node);
182 /* Get value */
183 len = 0;
184 /* skip spaces */
185 while ((c = fgetc(fp)) == ' ') ;
186 /* we got a quoted string */
187 if (c == '"')
189 quote = 1;
190 c = fgetc(fp);
194 /* add escaped char */
195 if (c == '\\')
197 c = fgetc(fp);
198 if (c == 'n')
200 buffer[len] = '\n';
201 len++;
202 } else
204 buffer[len] = c;
205 len++;
208 /* We have a quoted string, and the closing quote comes */
209 else if (c == '"' && quote)
210 quote = -1;
211 else
213 buffer[len] = c;
214 len++;
216 c = fgetc(fp);
217 } while ((c != '\n' || quote) && c != EOF && quote >= 0 && len < 1023);
218 new->value = g_strndup(buffer, len);
219 cfgo->total_size += len;
220 if (multiple)
222 cfg_add_child(multiple, new);
223 } else
225 cfg_add_child(cur, new);
228 /* seek end of line */
229 while (c != EOF && c != '\n')
230 c = fgetc(fp);
231 } else
232 while (c != EOF && c != '\n')
233 c = fgetc(fp);
239 config_obj *cfg_open(gchar * url)
241 config_obj *cfgo = NULL;
242 /* check if there is an url passed */
243 if (url == NULL)
245 return NULL;
248 cfgo = g_malloc(sizeof(config_obj));
249 /* check if malloc went ok */
250 if (cfgo == NULL)
252 return NULL;
254 /* cfgo->lock = g_mutex_new();
255 g_mutex_lock(cfgo->lock);
257 cfgo->url = g_strdup(url);
258 cfgo->root = NULL;
259 cfgo->total_size = sizeof(config_obj) /*+sizeof(&cfgo->lock) */ + strlen(cfgo->url);
260 cfgo->save_timeout = 0;
262 if (g_file_test(cfgo->url, G_FILE_TEST_EXISTS))
264 FILE *fp = g_fopen(cfgo->url, "r");
265 if (fp)
267 cfg_open_parse_file(cfgo, fp);
268 fclose(fp);
271 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Config %s: allocated: %i\n", cfgo->url, cfgo->total_size);
273 g_mutex_unlock(cfgo->lock);
275 return cfgo;
279 void cfg_close(config_obj * cfgo)
281 if (cfgo == NULL)
283 return;
285 cfg_save_real(cfgo);
286 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Closing config '%s' with %i bytes allocated\n", cfgo->url, cfgo->total_size);
288 g_mutex_lock(cfgo->lock);
290 if (cfgo->url != NULL)
292 cfgo->total_size -= strlen(cfgo->url);
293 cfg_free_string(cfgo->url);
295 while (cfgo->root)
296 __int_cfg_remove_node(cfgo, cfgo->root);
298 g_mutex_unlock(cfgo->lock);
300 cfgo->total_size -= /*sizeof(&cfgo->lock)+ */ sizeof(config_obj);
301 /* g_mutex_free(cfgo->lock);*/
302 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Memory remaining: %i\n", cfgo->total_size);
303 g_free(cfgo);
304 cfgo = NULL;
308 static config_node *cfg_new_node(void)
310 config_node *newnode = g_slice_new(config_node);
311 newnode->type = TYPE_CATEGORY;
312 newnode->name = NULL;
313 newnode->next = NULL;
314 newnode->prev = NULL;
315 newnode->parent = NULL;
316 newnode->value = NULL;
317 newnode->children = NULL;
318 return newnode;
322 static config_node *cfg_add_class(config_obj * cfg, config_node * parent, const char *class)
324 config_node *newnode = cfg_new_node();
325 newnode->type = TYPE_CATEGORY;
326 newnode->name = g_strdup(class);
327 newnode->parent = parent;
328 cfg->total_size += sizeof(config_node) + strlen(class);
329 if (!parent)
331 if (cfg->root == NULL)
333 cfg->root = newnode;
334 } else
336 config_node *temp = cfg->root;
337 while (temp->next != NULL)
338 temp = temp->next;
339 temp->next = newnode;
340 newnode->prev = temp;
342 } else
344 if (parent->children == NULL)
346 parent->children = newnode;
347 } else
349 config_node *temp = parent->children;
350 /* get last node */
351 while (temp->next != NULL)
352 temp = temp->next;
353 temp->next = newnode;
354 newnode->prev = temp;
358 return newnode;
362 void cfg_add_child(config_node * parent, config_node * child)
364 if (parent == NULL || child == NULL)
365 return;
366 if (parent->type == TYPE_ITEM)
367 return;
368 if (parent->children == NULL)
370 parent->children = child;
371 child->parent = parent;
372 } else
374 config_node *temp = parent->children;
376 /* get last node */
377 while (temp->next != NULL)
378 temp = temp->next;
379 temp->next = child;
380 child->prev = temp;
381 child->parent = parent;
386 static void cfg_save_category(config_obj * cfg, config_node * node, FILE * fp)
388 config_node *temp = NULL;
390 if (node == NULL)
391 return;
392 /* find the first */
393 while (node->prev != NULL)
394 node = node->prev;
395 /* save some stuff */
396 for (temp = node; temp != NULL; temp = temp->next)
398 if (temp->type == TYPE_CATEGORY)
400 fputs("\n[", fp);
401 fputs(temp->name, fp);
402 fputs("]\n", fp);
403 cfg_save_category(cfg, temp->children, fp);
404 fputs("[]\n", fp);
406 if (temp->type == TYPE_ITEM_MULTIPLE)
408 fputs("\n{", fp);
409 fputs(temp->name, fp);
410 fputs("}\n", fp);
411 cfg_save_category(cfg, temp->children, fp);
412 fputs("{}\n\n", fp);
413 } else if (temp->type == TYPE_ITEM)
415 int i = 0;
416 int length = (temp->value) ? strlen(temp->value) : 0;
417 fputs(temp->name, fp);
418 fputs("=\"", fp);
419 for (i = 0; i < length; i++)
421 if (temp->value[i] == '"')
423 fputs("\\\"", fp);
424 } else if (temp->value[i] == '\\')
426 fputs("\\\\", fp);
427 } else if (temp->value[i] == '\n')
429 fputs("\\n", fp);
430 } else
432 putc(temp->value[i], fp);
435 fputs("\"\n", fp);
441 static gboolean cfg_save_real(config_obj * cfgo)
443 if (cfgo == NULL)
445 return FALSE;
448 if (cfgo->save_timeout)
450 g_source_remove(cfgo->save_timeout);
451 cfgo->save_timeout = 0;
452 } else
454 return FALSE;
456 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Save triggered:%s", cfgo->url);
457 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Saving config file: %s (%i bytes)", cfgo->url, cfgo->total_size);
458 if (cfgo->root != NULL)
460 FILE *fp = g_fopen(cfgo->url, "w");
461 if (!fp)
462 return FALSE;
463 fputs("2\n", fp);
464 cfg_save_category(cfgo, cfgo->root, fp);
465 fclose(fp);
466 #ifndef WIN32
467 chmod(cfgo->url, 0600);
468 #endif
471 return FALSE;
475 static config_node *cfg_get_class(config_obj * cfg, const char *class)
477 return cfg_get_class_multiple(cfg, NULL, class);
481 static config_node *cfg_get_class_multiple(config_obj * cfg, config_node * root, const char *class)
483 config_node *node = NULL;
484 if (root != NULL)
486 node = root->children;
488 } else
490 node = cfg->root;
492 if (node == NULL)
493 return NULL;
494 /* find the first */
495 while (node->prev != NULL)
496 node = node->prev;
498 for (; node != NULL; node = node->next)
500 if (node->type == TYPE_CATEGORY && !strcmp(node->name, class))
502 return node;
506 return NULL;
510 static config_node *cfg_get_single_value(config_obj * cfg, const char *class, const char *sclass, const char *ssclass,
511 const char *key)
513 /* take children */
514 config_node *cur = NULL;
515 cur = cfg_get_class(cfg, class);
516 if (cur == NULL || cur->children == NULL)
518 return NULL;
520 if (sclass)
522 cur = cfg_get_class_multiple(cfg, cur, sclass);
523 if (cur == NULL || cur->children == NULL)
524 return NULL;
526 if (ssclass)
528 cur = cfg_get_class_multiple(cfg, cur, ssclass);
529 if (cur == NULL || cur->children == NULL)
530 return NULL;
532 cur = cur->children;
533 for (; cur != NULL; cur = cur->next)
535 if (!strcmp(cur->name, key))
537 return cur;
540 return NULL;
544 /*void cfg_free_string(char *string)
546 if(string != NULL)
548 q_free(string);
552 static char *__int_cfg_get_single_value_as_string(config_obj * cfg, const char *class, const char *sclass,
553 const char *ssclass, const char *key)
555 config_node *cur = cfg_get_single_value(cfg, class, sclass, ssclass, key);
556 if (cur != NULL)
558 if (cur->type == TYPE_ITEM)
560 return g_strdup((char *)cur->value);
563 return NULL;
567 char *cfg_get_single_value_as_string(config_obj * cfg, const char *class, const char *key)
569 return cfg_get_single_value_as_string_mm(cfg, class, NULL, NULL, key);
573 char *cfg_get_single_value_as_string_with_default(config_obj * cfg, const char *class, const char *key, const char *def)
575 return cfg_get_single_value_as_string_with_default_mm(cfg, class, NULL, NULL, key, def);
579 static int __int_cfg_get_single_value_as_int_mm(config_obj * cfg, const char *class, const char *sclass,
580 const char *ssclass, const char *key)
582 config_node *cur = NULL;
583 int retv = CFG_INT_NOT_DEFINED;
585 cur = cfg_get_single_value(cfg, class, sclass, ssclass, key);
586 if (cur != NULL)
588 if (cur->type == TYPE_ITEM)
590 retv = (int)g_ascii_strtoull(cur->value, NULL, 0);
594 return retv;
598 int cfg_get_single_value_as_int(config_obj * cfg, const char *class, const char *key)
600 int retv = 0;
601 /* g_mutex_lock(cfg->lock);*/
602 retv = __int_cfg_get_single_value_as_int_mm(cfg, class, NULL, NULL, key);
603 /* g_mutex_unlock(cfg->lock);*/
604 return retv;
608 void cfg_set_single_value_as_int(config_obj * cfg, const char *class, const char *key, int value)
610 cfg_set_single_value_as_int_mm(cfg, class, NULL, NULL, key, value);
614 static void __int_cfg_set_single_value_as_int(config_obj * cfg, const char *class, const char *sclass,
615 const char *ssclass, const char *key, int value)
617 gchar *temp = NULL;
618 temp = g_strdup_printf("%i", value);
619 __int_cfg_set_single_value_as_string(cfg, class, sclass, ssclass, key, temp);
620 cfg_free_string(temp);
624 int cfg_get_single_value_as_int_with_default(config_obj * cfg, const char *class, const char *key, int def)
626 return cfg_get_single_value_as_int_with_default_mm(cfg, class, NULL, NULL, key, def);
630 /* float */
631 static float __int_cfg_get_single_value_as_float(config_obj * cfg, const char *class, const char *sclass,
632 const char *ssclass, const char *key)
634 float result = 0;
635 config_node *cur = NULL;
636 cur = cfg_get_single_value(cfg, class, sclass, ssclass, key);
638 if (cur == NULL)
640 return CFG_INT_NOT_DEFINED;
642 /* make it return an error */
643 result = g_ascii_strtod(cur->value, NULL);
644 return result;
648 float cfg_get_single_value_as_float(config_obj * cfg, const char *class, const char *key)
650 float retv = 0;
651 /* g_mutex_lock(cfg->lock);*/
652 retv = __int_cfg_get_single_value_as_float(cfg, class, NULL, NULL, key);
653 /* g_mutex_unlock(cfg->lock);*/
654 return retv;
658 float cfg_get_single_value_as_float_mm(config_obj * cfg, const char *class, const char *sclass, const char *ssclass,
659 const char *key)
661 float retv = 0;
662 /* g_mutex_lock(cfg->lock);*/
663 retv = __int_cfg_get_single_value_as_float(cfg, class, sclass, ssclass, key);
664 /* g_mutex_unlock(cfg->lock);*/
665 return retv;
669 void cfg_set_single_value_as_float(config_obj * cfg, const char *class, const char *key, float value)
671 char *value1 = NULL;
672 /* g_mutex_lock(cfg->lock);*/
673 value1 = g_strdup_printf("%f", value);
674 __int_cfg_set_single_value_as_string(cfg, class, NULL, NULL, key, value1);
675 cfg_free_string(value1);
676 /* g_mutex_unlock(cfg->lock);*/
680 float cfg_get_single_value_as_float_with_default(config_obj * cfg, const char *class, const char *key, float def)
682 float retv = 0;
683 /* g_mutex_lock(cfg->lock);*/
684 retv = __int_cfg_get_single_value_as_float(cfg, class, NULL, NULL, key);
685 if (retv == CFG_INT_NOT_DEFINED)
687 char *value1 = g_strdup_printf("%f", def);
688 __int_cfg_set_single_value_as_string(cfg, class, NULL, NULL, key, value1);
689 cfg_free_string(value1);
690 retv = __int_cfg_get_single_value_as_float(cfg, class, NULL, NULL, key);
692 /* g_mutex_unlock(cfg->lock);*/
693 /* make it return an error */
694 return retv;
698 static void __int_cfg_remove_node(config_obj * cfg, config_node * node)
700 if (node->type != TYPE_ITEM)
702 while (node->children)
704 __int_cfg_remove_node(cfg, node->children);
707 /* only child, and I have a parent */
708 if (node->next == NULL && node->prev == NULL && node->parent)
710 /* remove from list */
711 if (node->parent->type != TYPE_ITEM)
713 node->parent->children = NULL;
716 /* remove node from linked list */
717 if (node->prev != NULL)
719 if (node->parent && node->parent->children == node)
721 node->parent->children = node->prev;
723 node->prev->next = node->next;
725 if (node->next != NULL)
727 if (node->parent && node->parent->children == node)
729 node->parent->children = node->next;
731 node->next->prev = node->prev;
733 if (node == cfg->root)
735 if (node->prev)
737 cfg->root = node->prev;
738 } else if (node->next)
740 cfg->root = node->next;
741 } else
743 cfg->root = NULL;
746 cfg->total_size -= sizeof(config_node);
747 if (node->name)
749 cfg->total_size -= strlen(node->name);
750 cfg_free_string(node->name);
752 if (node->value)
754 cfg->total_size -= strlen(node->value);
755 cfg_free_string(node->value);
757 g_slice_free(config_node, node);
761 void cfg_del_single_value_mm(config_obj * cfg, const char *class, const char *sclass, const char *ssclass,
762 const char *key)
764 config_node *node = NULL;
765 /* g_mutex_lock(cfg->lock);*/
766 node = cfg_get_single_value(cfg, class, sclass, ssclass, key);
767 if (node != NULL)
769 __int_cfg_remove_node(cfg, node);
770 cfg_save_delayed(cfg);
771 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "triggered save delay: del: %s, %s", class, key);
773 /* g_mutex_unlock(cfg->lock);*/
777 void cfg_del_single_value(config_obj * cfg, const char *class, const char *key)
779 cfg_del_single_value_mm(cfg, class, NULL, NULL, key);
783 void cfg_remove_class(config_obj * cfg, const char *class)
785 config_node *node = NULL;
786 if (cfg == NULL || class == NULL)
787 return;
789 /* g_mutex_lock(cfg->lock);*/
790 node = cfg_get_class(cfg, class);
791 if (node)
793 __int_cfg_remove_node(cfg, node);
795 cfg_save_delayed(cfg);
796 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "triggered save delay: del: %s", class);
797 /* g_mutex_unlock(cfg->lock);*/
801 static void __int_cfg_set_single_value_as_string(config_obj * cfg, const char *class, const char *sclass,
802 const char *ssclass, const char *key, const char *value)
804 config_node *newnode = cfg_get_single_value(cfg, class, sclass, ssclass, key);
805 if (newnode == NULL)
807 config_node *node = cfg_get_class(cfg, class);
808 if (node == NULL)
810 node = cfg_add_class(cfg, NULL, class);
811 if (node == NULL)
812 return;
814 if (sclass)
816 config_node *nnode = cfg_get_class_multiple(cfg, node, sclass);
817 if (nnode == NULL)
819 nnode = cfg_add_class(cfg, node, sclass);
820 if (nnode == NULL)
821 return;
823 node = nnode;
825 if (ssclass)
827 config_node *nnode = cfg_get_class_multiple(cfg, node, ssclass);
828 if (nnode == NULL)
830 nnode = cfg_add_class(cfg, node, ssclass);
831 if (nnode == NULL)
832 return;
834 node = nnode;
836 newnode = cfg_new_node();
837 newnode->name = g_strdup(key);
838 cfg->total_size += sizeof(config_node) + strlen(key);
839 cfg_add_child(node, newnode);
841 } else if ((value == NULL && newnode->value == NULL) ||
842 (value != NULL && newnode->value != NULL && strlen(newnode->value) == strlen(value)
843 && !memcmp(newnode->value, value, strlen(newnode->value))))
845 /* Check if the content is the same, if it is, do nothing */
846 return;
848 newnode->type = TYPE_ITEM;
849 if (newnode->value)
851 cfg->total_size -= strlen(newnode->value);
852 cfg_free_string(newnode->value);
854 if (value)
856 newnode->value = g_strdup(value);
857 cfg->total_size += strlen(value);
858 } else
860 newnode->value = NULL;
862 cfg_save_delayed(cfg);
863 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "triggered save delay: set: %s,%s -> %s", class, key, value);
867 void cfg_set_single_value_as_string(config_obj * cfg, const char *class, const char *key, const char *value)
869 /* g_mutex_lock(cfg->lock);*/
870 __int_cfg_set_single_value_as_string(cfg, class, NULL, NULL, key, value);
871 /* g_mutex_unlock(cfg->lock);*/
875 /* multiple values */
877 static config_node *cfg_get_multiple_value(config_obj * cfg, const char *class, const char *key, const char *id)
879 config_node *node = cfg_get_single_value(cfg, class, NULL, NULL, key);
880 if (node == NULL)
882 return NULL;
884 if (node->type != TYPE_ITEM_MULTIPLE)
886 return NULL;
888 if (node->children == NULL)
890 return NULL;
892 /* first */
893 node = node->children;
894 while (node->prev != NULL)
895 node = node->prev;
896 /* get item */
897 for (; node != NULL; node = node->next)
899 if (!strcmp(node->name, id))
901 return node;
904 return NULL;
908 void cfg_del_multiple_value(config_obj * cfg, const char *class, const char *key, const char *id)
910 config_node *cur = NULL;
911 /* g_mutex_lock(cfg->lock);*/
912 cur = cfg_get_multiple_value(cfg, class, key, id);
913 if (cur != NULL)
915 __int_cfg_remove_node(cfg, cur);
916 cfg_save_delayed(cfg);
918 /* g_mutex_unlock(cfg->lock);*/
922 void cfg_set_multiple_value_as_string(config_obj * cfg, const char *class, const char *key, const char *id,
923 const char *value)
925 config_node *cur = NULL;
926 /* g_mutex_lock(cfg->lock);*/
927 cur = cfg_get_multiple_value(cfg, class, key, id);
928 if (cur != NULL)
930 if (strlen(cur->value) == strlen(value) && !memcmp(cur->value, value, strlen(cur->value)))
932 return;
934 if (cur->value)
936 cfg->total_size -= strlen(cur->value);
937 cfg_free_string(cur->value);
940 cur->value = g_strdup(value);
941 cfg->total_size += strlen(cur->value);
942 cfg_save_delayed(cfg);
943 } else
945 config_node *node = cfg_get_single_value(cfg, class, NULL, NULL, key);
946 if (node == NULL)
948 node = cfg_get_class(cfg, class);
949 if (node == NULL)
951 node = cfg_add_class(cfg, NULL, class);
953 cur = cfg_new_node();
954 cur->name = g_strdup(key);
955 cur->type = TYPE_ITEM_MULTIPLE;
956 cfg_add_child(node, cur);
957 cfg->total_size += sizeof(config_node) + strlen(key);
958 node = cur;
960 if (node->type != TYPE_ITEM_MULTIPLE)
961 return;
962 cur = cfg_new_node();
963 cur->type = TYPE_ITEM;
964 cur->name = g_strdup(id);
965 cur->value = g_strdup(value);
966 cfg->total_size += sizeof(config_node) + strlen(id) + strlen(value);;
967 cfg_add_child(node, cur);
968 cfg_save_delayed(cfg);
970 /* g_mutex_unlock(cfg->lock);*/
974 conf_mult_obj *cfg_get_multiple_as_string(config_obj * cfg, const char *class, const char *key)
976 conf_mult_obj *list = NULL;
977 config_node *cur = NULL;
978 /* g_mutex_lock(cfg->lock);*/
979 cur = cfg_get_single_value(cfg, class, NULL, NULL, key);
980 if (cur && cur->type == TYPE_ITEM_MULTIPLE && cur->children != NULL)
982 cur = cur->children;
983 /* get first */
984 while (cur->prev != NULL)
985 cur = cur->prev;
988 conf_mult_obj *temp = g_slice_new0(conf_mult_obj);
989 temp->value = g_strdup(cur->value);
990 temp->key = g_strdup(cur->name);
991 temp->next = list;
992 if (temp->next)
993 temp->next->prev = temp;
994 list = temp;
995 cur = cur->next;
996 } while (cur != NULL);
998 /* g_mutex_unlock(cfg->lock);*/
999 return list;
1003 void cfg_free_multiple(conf_mult_obj * data)
1005 conf_mult_obj *list = data;
1006 if (list == NULL)
1007 return;
1008 /* go to first */
1009 while (list->prev != NULL)
1011 list = list->prev;
1013 while (list != NULL)
1015 if (list->value)
1016 cfg_free_string(list->value);
1017 if (list->key)
1018 cfg_free_string(list->key);
1019 if (list->next != NULL)
1021 if (list->prev)
1022 g_slice_free(conf_mult_obj, list->prev);
1023 list = list->next;
1024 } else
1026 g_slice_free(conf_mult_obj, list->prev);
1027 g_slice_free(conf_mult_obj, list);
1028 list = NULL;
1034 conf_mult_obj *cfg_get_class_list(config_obj * data)
1036 conf_mult_obj *list = NULL;
1037 config_node *root = NULL;
1038 if (!data)
1039 return NULL;
1040 if (!data->root)
1041 return NULL;
1042 /* g_mutex_lock(data->lock);*/
1043 root = data->root;
1044 while (root->prev != NULL)
1045 root = root->prev;
1048 if (root->type == TYPE_CATEGORY)
1050 conf_mult_obj *temp = g_slice_new0(conf_mult_obj);
1051 temp->value = NULL;
1052 temp->key = g_strdup(root->name);
1053 temp->next = list;
1054 if (temp->next)
1055 temp->next->prev = temp;
1056 list = temp;
1058 root = root->next;
1059 } while (root != NULL);
1060 while (list->prev != NULL)
1061 list = list->prev;
1062 /* g_mutex_unlock(data->lock);*/
1064 return list;
1068 conf_mult_obj *cfg_get_key_list(config_obj * data, const char *class)
1070 conf_mult_obj *list = NULL;
1071 config_node *root = NULL;
1072 if (data == NULL)
1073 return NULL;
1074 if (data->root == NULL)
1075 return NULL;
1076 /* g_mutex_lock(data->lock);*/
1077 root = cfg_get_class(data, class);
1078 if (!root || !root->children)
1080 /* g_mutex_unlock(data->lock);*/
1081 return NULL;
1083 root = root->children;
1084 while (root->prev != NULL)
1085 root = root->prev;
1088 if (root->type == TYPE_ITEM)
1090 conf_mult_obj *temp = g_slice_new0(conf_mult_obj);
1091 temp->value = g_strdup(root->value);
1092 temp->key = g_strdup(root->name);
1093 temp->next = list;
1094 if (temp->next)
1095 temp->next->prev = temp;
1096 list = temp;
1098 root = root->next;
1099 } while (root != NULL);
1100 while (list && list->prev != NULL)
1101 list = list->prev;
1102 /* g_mutex_unlock(data->lock);*/
1103 return list;
1107 static void __int_cfg_do_special_cleanup(config_obj * cfg, config_node * node)
1109 config_node *item, *root = NULL;
1110 if (!cfg || !cfg->root)
1111 return;
1112 if (node == NULL)
1113 root = cfg->root;
1114 else
1115 root = node;
1116 if (!root)
1117 return;
1118 while (root)
1120 if (root->type == TYPE_CATEGORY)
1122 if (root->children)
1123 __int_cfg_do_special_cleanup(cfg, root->children);
1124 if (root->children == NULL)
1126 item = NULL;
1127 if (root->prev)
1128 item = root->prev;
1129 else if (root->next)
1130 item = root->next;
1131 __int_cfg_remove_node(cfg, root);
1132 root = item;
1133 } else
1134 root = root->next;
1135 } else if (root->type == TYPE_ITEM)
1137 if (root->value == NULL || root->value[0] == '\0' || strlen(root->value) == 0)
1139 config_node *inode = root;
1140 root = inode->prev;
1141 if (!root)
1142 root = inode->next;
1143 __int_cfg_remove_node(cfg, inode);
1144 if (!root)
1145 return;
1146 } else
1147 root = root->next;
1148 } else if (root)
1149 root = root->next;
1154 void cfg_do_special_cleanup(config_obj * cfg)
1156 if (!cfg || !cfg->root)
1157 return;
1159 /* g_mutex_lock(cfg->lock);*/
1160 __int_cfg_do_special_cleanup(cfg, NULL);
1161 cfg_save_delayed(cfg);
1162 /* g_mutex_unlock(cfg->lock);*/
1167 * Full api for use with metadata
1171 * String
1173 void cfg_set_single_value_as_string_mm(config_obj * cfg, const char *class, const char *sclass, const char *ssclass,
1174 const char *key, const char *value)
1176 /* g_mutex_lock(cfg->lock);*/
1177 __int_cfg_set_single_value_as_string(cfg, class, sclass, ssclass, key, value);
1178 /* g_mutex_unlock(cfg->lock);*/
1182 char *cfg_get_single_value_as_string_mm(config_obj * cfg, const char *class, const char *sclass, const char *ssclass,
1183 const char *key)
1185 char *retv = NULL;
1186 /* g_mutex_lock(cfg->lock);*/
1187 retv = __int_cfg_get_single_value_as_string(cfg, class, sclass, ssclass, key);
1188 /* g_mutex_unlock(cfg->lock);*/
1189 return retv;
1193 char *cfg_get_single_value_as_string_with_default_mm(config_obj * cfg, const char *class, const char *sclass,
1194 const char *ssclass, const char *key, const char *def)
1196 char *retv = NULL;
1197 /* g_mutex_lock(cfg->lock);*/
1198 retv = __int_cfg_get_single_value_as_string(cfg, class, sclass, ssclass, key);
1199 if (retv == NULL)
1201 __int_cfg_set_single_value_as_string(cfg, class, sclass, ssclass, key, def);
1202 retv = __int_cfg_get_single_value_as_string(cfg, class, sclass, ssclass, key);
1204 /* g_mutex_unlock(cfg->lock);*/
1205 return retv;
1210 * Int
1212 void cfg_set_single_value_as_int_mm(config_obj * cfg, const char *class, const char *sclass, const char *ssclass,
1213 const char *key, int value)
1215 gchar *temp = NULL;
1216 /* g_mutex_lock(cfg->lock);*/
1217 temp = g_strdup_printf("%i", value);
1218 __int_cfg_set_single_value_as_string(cfg, class, sclass, ssclass, key, temp);
1219 cfg_free_string(temp);
1220 /* g_mutex_unlock(cfg->lock);*/
1224 int cfg_get_single_value_as_int_with_default_mm(config_obj * cfg, const char *class, const char *sclass,
1225 const char *ssclass, const char *key, int def)
1227 int retv = CFG_INT_NOT_DEFINED;
1228 /* g_mutex_lock(cfg->lock); */
1229 retv = __int_cfg_get_single_value_as_int_mm(cfg, class, sclass, ssclass, key);
1230 if (retv == CFG_INT_NOT_DEFINED)
1232 __int_cfg_set_single_value_as_int(cfg, class, sclass, ssclass, key, def);
1233 retv = __int_cfg_get_single_value_as_int_mm(cfg, class, sclass, ssclass, key);
1235 /* g_mutex_unlock(cfg->lock); */
1236 return retv;
1240 static void cfg_save_delayed(config_obj * cfg)
1242 if (cfg->save_timeout)
1244 g_source_remove(cfg->save_timeout);
1245 cfg->save_timeout = 0;
1247 cfg->save_timeout = g_timeout_add_seconds(5, (GSourceFunc) cfg_save_real, cfg);