source: set.c @ 612b49d

Last change on this file since 612b49d 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
RevLine 
[5ebff60]1/********************************************************************\
[b7d3cc34]2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[03886fc]4  * Copyright 2002-2013 Wilmer van der Gaast and others                *
[b7d3cc34]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;
[6f10697]22  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
[b7d3cc34]24*/
[03886fc]25
[b7d3cc34]26#define BITLBEE_CORE
27#include "bitlbee.h"
28
[7125cb3]29/* Used to use NULL for this, but NULL is actually a "valid" value. */
30char *SET_INVALID = "nee";
31
[5ebff60]32set_t *set_add(set_t **head, const char *key, const char *def, set_eval eval, void *data)
[b7d3cc34]33{
[5ebff60]34        set_t *s = set_find(head, key);
35
[5c9512f]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. */
[5ebff60]38        if (!s) {
39                if ((s = *head)) {
[03886fc]40                        /* Sorted insertion. Special-case insertion at the start. */
[5ebff60]41                        if (strcmp(key, s->key) < 0) {
42                                s = g_new0(set_t, 1);
[03886fc]43                                s->next = *head;
44                                *head = s;
[5ebff60]45                        } else {
46                                while (s->next && strcmp(key, s->next->key) > 0) {
[03886fc]47                                        s = s->next;
[5ebff60]48                                }
[03886fc]49                                set_t *last_next = s->next;
[5ebff60]50                                s->next = g_new0(set_t, 1);
[03886fc]51                                s = s->next;
52                                s->next = last_next;
53                        }
[5ebff60]54                } else {
55                        s = *head = g_new0(set_t, 1);
[b7d3cc34]56                }
[5ebff60]57                s->key = g_strdup(key);
[b7d3cc34]58        }
[5ebff60]59
60        if (s->def) {
61                g_free(s->def);
[b7d3cc34]62                s->def = NULL;
63        }
[5ebff60]64        if (def) {
65                s->def = g_strdup(def);
66        }
67
[5c9512f]68        s->eval = eval;
69        s->data = data;
[5ebff60]70
[5c9512f]71        return s;
[b7d3cc34]72}
73
[5ebff60]74set_t *set_find(set_t **head, const char *key)
[b7d3cc34]75{
[5c9512f]76        set_t *s = *head;
[5ebff60]77
78        while (s) {
79                if (g_strcasecmp(s->key, key) == 0 ||
80                    (s->old_key && g_strcasecmp(s->old_key, key) == 0)) {
[b7d3cc34]81                        break;
[5ebff60]82                }
[b7d3cc34]83                s = s->next;
84        }
[5ebff60]85
[5c9512f]86        return s;
[b7d3cc34]87}
88
[5ebff60]89char *set_getstr(set_t **head, const char *key)
[b7d3cc34]90{
[5ebff60]91        set_t *s = set_find(head, key);
92
93        if (!s || (!s->value && !s->def)) {
[5c9512f]94                return NULL;
[5ebff60]95        }
96
97        return set_value(s);
[b7d3cc34]98}
99
[5ebff60]100int set_getint(set_t **head, const char *key)
[b7d3cc34]101{
[5ebff60]102        char *s = set_getstr(head, key);
[b7d3cc34]103        int i = 0;
[5ebff60]104
105        if (!s) {
[5c9512f]106                return 0;
[5ebff60]107        }
108
109        if (sscanf(s, "%d", &i) != 1) {
[5c9512f]110                return 0;
[5ebff60]111        }
112
[5c9512f]113        return i;
[b7d3cc34]114}
115
[5ebff60]116int set_getbool(set_t **head, const char *key)
[5100caa]117{
[5ebff60]118        char *s = set_getstr(head, key);
119
120        if (!s) {
[5100caa]121                return 0;
[5ebff60]122        }
123
124        return bool2int(s);
[5100caa]125}
126
[5ebff60]127int set_isvisible(set_t *set)
[06b5893]128{
129        /* the default value is not stored in value, only in def */
[5ebff60]130        return !((set->flags & SET_HIDDEN) ||
131                 ((set->flags & SET_HIDDEN_DEFAULT) &&
132                  (set->value == NULL)));
[06b5893]133}
134
[5ebff60]135int set_setstr(set_t **head, const char *key, char *value)
[b7d3cc34]136{
[5ebff60]137        set_t *s = set_find(head, key);
[b7d3cc34]138        char *nv = value;
[5ebff60]139
140        if (!s) {
[7125cb3]141                /*
142                Used to do this, but it never really made sense.
[5c9512f]143                s = set_add( head, key, NULL, NULL, NULL );
[7125cb3]144                */
145                return 0;
[5ebff60]146        }
147
148        if (value == NULL && (s->flags & SET_NULL_OK) == 0) {
[7125cb3]149                return 0;
[5ebff60]150        }
151
[7125cb3]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. */
[5ebff60]155        if (s->eval && ((nv = s->eval(s, value)) == SET_INVALID ||
156                        ((s->flags & SET_NULL_OK) == 0 && nv == NULL))) {
[5c9512f]157                return 0;
[5ebff60]158        }
159
160        if (s->value) {
161                g_free(s->value);
[b7d3cc34]162                s->value = NULL;
163        }
[5ebff60]164
[5c9512f]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. */
[90a45b8]167        if (!s->def || (g_strcmp0(nv, s->def) != 0)) {
[5ebff60]168                s->value = g_strdup(nv);
169        }
170
171        if (nv != value) {
172                g_free(nv);
173        }
174
[5c9512f]175        return 1;
[b7d3cc34]176}
177
[5ebff60]178int set_setint(set_t **head, const char *key, int value)
[b7d3cc34]179{
[5ebff60]180        char *s = g_strdup_printf("%d", value);
181        int retval = set_setstr(head, key, s);
182
183        g_free(s);
[434ffa2]184        return retval;
[b7d3cc34]185}
186
[5ebff60]187void set_del(set_t **head, const char *key)
[b7d3cc34]188{
[5c9512f]189        set_t *s = *head, *t = NULL;
[5ebff60]190
191        while (s) {
192                if (g_strcasecmp(s->key, key) == 0) {
[b7d3cc34]193                        break;
[5ebff60]194                }
195                s = (t = s)->next;
[b7d3cc34]196        }
[5ebff60]197        if (s) {
198                if (t) {
[dd89a55]199                        t->next = s->next;
[5ebff60]200                } else {
[5c9512f]201                        *head = s->next;
[5ebff60]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);
[b7d3cc34]209        }
210}
211
[5ebff60]212int set_reset(set_t **head, const char *key)
[cd428e4]213{
214        set_t *s;
[5ebff60]215
216        s = set_find(head, key);
217        if (s) {
218                return set_setstr(head, key, s->def);
219        }
220
[f3579fd]221        return 0;
[cd428e4]222}
223
[5ebff60]224char *set_eval_int(set_t *set, char *value)
[b7d3cc34]225{
[6237ded]226        char *s = value;
[5ebff60]227
[5eec897]228        /* Allow a minus at the first position. */
[5ebff60]229        if (*s == '-') {
230                s++;
231        }
232
233        for (; *s; s++) {
234                if (!g_ascii_isdigit(*s)) {
[7125cb3]235                        return SET_INVALID;
[5ebff60]236                }
237        }
238
[5c9512f]239        return value;
[b7d3cc34]240}
241
[5ebff60]242char *set_eval_bool(set_t *set, char *value)
[b7d3cc34]243{
[5ebff60]244        return is_bool(value) ? value : SET_INVALID;
[b7d3cc34]245}
246
[5ebff60]247char *set_eval_list(set_t *set, char *value)
[56244c0]248{
249        GSList *options = set->eval_data, *opt;
[5ebff60]250
251        for (opt = options; opt; opt = opt->next) {
252                if (strcmp(value, opt->data) == 0) {
[56244c0]253                        return value;
[5ebff60]254                }
255        }
256
[56244c0]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. */
[5ebff60]260
[56244c0]261        return NULL;
262}
263
[5ebff60]264char *set_eval_to_char(set_t *set, char *value)
[b7d3cc34]265{
[5ebff60]266        char *s = g_new(char, 3);
267
268        if (*value == ' ') {
269                strcpy(s, " ");
270        } else {
271                sprintf(s, "%c ", *value);
272        }
273
[5c9512f]274        return s;
[b7d3cc34]275}
276
[5ebff60]277char *set_eval_oauth(set_t *set, char *value)
[b7d3cc34]278{
[ce199b7]279        account_t *acc = set->data;
[5ebff60]280
281        if (bool2int(value) && strcmp(acc->pass, PASSWORD_PENDING) == 0) {
[ce199b7]282                *acc->pass = '\0';
[5ebff60]283        }
284
285        return set_eval_bool(set, value);
[b7d3cc34]286}
Note: See TracBrowser for help on using the repository browser.