source: set.c @ f8d2cff

Last change on this file since f8d2cff was 90a45b8, checked in by dequis <dx@…>, at 2016-12-26T22:38:32Z

Fix some clang static analyzer warnings

Nothing interesting.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2013 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Some stuff to register, handle and save user preferences             */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28
29/* Used to use NULL for this, but NULL is actually a "valid" value. */
30char *SET_INVALID = "nee";
31
32set_t *set_add(set_t **head, const char *key, const char *def, set_eval eval, void *data)
33{
34        set_t *s = set_find(head, key);
35
36        /* Possibly the setting already exists. If it doesn't exist yet,
37           we create it. If it does, we'll just change the default. */
38        if (!s) {
39                if ((s = *head)) {
40                        /* Sorted insertion. Special-case insertion at the start. */
41                        if (strcmp(key, s->key) < 0) {
42                                s = g_new0(set_t, 1);
43                                s->next = *head;
44                                *head = s;
45                        } else {
46                                while (s->next && strcmp(key, s->next->key) > 0) {
47                                        s = s->next;
48                                }
49                                set_t *last_next = s->next;
50                                s->next = g_new0(set_t, 1);
51                                s = s->next;
52                                s->next = last_next;
53                        }
54                } else {
55                        s = *head = g_new0(set_t, 1);
56                }
57                s->key = g_strdup(key);
58        }
59
60        if (s->def) {
61                g_free(s->def);
62                s->def = NULL;
63        }
64        if (def) {
65                s->def = g_strdup(def);
66        }
67
68        s->eval = eval;
69        s->data = data;
70
71        return s;
72}
73
74set_t *set_find(set_t **head, const char *key)
75{
76        set_t *s = *head;
77
78        while (s) {
79                if (g_strcasecmp(s->key, key) == 0 ||
80                    (s->old_key && g_strcasecmp(s->old_key, key) == 0)) {
81                        break;
82                }
83                s = s->next;
84        }
85
86        return s;
87}
88
89char *set_getstr(set_t **head, const char *key)
90{
91        set_t *s = set_find(head, key);
92
93        if (!s || (!s->value && !s->def)) {
94                return NULL;
95        }
96
97        return set_value(s);
98}
99
100int set_getint(set_t **head, const char *key)
101{
102        char *s = set_getstr(head, key);
103        int i = 0;
104
105        if (!s) {
106                return 0;
107        }
108
109        if (sscanf(s, "%d", &i) != 1) {
110                return 0;
111        }
112
113        return i;
114}
115
116int set_getbool(set_t **head, const char *key)
117{
118        char *s = set_getstr(head, key);
119
120        if (!s) {
121                return 0;
122        }
123
124        return bool2int(s);
125}
126
127int set_isvisible(set_t *set)
128{
129        /* the default value is not stored in value, only in def */
130        return !((set->flags & SET_HIDDEN) ||
131                 ((set->flags & SET_HIDDEN_DEFAULT) &&
132                  (set->value == NULL)));
133}
134
135int set_setstr(set_t **head, const char *key, char *value)
136{
137        set_t *s = set_find(head, key);
138        char *nv = value;
139
140        if (!s) {
141                /*
142                Used to do this, but it never really made sense.
143                s = set_add( head, key, NULL, NULL, NULL );
144                */
145                return 0;
146        }
147
148        if (value == NULL && (s->flags & SET_NULL_OK) == 0) {
149                return 0;
150        }
151
152        /* Call the evaluator. For invalid values, evaluators should now
153           return SET_INVALID, but previously this was NULL. Try to handle
154           that too if NULL is not an allowed value for this setting. */
155        if (s->eval && ((nv = s->eval(s, value)) == SET_INVALID ||
156                        ((s->flags & SET_NULL_OK) == 0 && nv == NULL))) {
157                return 0;
158        }
159
160        if (s->value) {
161                g_free(s->value);
162                s->value = NULL;
163        }
164
165        /* If there's a default setting and it's equal to what we're trying to
166           set, stick with s->value = NULL. Otherwise, remember the setting. */
167        if (!s->def || (g_strcmp0(nv, s->def) != 0)) {
168                s->value = g_strdup(nv);
169        }
170
171        if (nv != value) {
172                g_free(nv);
173        }
174
175        return 1;
176}
177
178int set_setint(set_t **head, const char *key, int value)
179{
180        char *s = g_strdup_printf("%d", value);
181        int retval = set_setstr(head, key, s);
182
183        g_free(s);
184        return retval;
185}
186
187void set_del(set_t **head, const char *key)
188{
189        set_t *s = *head, *t = NULL;
190
191        while (s) {
192                if (g_strcasecmp(s->key, key) == 0) {
193                        break;
194                }
195                s = (t = s)->next;
196        }
197        if (s) {
198                if (t) {
199                        t->next = s->next;
200                } else {
201                        *head = s->next;
202                }
203
204                g_free(s->key);
205                g_free(s->old_key);
206                g_free(s->value);
207                g_free(s->def);
208                g_free(s);
209        }
210}
211
212int set_reset(set_t **head, const char *key)
213{
214        set_t *s;
215
216        s = set_find(head, key);
217        if (s) {
218                return set_setstr(head, key, s->def);
219        }
220
221        return 0;
222}
223
224char *set_eval_int(set_t *set, char *value)
225{
226        char *s = value;
227
228        /* Allow a minus at the first position. */
229        if (*s == '-') {
230                s++;
231        }
232
233        for (; *s; s++) {
234                if (!g_ascii_isdigit(*s)) {
235                        return SET_INVALID;
236                }
237        }
238
239        return value;
240}
241
242char *set_eval_bool(set_t *set, char *value)
243{
244        return is_bool(value) ? value : SET_INVALID;
245}
246
247char *set_eval_list(set_t *set, char *value)
248{
249        GSList *options = set->eval_data, *opt;
250
251        for (opt = options; opt; opt = opt->next) {
252                if (strcmp(value, opt->data) == 0) {
253                        return value;
254                }
255        }
256
257        /* TODO: It'd be nice to show the user a list of allowed values,
258                 but we don't have enough context here to do that. May
259                 want to fix that. */
260
261        return NULL;
262}
263
264char *set_eval_to_char(set_t *set, char *value)
265{
266        char *s = g_new(char, 3);
267
268        if (*value == ' ') {
269                strcpy(s, " ");
270        } else {
271                sprintf(s, "%c ", *value);
272        }
273
274        return s;
275}
276
277char *set_eval_oauth(set_t *set, char *value)
278{
279        account_t *acc = set->data;
280
281        if (bool2int(value) && strcmp(acc->pass, PASSWORD_PENDING) == 0) {
282                *acc->pass = '\0';
283        }
284
285        return set_eval_bool(set, value);
286}
Note: See TracBrowser for help on using the repository browser.