LGPL
[vlc.git] / src / config / core.c
1 /*****************************************************************************
2  * core.c management of the modules configuration
3  *****************************************************************************
4  * Copyright (C) 2001-2007 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <vlc_common.h>
29 #include <vlc_keys.h>
30 #include <vlc_modules.h>
31
32 #include "vlc_configuration.h"
33
34 #include <assert.h>
35
36 #include "configuration.h"
37 #include "modules/modules.h"
38
39 vlc_rwlock_t config_lock = VLC_STATIC_RWLOCK;
40
41 static inline char *strdupnull (const char *src)
42 {
43     return src ? strdup (src) : NULL;
44 }
45
46 #undef config_GetType
47 /*****************************************************************************
48  * config_GetType: get the type of a variable (bool, int, float, string)
49  *****************************************************************************
50  * This function is used to get the type of a variable from its name.
51  * Beware, this is quite slow.
52  *****************************************************************************/
53 int config_GetType( vlc_object_t *p_this, const char *psz_name )
54 {
55     module_config_t *p_config;
56     int i_type;
57
58     p_config = config_FindConfig( p_this, psz_name );
59
60     /* sanity checks */
61     if( !p_config )
62     {
63         return 0;
64     }
65
66     switch( CONFIG_CLASS(p_config->i_type) )
67     {
68     case CONFIG_ITEM_FLOAT:
69         i_type = VLC_VAR_FLOAT;
70         break;
71
72     case CONFIG_ITEM_INTEGER:
73         i_type = VLC_VAR_INTEGER;
74         break;
75
76     case CONFIG_ITEM_BOOL:
77         i_type = VLC_VAR_BOOL;
78         break;
79
80     case CONFIG_ITEM_STRING:
81         i_type = VLC_VAR_STRING;
82         break;
83
84     default:
85         i_type = 0;
86         break;
87     }
88
89     return i_type;
90 }
91
92 bool config_IsSafe( const char *name )
93 {
94     module_config_t *p_config = config_FindConfig( NULL, name );
95     return p_config != NULL && p_config->b_safe;
96 }
97
98 #undef config_GetInt
99 /*****************************************************************************
100  * config_GetInt: get the value of an int variable
101  *****************************************************************************
102  * This function is used to get the value of variables which are internally
103  * represented by an integer (CONFIG_ITEM_INTEGER and
104  * CONFIG_ITEM_BOOL).
105  *****************************************************************************/
106 int64_t config_GetInt( vlc_object_t *p_this, const char *psz_name )
107 {
108     module_config_t *p_config;
109
110     p_config = config_FindConfig( p_this, psz_name );
111
112     /* sanity checks */
113     if( !p_config )
114     {
115         msg_Err( p_this, "option %s does not exist", psz_name );
116         return -1;
117     }
118
119     if (!IsConfigIntegerType (p_config->i_type))
120     {
121         msg_Err( p_this, "option %s does not refer to an int", psz_name );
122         return -1;
123     }
124
125     int64_t val;
126
127     vlc_rwlock_rdlock (&config_lock);
128     val = p_config->value.i;
129     vlc_rwlock_unlock (&config_lock);
130     return val;
131 }
132
133 #undef config_GetFloat
134 /*****************************************************************************
135  * config_GetFloat: get the value of a float variable
136  *****************************************************************************
137  * This function is used to get the value of variables which are internally
138  * represented by a float (CONFIG_ITEM_FLOAT).
139  *****************************************************************************/
140 float config_GetFloat( vlc_object_t *p_this, const char *psz_name )
141 {
142     module_config_t *p_config;
143
144     p_config = config_FindConfig( p_this, psz_name );
145
146     /* sanity checks */
147     if( !p_config )
148     {
149         msg_Err( p_this, "option %s does not exist", psz_name );
150         return -1;
151     }
152
153     if (!IsConfigFloatType (p_config->i_type))
154     {
155         msg_Err( p_this, "option %s does not refer to a float", psz_name );
156         return -1;
157     }
158
159     float val;
160
161     vlc_rwlock_rdlock (&config_lock);
162     val = p_config->value.f;
163     vlc_rwlock_unlock (&config_lock);
164     return val;
165 }
166
167 #undef config_GetPsz
168 /*****************************************************************************
169  * config_GetPsz: get the string value of a string variable
170  *****************************************************************************
171  * This function is used to get the value of variables which are internally
172  * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_*FILE,
173  * CONFIG_ITEM_DIRECTORY, CONFIG_ITEM_PASSWORD, and CONFIG_ITEM_MODULE).
174  *
175  * Important note: remember to free() the returned char* because it's a
176  *   duplicate of the actual value. It isn't safe to return a pointer to the
177  *   actual value as it can be modified at any time.
178  *****************************************************************************/
179 char * config_GetPsz( vlc_object_t *p_this, const char *psz_name )
180 {
181     module_config_t *p_config;
182
183     p_config = config_FindConfig( p_this, psz_name );
184
185     /* sanity checks */
186     if( !p_config )
187     {
188         msg_Err( p_this, "option %s does not exist", psz_name );
189         return NULL;
190     }
191
192     if (!IsConfigStringType (p_config->i_type))
193     {
194         msg_Err( p_this, "option %s does not refer to a string", psz_name );
195         return NULL;
196     }
197
198     /* return a copy of the string */
199     vlc_rwlock_rdlock (&config_lock);
200     char *psz_value = strdupnull (p_config->value.psz);
201     vlc_rwlock_unlock (&config_lock);
202
203     return psz_value;
204 }
205
206 #undef config_PutPsz
207 /*****************************************************************************
208  * config_PutPsz: set the string value of a string variable
209  *****************************************************************************
210  * This function is used to set the value of variables which are internally
211  * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_*FILE,
212  * CONFIG_ITEM_DIRECTORY, CONFIG_ITEM_PASSWORD, and CONFIG_ITEM_MODULE).
213  *****************************************************************************/
214 void config_PutPsz( vlc_object_t *p_this,
215                       const char *psz_name, const char *psz_value )
216 {
217     module_config_t *p_config;
218
219     p_config = config_FindConfig( p_this, psz_name );
220
221
222     /* sanity checks */
223     if( !p_config )
224     {
225         msg_Warn( p_this, "option %s does not exist", psz_name );
226         return;
227     }
228
229     if (!IsConfigStringType (p_config->i_type))
230     {
231         msg_Err( p_this, "option %s does not refer to a string", psz_name );
232         return;
233     }
234
235     char *str, *oldstr;
236     if ((psz_value != NULL) && *psz_value)
237         str = strdup (psz_value);
238     else
239         str = NULL;
240
241     vlc_rwlock_wrlock (&config_lock);
242     oldstr = (char *)p_config->value.psz;
243     p_config->value.psz = str;
244     p_config->b_dirty = true;
245     vlc_rwlock_unlock (&config_lock);
246
247     free (oldstr);
248 }
249
250 #undef config_PutInt
251 /*****************************************************************************
252  * config_PutInt: set the integer value of an int variable
253  *****************************************************************************
254  * This function is used to set the value of variables which are internally
255  * represented by an integer (CONFIG_ITEM_INTEGER and
256  * CONFIG_ITEM_BOOL).
257  *****************************************************************************/
258 void config_PutInt( vlc_object_t *p_this, const char *psz_name,
259                     int64_t i_value )
260 {
261     module_config_t *p_config;
262
263     p_config = config_FindConfig( p_this, psz_name );
264
265     /* sanity checks */
266     if( !p_config )
267     {
268         msg_Warn( p_this, "option %s does not exist", psz_name );
269         return;
270     }
271
272     if (!IsConfigIntegerType (p_config->i_type))
273     {
274         msg_Err( p_this, "option %s does not refer to an int", psz_name );
275         return;
276     }
277
278     if (i_value < p_config->min.i)
279         i_value = p_config->min.i;
280     if (i_value > p_config->max.i)
281         i_value = p_config->max.i;
282
283     vlc_rwlock_wrlock (&config_lock);
284     p_config->value.i = i_value;
285     p_config->b_dirty = true;
286     vlc_rwlock_unlock (&config_lock);
287 }
288
289 #undef config_PutFloat
290 /*****************************************************************************
291  * config_PutFloat: set the value of a float variable
292  *****************************************************************************
293  * This function is used to set the value of variables which are internally
294  * represented by a float (CONFIG_ITEM_FLOAT).
295  *****************************************************************************/
296 void config_PutFloat( vlc_object_t *p_this,
297                       const char *psz_name, float f_value )
298 {
299     module_config_t *p_config;
300
301     p_config = config_FindConfig( p_this, psz_name );
302
303     /* sanity checks */
304     if( !p_config )
305     {
306         msg_Warn( p_this, "option %s does not exist", psz_name );
307         return;
308     }
309
310     if (!IsConfigFloatType (p_config->i_type))
311     {
312         msg_Err( p_this, "option %s does not refer to a float", psz_name );
313         return;
314     }
315
316     /* if f_min == f_max == 0, then do not use them */
317     if ((p_config->min.f == 0) && (p_config->max.f == 0))
318         ;
319     else if (f_value < p_config->min.f)
320         f_value = p_config->min.f;
321     else if (f_value > p_config->max.f)
322         f_value = p_config->max.f;
323
324     vlc_rwlock_wrlock (&config_lock);
325     p_config->value.f = f_value;
326     p_config->b_dirty = true;
327     vlc_rwlock_unlock (&config_lock);
328 }
329
330 static int confcmp (const void *a, const void *b)
331 {
332     const module_config_t *const *ca = a, *const *cb = b;
333
334     return strcmp ((*ca)->psz_name, (*cb)->psz_name);
335 }
336
337 static int confnamecmp (const void *key, const void *elem)
338 {
339     const module_config_t *const *conf = elem;
340
341     return strcmp (key, (*conf)->psz_name);
342 }
343
344 static struct
345 {
346     module_config_t **list;
347     size_t count;
348 } config = { NULL, 0 };
349
350 /**
351  * Index the configuration items by name for faster lookups.
352  */
353 int config_SortConfig (void)
354 {
355     size_t nmod;
356     module_t **mlist = module_list_get (&nmod);
357     if (unlikely(mlist == NULL))
358         return VLC_ENOMEM;
359
360     size_t nconf = 0;
361     for (size_t i = 0; i < nmod; i++)
362          nconf  += mlist[i]->confsize;
363
364     module_config_t **clist = malloc (sizeof (*clist) * nconf);
365     if (unlikely(clist == NULL))
366     {
367         module_list_free (mlist);
368         return VLC_ENOMEM;
369     }
370
371     nconf = 0;
372     for (size_t i = 0; i < nmod; i++)
373     {
374         module_t *parser = mlist[i];
375         module_config_t *item, *end;
376
377         for (item = parser->p_config, end = item + parser->confsize;
378              item < end;
379              item++)
380         {
381             if (!CONFIG_ITEM(item->i_type))
382                 continue; /* ignore hints */
383             clist[nconf++] = item;
384         }
385     }
386     module_list_free (mlist);
387
388     qsort (clist, nconf, sizeof (*clist), confcmp);
389
390     config.list = clist;
391     config.count = nconf;
392     return VLC_SUCCESS;
393 }
394
395 void config_UnsortConfig (void)
396 {
397     module_config_t **clist;
398
399     clist = config.list;
400     config.list = NULL;
401     config.count = 0;
402
403     free (clist);
404 }
405
406 /*****************************************************************************
407  * config_FindConfig: find the config structure associated with an option.
408  *****************************************************************************
409  * FIXME: remove p_this pointer parameter (or use it)
410  *****************************************************************************/
411 module_config_t *config_FindConfig (vlc_object_t *p_this, const char *name)
412 {
413     VLC_UNUSED(p_this);
414
415     if (unlikely(name == NULL))
416         return NULL;
417
418     module_config_t *const *p;
419     p = bsearch (name, config.list, config.count, sizeof (*p), confnamecmp);
420     return p ? *p : NULL;
421 }
422
423 /**
424  * Destroys an array of configuration items.
425  * \param config start of array of items
426  * \param confsize number of items in the array
427  */
428 void config_Free (module_config_t *config, size_t confsize)
429 {
430     for (size_t j = 0; j < confsize; j++)
431     {
432         module_config_t *p_item = config + j;
433
434         free( p_item->psz_type );
435         free( p_item->psz_name );
436         free( p_item->psz_text );
437         free( p_item->psz_longtext );
438
439         if (IsConfigStringType (p_item->i_type))
440         {
441             free (p_item->value.psz);
442             free (p_item->orig.psz);
443         }
444
445         if( p_item->ppsz_list )
446             for (int i = 0; i < p_item->i_list; i++)
447                 free( p_item->ppsz_list[i] );
448         if( p_item->ppsz_list_text )
449             for (int i = 0; i < p_item->i_list; i++)
450                 free( p_item->ppsz_list_text[i] );
451         free( p_item->ppsz_list );
452         free( p_item->ppsz_list_text );
453         free( p_item->pi_list );
454
455         if( p_item->i_action )
456         {
457             for (int i = 0; i < p_item->i_action; i++)
458                 free( p_item->ppsz_action_text[i] );
459             free( p_item->ppf_action );
460             free( p_item->ppsz_action_text );
461         }
462     }
463
464     free (config);
465 }
466
467 #undef config_ResetAll
468 /*****************************************************************************
469  * config_ResetAll: reset the configuration data for all the modules.
470  *****************************************************************************/
471 void config_ResetAll( vlc_object_t *p_this )
472 {
473     VLC_UNUSED(p_this);
474     module_t *p_module;
475     module_t **list = module_list_get (NULL);
476
477     vlc_rwlock_wrlock (&config_lock);
478     for (size_t j = 0; (p_module = list[j]) != NULL; j++)
479         for (size_t i = 0; i < p_module->confsize; i++ )
480         {
481             module_config_t *p_config = p_module->p_config + i;
482
483             if (IsConfigIntegerType (p_config->i_type))
484                 p_config->value.i = p_config->orig.i;
485             else
486             if (IsConfigFloatType (p_config->i_type))
487                 p_config->value.f = p_config->orig.f;
488             else
489             if (IsConfigStringType (p_config->i_type))
490             {
491                 free ((char *)p_config->value.psz);
492                 p_config->value.psz =
493                         strdupnull (p_config->orig.psz);
494             }
495         }
496     vlc_rwlock_unlock (&config_lock);
497
498     module_list_free (list);
499 }