Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / lib-config / get.c
1 /*
2  get.c : irssi configuration - get settings from memory
3
4     Copyright (C) 1999 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "module.h"
22
23 CONFIG_NODE *config_node_find(CONFIG_NODE *node, const char *key)
24 {
25         GSList *tmp;
26
27         g_return_val_if_fail(node != NULL, NULL);
28         g_return_val_if_fail(key != NULL, NULL);
29         g_return_val_if_fail(is_node_list(node), NULL);
30
31         for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
32                 CONFIG_NODE *node = tmp->data;
33
34                 if (node->key != NULL && g_strcasecmp(node->key, key) == 0)
35                         return node;
36         }
37
38         return NULL;
39 }
40
41 CONFIG_NODE *config_node_section(CONFIG_NODE *parent, const char *key, int new_type)
42 {
43         return config_node_section_index(parent, key, -1, new_type);
44 }
45
46 CONFIG_NODE *config_node_section_index(CONFIG_NODE *parent, const char *key,
47                                        int index, int new_type)
48 {
49         CONFIG_NODE *node;
50         int nindex;
51
52         g_return_val_if_fail(parent != NULL, NULL);
53         g_return_val_if_fail(is_node_list(parent), NULL);
54
55         node = key == NULL ? NULL : config_node_find(parent, key);
56         if (node != NULL) {
57                 g_return_val_if_fail(new_type == -1 || new_type == node->type, NULL);
58                 nindex = g_slist_index(parent->value, node);
59                 if (index >= 0 && nindex != index &&
60                     nindex <= g_slist_length(parent->value)) {
61                         /* move it to wanted position */
62                         parent->value = g_slist_remove(parent->value, node);
63                         parent->value = g_slist_insert(parent->value, node, index);
64                 }
65                 return node;
66         }
67
68         if (new_type == -1)
69                 return NULL;
70
71         node = g_new0(CONFIG_NODE, 1);
72         parent->value = index < 0 ? g_slist_append(parent->value, node) :
73                 g_slist_insert(parent->value, node, index);
74
75         node->type = new_type;
76         node->key = key == NULL ? NULL : g_strdup(key);
77
78         return node;
79 }
80
81 CONFIG_NODE *config_node_traverse(CONFIG_REC *rec, const char *section, int create)
82 {
83         CONFIG_NODE *node;
84         char **list, **tmp, *str;
85         int is_list, new_type;
86
87         g_return_val_if_fail(rec != NULL, NULL);
88
89         if (section == NULL || *section == '\0')
90                 return rec->mainnode;
91
92         /* check if it already exists in cache */
93         node = g_hash_table_lookup(rec->cache, section);
94         if (node != NULL) return node;
95
96         new_type = -1;
97
98         node = rec->mainnode;
99         list = g_strsplit(section, "/", -1);
100         for (tmp = list; *tmp != NULL; tmp++) {
101                 is_list = **tmp == '(';
102                 if (create) new_type = is_list ? NODE_TYPE_LIST : NODE_TYPE_BLOCK;
103
104                 node = config_node_section(node, *tmp + is_list, new_type);
105                 if (node == NULL) {
106                         g_strfreev(list);
107                         return NULL;
108                 }
109         }
110         g_strfreev(list);
111
112         /* save to cache */
113         str = g_strdup(section);
114         g_hash_table_insert(rec->cache, str, node);
115         g_hash_table_insert(rec->cache_nodes, node, str);
116         return node;
117 }
118
119 char *config_get_str(CONFIG_REC *rec, const char *section, const char *key, const char *def)
120 {
121         CONFIG_NODE *parent, *node;
122         char *path;
123
124         g_return_val_if_fail(rec != NULL, (char *) def);
125         g_return_val_if_fail(key != NULL, (char *) def);
126
127         /* check if it already exists in cache */
128         path = g_strconcat(section == NULL ? "" : section, "/", key, NULL);
129         node = g_hash_table_lookup(rec->cache, path);
130
131         if (node != NULL)
132                 g_free(path);
133         else {
134                 parent = config_node_traverse(rec, section, FALSE);
135                 node = parent == NULL ? NULL :
136                         config_node_find(parent, key);
137
138                 /* save to cache */
139                 if (node == NULL)
140                         g_free(path);
141                 else {
142                         g_hash_table_insert(rec->cache, path, node);
143                         g_hash_table_insert(rec->cache_nodes, node, path);
144                 }
145         }
146
147         return (node == NULL || !has_node_value(node)) ? (char *) def : node->value;
148 }
149
150 int config_get_int(CONFIG_REC *rec, const char *section, const char *key, int def)
151 {
152         char *str;
153
154         str = config_get_str(rec, section, key, NULL);
155         if (str == NULL) return def;
156
157         return atoi(str);
158 }
159
160 int config_get_bool(CONFIG_REC *rec, const char *section, const char *key, int def)
161 {
162         char *str;
163
164         str = config_get_str(rec, section, key, NULL);
165         if (str == NULL) return def;
166
167         return i_toupper(*str) == 'T' || i_toupper(*str) == 'Y';
168 }
169
170 char *config_node_get_str(CONFIG_NODE *parent, const char *key, const char *def)
171 {
172         CONFIG_NODE *node;
173
174         if (parent == NULL) return (char *) def;
175
176         node = config_node_find(parent, key);
177         return (char *) ((node != NULL && has_node_value(node)) ?
178                          node->value : def);
179 }
180
181 int config_node_get_int(CONFIG_NODE *parent, const char *key, int def)
182 {
183         char *str;
184
185         str = config_node_get_str(parent, key, NULL);
186         if (str == NULL) return def;
187
188         return atoi(str);
189 }
190
191 int config_node_get_bool(CONFIG_NODE *parent, const char *key, int def)
192 {
193         char *str;
194
195         str = config_node_get_str(parent, key, NULL);
196         if (str == NULL) return def;
197
198         return i_toupper(*str) == 'T' || i_toupper(*str) == 'Y' ||
199                 (i_toupper(*str) == 'O' && i_toupper(str[1]) == 'N');
200 }
201
202 char **config_node_get_list(CONFIG_NODE *node)
203 {
204         GString *values;
205         GSList *tmp;
206         char **ret;
207
208         g_return_val_if_fail(node != NULL, NULL);
209         g_return_val_if_fail(is_node_list(node), NULL);
210
211         /* put values to string */
212         values = g_string_new(NULL);
213         for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
214                 node = tmp->data;
215
216                 if (node->type == NODE_TYPE_VALUE)
217                         g_string_append_printf(values, "%s ", (char *) node->value);
218         }
219
220         /* split the values to **str array */
221         if (values->len == 0)
222                 ret = NULL;
223         else {
224                 g_string_truncate(values, values->len-1);
225                 ret = g_strsplit(values->str, " ", -1);
226         }
227
228         g_string_free(values, TRUE);
229         return ret;
230 }
231
232 CONFIG_NODE *config_node_nth(CONFIG_NODE *node, int index)
233 {
234         GSList *tmp;
235
236         g_return_val_if_fail(node != NULL, NULL);
237         g_return_val_if_fail(is_node_list(node), NULL);
238
239         for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
240                 CONFIG_NODE *node = tmp->data;
241
242                 if (node->type != NODE_TYPE_COMMENT) {
243                         if (index == 0)
244                                 return node;
245                         index--;
246                 }
247         }
248
249         return NULL;
250 }
251
252 int config_node_index(CONFIG_NODE *parent, const char *key)
253 {
254         CONFIG_NODE *node;
255         GSList *tmp;
256         int index;
257
258         g_return_val_if_fail(parent != NULL, -1);
259         g_return_val_if_fail(key != NULL, -1);
260
261         node = config_node_find(parent, key);
262         if (node == NULL)
263                 return -1;
264
265         index = 0;
266         for (tmp = parent->value; tmp != NULL; tmp = tmp->next) {
267                 CONFIG_NODE *tmpnode = tmp->data;
268
269                 if (tmpnode == node)
270                         return index;
271
272                 if (tmpnode->type != NODE_TYPE_COMMENT)
273                         index++;
274         }
275
276         return -1;
277 }
278
279 GSList *config_node_first(GSList *list)
280 {
281         while (list != NULL) {
282                 CONFIG_NODE *node = list->data;
283
284                 if (node->type != NODE_TYPE_COMMENT)
285                         break;
286                 list = list->next;
287         }
288         return list;
289 }
290
291 GSList *config_node_next(GSList *list)
292 {
293         list = list->next;
294         return config_node_first(list);
295 }