source: set.c @ ba3506e

Last change on this file since ba3506e was 03886fc, checked in by Wilmer van der Gaast <wilmer@…>, at 2013-02-21T18:37:06Z

Keep settings lists sorted. It's already sorted somewhat, but in unclearly
divided fragments. The lists are getting long enough in places that having
sections would help. That's more work, just sorting is a good start.

  • Property mode set to 100644
File size: 5.9 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., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  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        {
40                if( ( s = *head ) )
41                {
42                        /* Sorted insertion. Special-case insertion at the start. */
43                        if( strcmp( key, s->key ) < 0 )
44                        {
45                                s = g_new0( set_t, 1 );
46                                s->next = *head;
47                                *head = s;
48                        }
49                        else
50                        {
51                                while( s->next && strcmp( key, s->next->key ) > 0 )
52                                        s = s->next;
53                                set_t *last_next = s->next;
54                                s->next = g_new0( set_t, 1 );
55                                s = s->next;
56                                s->next = last_next;
57                        }
58                }
59                else
60                {
61                        s = *head = g_new0( set_t, 1 );
62                }
63                s->key = g_strdup( key );
64        }
65       
66        if( s->def )
67        {
68                g_free( s->def );
69                s->def = NULL;
70        }
71        if( def ) s->def = g_strdup( def );
72       
73        s->eval = eval;
74        s->data = data;
75       
76        return s;
77}
78
79set_t *set_find( set_t **head, const char *key )
80{
81        set_t *s = *head;
82       
83        while( s )
84        {
85                if( g_strcasecmp( s->key, key ) == 0 ||
86                    ( s->old_key && g_strcasecmp( s->old_key, key ) == 0 ) )
87                        break;
88                s = s->next;
89        }
90       
91        return s;
92}
93
94char *set_getstr( set_t **head, const char *key )
95{
96        set_t *s = set_find( head, key );
97       
98        if( !s || ( !s->value && !s->def ) )
99                return NULL;
100       
101        return set_value( s );
102}
103
104int set_getint( set_t **head, const char *key )
105{
106        char *s = set_getstr( head, key );
107        int i = 0;
108       
109        if( !s )
110                return 0;
111       
112        if( sscanf( s, "%d", &i ) != 1 )
113                return 0;
114       
115        return i;
116}
117
118int set_getbool( set_t **head, const char *key )
119{
120        char *s = set_getstr( head, key );
121       
122        if( !s )
123                return 0;
124       
125        return bool2int( s );
126}
127
128int set_isvisible( set_t *set )
129{
130        /* the default value is not stored in value, only in def */
131        return !( ( set->flags & SET_HIDDEN ) ||
132                  ( ( set->flags & SET_HIDDEN_DEFAULT ) &&
133                    ( set->value == NULL ) ) );
134}
135
136int set_setstr( set_t **head, const char *key, char *value )
137{
138        set_t *s = set_find( head, key );
139        char *nv = value;
140       
141        if( !s )
142                /*
143                Used to do this, but it never really made sense.
144                s = set_add( head, key, NULL, NULL, NULL );
145                */
146                return 0;
147       
148        if( value == NULL && ( s->flags & SET_NULL_OK ) == 0 )
149                return 0;
150       
151        /* Call the evaluator. For invalid values, evaluators should now
152           return SET_INVALID, but previously this was NULL. Try to handle
153           that too if NULL is not an allowed value for this setting. */
154        if( s->eval && ( ( nv = s->eval( s, value ) ) == SET_INVALID ||
155                         ( ( s->flags & SET_NULL_OK ) == 0 && nv == NULL ) ) )
156                return 0;
157       
158        if( s->value )
159        {
160                g_free( s->value );
161                s->value = NULL;
162        }
163       
164        /* If there's a default setting and it's equal to what we're trying to
165           set, stick with s->value = NULL. Otherwise, remember the setting. */
166        if( !s->def || ( strcmp( nv, s->def ) != 0 ) )
167                s->value = g_strdup( nv );
168       
169        if( nv != value )
170                g_free( nv );
171       
172        return 1;
173}
174
175int set_setint( set_t **head, const char *key, int value )
176{
177        char s[24];     /* Not quite 128-bit clean eh? ;-) */
178       
179        g_snprintf( s, sizeof( s ), "%d", value );
180        return set_setstr( head, key, s );
181}
182
183void set_del( set_t **head, const char *key )
184{
185        set_t *s = *head, *t = NULL;
186       
187        while( s )
188        {
189                if( g_strcasecmp( s->key, key ) == 0 )
190                        break;
191                s = (t=s)->next;
192        }
193        if( s )
194        {
195                if( t )
196                        t->next = s->next;
197                else
198                        *head = s->next;
199               
200                g_free( s->key );
201                g_free( s->old_key );
202                g_free( s->value );
203                g_free( s->def );
204                g_free( s );
205        }
206}
207
208int set_reset( set_t **head, const char *key )
209{
210        set_t *s;
211       
212        s = set_find( head, key );
213        if( s )
214                return set_setstr( head, key, s->def );
215       
216        return 0;
217}
218
219char *set_eval_int( set_t *set, char *value )
220{
221        char *s = value;
222       
223        /* Allow a minus at the first position. */
224        if( *s == '-' )
225                s ++;
226       
227        for( ; *s; s ++ )
228                if( !isdigit( *s ) )
229                        return SET_INVALID;
230       
231        return value;
232}
233
234char *set_eval_bool( set_t *set, char *value )
235{
236        return is_bool( value ) ? value : SET_INVALID;
237}
238
239char *set_eval_list( set_t *set, char *value )
240{
241        GSList *options = set->eval_data, *opt;
242       
243        for( opt = options; opt; opt = opt->next )
244                if( strcmp( value, opt->data ) == 0 )
245                        return value;
246       
247        /* TODO: It'd be nice to show the user a list of allowed values,
248                 but we don't have enough context here to do that. May
249                 want to fix that. */
250       
251        return NULL;
252}
253
254char *set_eval_to_char( set_t *set, char *value )
255{
256        char *s = g_new( char, 3 );
257       
258        if( *value == ' ' )
259                strcpy( s, " " );
260        else
261                sprintf( s, "%c ", *value );
262       
263        return s;
264}
265
266char *set_eval_oauth( set_t *set, char *value )
267{
268        account_t *acc = set->data;
269       
270        if( bool2int( value ) && strcmp( acc->pass, PASSWORD_PENDING ) == 0 )
271                *acc->pass = '\0';
272       
273        return set_eval_bool( set, value );
274}
Note: See TracBrowser for help on using the repository browser.