imported irssi.
[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
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 /* find the section from node - if not found create it unless new_type is -1.
42    you can also specify in new_type if it's NODE_TYPE_LIST or NODE_TYPE_BLOCK */
43 CONFIG_NODE *config_node_section(CONFIG_NODE *parent, const char *key, int new_type)
44 {
45         CONFIG_NODE *node;
46
47         g_return_val_if_fail(parent != NULL, NULL);
48         g_return_val_if_fail(is_node_list(parent), NULL);
49
50         node = key == NULL ? NULL : config_node_find(parent, key);
51         if (node != NULL) {
52                 g_return_val_if_fail(new_type == -1 || new_type == node->type, NULL);
53                 return node;
54         }
55
56         if (new_type == -1)
57                 return NULL;
58
59         node = g_new0(CONFIG_NODE, 1);
60         parent->value = g_slist_append(parent->value, node);
61
62         node->type = new_type;
63         node->key = key == NULL ? NULL : g_strdup(key);
64
65         return node;
66 }
67
68 /* find the section with the whole path.
69    create the path if necessary `create' is TRUE. */
70 CONFIG_NODE *config_node_traverse(CONFIG_REC *rec, const char *section, int create)
71 {
72         CONFIG_NODE *node;
73         char **list, **tmp, *str;
74         int is_list, new_type;
75
76         g_return_val_if_fail(rec != NULL, NULL);
77
78         if (section == NULL || *section == '\0')
79                 return rec->mainnode;
80
81         /* check if it already exists in cache */
82         node = g_hash_table_lookup(rec->cache, section);
83         if (node != NULL) return node;
84
85         new_type = -1;
86
87         node = rec->mainnode;
88         list = g_strsplit(section, "/", -1);
89         for (tmp = list; *tmp != NULL; tmp++) {
90                 is_list = **tmp == '(';
91                 if (create) new_type = is_list ? NODE_TYPE_LIST : NODE_TYPE_BLOCK;
92
93                 node = config_node_section(node, *tmp + is_list, new_type);
94                 if (node == NULL) {
95                         g_strfreev(list);
96                         return NULL;
97                 }
98         }
99         g_strfreev(list);
100
101         /* save to cache */
102         str = g_strdup(section);
103         g_hash_table_insert(rec->cache, str, node);
104         g_hash_table_insert(rec->cache_nodes, node, str);
105         return node;
106 }
107
108 char *config_get_str(CONFIG_REC *rec, const char *section, const char *key, const char *def)
109 {
110         CONFIG_NODE *parent, *node;
111         char *path;
112
113         g_return_val_if_fail(rec != NULL, (char *) def);
114         g_return_val_if_fail(key != NULL, (char *) def);
115
116         /* check if it already exists in cache */
117         path = g_strconcat(section == NULL ? "" : section, "/", key, NULL);
118         node = g_hash_table_lookup(rec->cache, path);
119
120         if (node != NULL)
121                 g_free(path);
122         else {
123                 parent = config_node_traverse(rec, section, FALSE);
124                 node = parent == NULL ? NULL :
125                         config_node_find(parent, key);
126
127                 /* save to cache */
128                 if (node == NULL)
129                         g_free(path);
130                 else {
131                         g_hash_table_insert(rec->cache, path, node);
132                         g_hash_table_insert(rec->cache_nodes, node, path);
133                 }
134         }
135
136         return (node == NULL || !has_node_value(node)) ? (char *) def : node->value;
137 }
138
139 int config_get_int(CONFIG_REC *rec, const char *section, const char *key, int def)
140 {
141         char *str;
142
143         str = config_get_str(rec, section, key, NULL);
144         if (str == NULL) return def;
145
146         return atoi(str);
147 }
148
149 int config_get_bool(CONFIG_REC *rec, const char *section, const char *key, int def)
150 {
151         char *str;
152
153         str = config_get_str(rec, section, key, NULL);
154         if (str == NULL) return def;
155
156         return toupper(*str) == 'T' || toupper(*str) == 'Y';
157 }
158
159 /* Return value of key `value_key' from list item where `key' is `value' */
160 const char *config_list_find(CONFIG_REC *rec, const char *section, const char *key, const char *value, const char *value_key)
161 {
162         CONFIG_NODE *node;
163
164         node = config_list_find_node(rec, section, key, value, value_key);
165         return node != NULL && node->type == NODE_TYPE_KEY ?
166                 node->value : NULL;
167 }
168
169 /* Like config_list_find(), but return node instead of it's value */
170 CONFIG_NODE *config_list_find_node(CONFIG_REC *rec, const char *section, const char *key, const char *value, const char *value_key)
171 {
172         CONFIG_NODE *node, *keynode;
173         GSList *tmp;
174
175         g_return_val_if_fail(rec != NULL, NULL);
176         g_return_val_if_fail(key != NULL, NULL);
177         g_return_val_if_fail(value_key != NULL, NULL);
178
179         node = config_node_traverse(rec, section, FALSE);
180         if (node == NULL || !is_node_list(node)) return NULL;
181
182         for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
183                 node = tmp->data;
184
185                 if (node->type != NODE_TYPE_BLOCK)
186                         continue;
187
188                 /* key matches value? */
189                 keynode = config_node_find(node, key);
190                 if (keynode == NULL || keynode->type != NODE_TYPE_KEY ||
191                     g_strcasecmp(keynode->value, value) != 0) continue;
192
193                 return config_node_find(node, value_key);
194         }
195
196         return NULL;
197 }
198
199 char *config_node_get_str(CONFIG_NODE *parent, const char *key, const char *def)
200 {
201         CONFIG_NODE *node;
202
203         if (parent == NULL) return (char *) def;
204
205         node = config_node_find(parent, key);
206         return (char *) ((node != NULL && has_node_value(node)) ?
207                          node->value : def);
208 }
209
210 int config_node_get_int(CONFIG_NODE *parent, const char *key, int def)
211 {
212         char *str;
213
214         str = config_node_get_str(parent, key, NULL);
215         if (str == NULL) return def;
216
217         return atoi(str);
218 }
219
220 int config_node_get_bool(CONFIG_NODE *parent, const char *key, int def)
221 {
222         char *str;
223
224         str = config_node_get_str(parent, key, NULL);
225         if (str == NULL) return def;
226
227         return toupper(*str) == 'T' || toupper(*str) == 'Y' ||
228                 (toupper(*str) == 'O' && toupper(str[1]) == 'N');
229 }
230
231 /* Get the value of keys `key' and `key_value' and put them to
232    `ret_key' and `ret_value'. Returns -1 if not found. */
233 int config_node_get_keyvalue(CONFIG_NODE *node, const char *key, const char *value_key, char **ret_key, char **ret_value)
234 {
235         CONFIG_NODE *keynode, *valuenode;
236         GSList *tmp;
237
238         g_return_val_if_fail(node != NULL, -1);
239         g_return_val_if_fail(key != NULL, -1);
240         g_return_val_if_fail(value_key != NULL, -1);
241         g_return_val_if_fail(ret_key != NULL, -1);
242         g_return_val_if_fail(ret_value != NULL, -1);
243
244         for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
245                 node = tmp->data;
246
247                 if (node->type != NODE_TYPE_BLOCK)
248                         continue;
249
250                 keynode = config_node_find(node, key);
251                 if (keynode == NULL || keynode->type != NODE_TYPE_KEY)
252                         continue;
253
254                 valuenode = config_node_find(node, value_key);
255
256                 *ret_key = keynode->key;
257                 *ret_value = valuenode != NULL && valuenode->type == NODE_TYPE_KEY ?
258                         valuenode->value : NULL;
259                 return 0;
260         }
261
262         return -1;
263 }
264
265 /* Return all values from from the list `node' in a g_strsplit() array */
266 char **config_node_get_list(CONFIG_NODE *node)
267 {
268         GString *values;
269         GSList *tmp;
270         char **ret;
271
272         g_return_val_if_fail(node != NULL, NULL);
273         g_return_val_if_fail(is_node_list(node), NULL);
274
275         /* put values to string */
276         values = g_string_new(NULL);
277         for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
278                 node = tmp->data;
279
280                 if (node->type == NODE_TYPE_VALUE)
281                         g_string_sprintfa(values, "%s ", (char *) node->value);
282         }
283
284         /* split the values to **str array */
285         if (values->len == 0)
286                 ret = NULL;
287         else {
288                 g_string_truncate(values, values->len-1);
289                 ret = g_strsplit(values->str, " ", -1);
290         }
291
292         g_string_free(values, TRUE);
293         return ret;
294 }
295
296 /* Returns n'th node from list. */
297 CONFIG_NODE *config_node_index(CONFIG_NODE *node, int index)
298 {
299         GSList *tmp;
300
301         g_return_val_if_fail(node != NULL, NULL);
302         g_return_val_if_fail(is_node_list(node), NULL);
303
304         for (tmp = node->value; tmp != NULL; tmp = tmp->next, index--) {
305                 if (index == 0)
306                         return tmp->data;
307         }
308
309         return NULL;
310 }