]> git.sesse.net Git - vlc/blob - src/config/core.c
Don't include config.h from the headers - refs #297.
[vlc] / src / config / core.c
1 /*****************************************************************************
2  * core.c management of the modules configuration
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, 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/vlc.h>
29 #include "../libvlc.h"
30 #include "vlc_keys.h"
31 #include "vlc_charset.h"
32
33 #include <errno.h>                                                  /* errno */
34
35 #ifdef HAVE_LIMITS_H
36 #   include <limits.h>
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 #    include <unistd.h>                                          /* getuid() */
41 #endif
42
43 #ifdef HAVE_GETOPT_LONG
44 #   ifdef HAVE_GETOPT_H
45 #       include <getopt.h>                                       /* getopt() */
46 #   endif
47 #else
48 #   include "../extras/getopt.h"
49 #endif
50
51 #if defined(HAVE_GETPWUID)
52 #   include <pwd.h>                                            /* getpwuid() */
53 #endif
54
55 #if defined( HAVE_SYS_STAT_H )
56 #   include <sys/stat.h>
57 #endif
58 #if defined( HAVE_SYS_TYPES_H )
59 #   include <sys/types.h>
60 #endif
61 #if defined( WIN32 )
62 #   if !defined( UNDER_CE )
63 #       include <direct.h>
64 #   endif
65 #include <tchar.h>
66 #endif
67
68 #include "configuration.h"
69 #include "modules/modules.h"
70
71 static inline char *strdupnull (const char *src)
72 {
73     return src ? strdup (src) : NULL;
74 }
75
76 static inline char *_strdupnull (const char *src)
77 {
78     return src ? strdup (_(src)) : NULL;
79 }
80
81 /* Item types that use a string value (i.e. serialized in the module cache) */
82 int IsConfigStringType (int type)
83 {
84     static const unsigned char config_types[] =
85     {
86         CONFIG_ITEM_STRING, CONFIG_ITEM_FILE, CONFIG_ITEM_MODULE,
87         CONFIG_ITEM_DIRECTORY, CONFIG_ITEM_MODULE_CAT, CONFIG_ITEM_PASSWORD,
88         CONFIG_ITEM_MODULE_LIST, CONFIG_ITEM_MODULE_LIST_CAT
89     };
90
91     /* NOTE: this needs to be changed if we ever get more than 255 types */
92     return memchr (config_types, type, sizeof (config_types)) != NULL;
93 }
94
95
96 int IsConfigIntegerType (int type)
97 {
98     static const unsigned char config_types[] =
99     {
100         CONFIG_ITEM_INTEGER, CONFIG_ITEM_KEY, CONFIG_ITEM_BOOL,
101         CONFIG_CATEGORY, CONFIG_SUBCATEGORY
102     };
103
104     return memchr (config_types, type, sizeof (config_types)) != NULL;
105 }
106
107
108 /*****************************************************************************
109  * config_GetType: get the type of a variable (bool, int, float, string)
110  *****************************************************************************
111  * This function is used to get the type of a variable from its name.
112  * Beware, this is quite slow.
113  *****************************************************************************/
114 int __config_GetType( vlc_object_t *p_this, const char *psz_name )
115 {
116     module_config_t *p_config;
117     int i_type;
118
119     p_config = config_FindConfig( p_this, psz_name );
120
121     /* sanity checks */
122     if( !p_config )
123     {
124         return 0;
125     }
126
127     switch( p_config->i_type )
128     {
129     case CONFIG_ITEM_BOOL:
130         i_type = VLC_VAR_BOOL;
131         break;
132
133     case CONFIG_ITEM_INTEGER:
134     case CONFIG_ITEM_KEY:
135         i_type = VLC_VAR_INTEGER;
136         break;
137
138     case CONFIG_ITEM_FLOAT:
139         i_type = VLC_VAR_FLOAT;
140         break;
141
142     case CONFIG_ITEM_MODULE:
143     case CONFIG_ITEM_MODULE_CAT:
144     case CONFIG_ITEM_MODULE_LIST:
145     case CONFIG_ITEM_MODULE_LIST_CAT:
146         i_type = VLC_VAR_MODULE;
147         break;
148
149     case CONFIG_ITEM_STRING:
150         i_type = VLC_VAR_STRING;
151         break;
152
153     case CONFIG_ITEM_PASSWORD:
154         i_type = VLC_VAR_STRING;
155         break;
156
157     case CONFIG_ITEM_FILE:
158         i_type = VLC_VAR_FILE;
159         break;
160
161     case CONFIG_ITEM_DIRECTORY:
162         i_type = VLC_VAR_DIRECTORY;
163         break;
164
165     default:
166         i_type = 0;
167         break;
168     }
169
170     return i_type;
171 }
172
173 /*****************************************************************************
174  * config_GetInt: get the value of an int variable
175  *****************************************************************************
176  * This function is used to get the value of variables which are internally
177  * represented by an integer (CONFIG_ITEM_INTEGER and
178  * CONFIG_ITEM_BOOL).
179  *****************************************************************************/
180 int __config_GetInt( vlc_object_t *p_this, const char *psz_name )
181 {
182     module_config_t *p_config;
183
184     p_config = config_FindConfig( p_this, psz_name );
185
186     /* sanity checks */
187     if( !p_config )
188     {
189         msg_Err( p_this, "option %s does not exist", psz_name );
190         return -1;
191     }
192
193     if (!IsConfigIntegerType (p_config->i_type))
194     {
195         msg_Err( p_this, "option %s does not refer to an int", psz_name );
196         return -1;
197     }
198
199     return p_config->value.i;
200 }
201
202 /*****************************************************************************
203  * config_GetFloat: get the value of a float variable
204  *****************************************************************************
205  * This function is used to get the value of variables which are internally
206  * represented by a float (CONFIG_ITEM_FLOAT).
207  *****************************************************************************/
208 float __config_GetFloat( vlc_object_t *p_this, const char *psz_name )
209 {
210     module_config_t *p_config;
211
212     p_config = config_FindConfig( p_this, psz_name );
213
214     /* sanity checks */
215     if( !p_config )
216     {
217         msg_Err( p_this, "option %s does not exist", psz_name );
218         return -1;
219     }
220
221     if (!IsConfigFloatType (p_config->i_type))
222     {
223         msg_Err( p_this, "option %s does not refer to a float", psz_name );
224         return -1;
225     }
226
227     return p_config->value.f;
228 }
229
230 /*****************************************************************************
231  * config_GetPsz: get the string value of a string variable
232  *****************************************************************************
233  * This function is used to get the value of variables which are internally
234  * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_FILE,
235  * CONFIG_ITEM_DIRECTORY, CONFIG_ITEM_PASSWORD, and CONFIG_ITEM_MODULE).
236  *
237  * Important note: remember to free() the returned char* because it's a
238  *   duplicate of the actual value. It isn't safe to return a pointer to the
239  *   actual value as it can be modified at any time.
240  *****************************************************************************/
241 char * __config_GetPsz( vlc_object_t *p_this, const char *psz_name )
242 {
243     module_config_t *p_config;
244
245     p_config = config_FindConfig( p_this, psz_name );
246
247     /* sanity checks */
248     if( !p_config )
249     {
250         msg_Err( p_this, "option %s does not exist", psz_name );
251         return NULL;
252     }
253
254     if (!IsConfigStringType (p_config->i_type))
255     {
256         msg_Err( p_this, "option %s does not refer to a string", psz_name );
257         return NULL;
258     }
259
260     /* return a copy of the string */
261     vlc_mutex_lock( p_config->p_lock );
262     char *psz_value = strdupnull (p_config->value.psz);
263     vlc_mutex_unlock( p_config->p_lock );
264
265     return psz_value;
266 }
267
268 /*****************************************************************************
269  * config_PutPsz: set the string value of a string variable
270  *****************************************************************************
271  * This function is used to set the value of variables which are internally
272  * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_FILE,
273  * CONFIG_ITEM_DIRECTORY, CONFIG_ITEM_PASSWORD, and CONFIG_ITEM_MODULE).
274  *****************************************************************************/
275 void __config_PutPsz( vlc_object_t *p_this,
276                       const char *psz_name, const char *psz_value )
277 {
278     module_config_t *p_config;
279     vlc_value_t oldval, val;
280
281     p_config = config_FindConfig( p_this, psz_name );
282
283
284     /* sanity checks */
285     if( !p_config )
286     {
287         msg_Warn( p_this, "option %s does not exist", psz_name );
288         return;
289     }
290
291     if (!IsConfigStringType (p_config->i_type))
292     {
293         msg_Err( p_this, "option %s does not refer to a string", psz_name );
294         return;
295     }
296
297     vlc_mutex_lock( p_config->p_lock );
298
299     /* backup old value */
300     oldval.psz_string = (char *)p_config->value.psz;
301
302     if ((psz_value != NULL) && *psz_value)
303         p_config->value.psz = strdup (psz_value);
304     else
305         p_config->value.psz = NULL;
306
307     p_config->b_dirty = VLC_TRUE;
308
309     val.psz_string = (char *)p_config->value.psz;
310
311     vlc_mutex_unlock( p_config->p_lock );
312
313     if( p_config->pf_callback )
314     {
315         p_config->pf_callback( p_this, psz_name, oldval, val,
316                                p_config->p_callback_data );
317     }
318
319     /* free old string */
320     if( oldval.psz_string ) free( oldval.psz_string );
321 }
322
323 /*****************************************************************************
324  * config_PutInt: set the integer value of an int variable
325  *****************************************************************************
326  * This function is used to set the value of variables which are internally
327  * represented by an integer (CONFIG_ITEM_INTEGER and
328  * CONFIG_ITEM_BOOL).
329  *****************************************************************************/
330 void __config_PutInt( vlc_object_t *p_this, const char *psz_name, int i_value )
331 {
332     module_config_t *p_config;
333     vlc_value_t oldval, val;
334
335     p_config = config_FindConfig( p_this, psz_name );
336
337     /* sanity checks */
338     if( !p_config )
339     {
340         msg_Warn( p_this, "option %s does not exist", psz_name );
341         return;
342     }
343
344     if (!IsConfigIntegerType (p_config->i_type))
345     {
346         msg_Err( p_this, "option %s does not refer to an int", psz_name );
347         return;
348     }
349
350     /* backup old value */
351     oldval.i_int = p_config->value.i;
352
353     /* if i_min == i_max == 0, then do not use them */
354     if ((p_config->min.i == 0) && (p_config->max.i == 0))
355     {
356         p_config->value.i = i_value;
357     }
358     else if (i_value < p_config->min.i)
359     {
360         p_config->value.i = p_config->min.i;
361     }
362     else if (i_value > p_config->max.i)
363     {
364         p_config->value.i = p_config->max.i;
365     }
366     else
367     {
368         p_config->value.i = i_value;
369     }
370
371     p_config->b_dirty = VLC_TRUE;
372
373     val.i_int = p_config->value.i;
374
375     if( p_config->pf_callback )
376     {
377         p_config->pf_callback( p_this, psz_name, oldval, val,
378                                p_config->p_callback_data );
379     }
380 }
381
382 /*****************************************************************************
383  * config_PutFloat: set the value of a float variable
384  *****************************************************************************
385  * This function is used to set the value of variables which are internally
386  * represented by a float (CONFIG_ITEM_FLOAT).
387  *****************************************************************************/
388 void __config_PutFloat( vlc_object_t *p_this,
389                         const char *psz_name, float f_value )
390 {
391     module_config_t *p_config;
392     vlc_value_t oldval, val;
393
394     p_config = config_FindConfig( p_this, psz_name );
395
396     /* sanity checks */
397     if( !p_config )
398     {
399         msg_Warn( p_this, "option %s does not exist", psz_name );
400         return;
401     }
402
403     if (!IsConfigFloatType (p_config->i_type))
404     {
405         msg_Err( p_this, "option %s does not refer to a float", psz_name );
406         return;
407     }
408
409     /* backup old value */
410     oldval.f_float = p_config->value.f;
411
412     /* if f_min == f_max == 0, then do not use them */
413     if ((p_config->min.f == 0) && (p_config->max.f == 0))
414     {
415         p_config->value.f = f_value;
416     }
417     else if (f_value < p_config->min.f)
418     {
419         p_config->value.f = p_config->min.f;
420     }
421     else if (f_value > p_config->max.f)
422     {
423         p_config->value.f = p_config->max.f;
424     }
425     else
426     {
427         p_config->value.f = f_value;
428     }
429
430     p_config->b_dirty = VLC_TRUE;
431
432     val.f_float = p_config->value.f;
433
434     if( p_config->pf_callback )
435     {
436         p_config->pf_callback( p_this, psz_name, oldval, val,
437                                p_config->p_callback_data );
438     }
439 }
440
441 /*****************************************************************************
442  * config_FindConfig: find the config structure associated with an option.
443  *****************************************************************************
444  * FIXME: This function really needs to be optimized.
445  * FIXME: And now even more.
446  *****************************************************************************/
447 module_config_t *config_FindConfig( vlc_object_t *p_this, const char *psz_name )
448 {
449     vlc_list_t *p_list;
450     int i_index;
451
452     if( !psz_name ) return NULL;
453
454     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
455
456     for( i_index = 0; i_index < p_list->i_count; i_index++ )
457     {
458         module_config_t *p_item, *p_end;
459         module_t *p_parser = (module_t *)p_list->p_values[i_index].p_object;
460
461         if( !p_parser->i_config_items )
462             continue;
463
464         for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
465              p_item < p_end;
466              p_item++ )
467         {
468             if( p_item->i_type & CONFIG_HINT )
469                 /* ignore hints */
470                 continue;
471             if( !strcmp( psz_name, p_item->psz_name )
472              || ( p_item->psz_oldname
473               && !strcmp( psz_name, p_item->psz_oldname ) ) )
474             {
475                 vlc_list_release( p_list );
476                 return p_item;
477             }
478         }
479     }
480
481     vlc_list_release( p_list );
482
483     return NULL;
484 }
485
486 /*****************************************************************************
487  * config_Free: frees a duplicated module's configuration data.
488  *****************************************************************************
489  * This function frees all the data duplicated by config_Duplicate.
490  *****************************************************************************/
491 void config_Free( module_t *p_module )
492 {
493     int i;
494
495     for (size_t j = 0; j < p_module->confsize; j++)
496     {
497         module_config_t *p_item = p_module->p_config + j;
498
499         free( p_item->psz_type );
500         free( p_item->psz_name );
501         free( p_item->psz_text );
502         free( p_item->psz_longtext );
503         free( p_item->psz_oldname );
504
505         if (IsConfigStringType (p_item->i_type))
506         {
507             free (p_item->value.psz);
508             free (p_item->orig.psz);
509             free (p_item->saved.psz);
510         }
511
512         if( p_item->ppsz_list )
513             for( i = 0; i < p_item->i_list; i++ )
514                 free( p_item->ppsz_list[i] );
515         if( p_item->ppsz_list_text )
516             for( i = 0; i < p_item->i_list; i++ )
517                 free( p_item->ppsz_list_text[i] );
518         free( p_item->ppsz_list );
519         free( p_item->ppsz_list_text );
520         free( p_item->pi_list );
521
522         if( p_item->i_action )
523         {
524             for( i = 0; i < p_item->i_action; i++ )
525             {
526                 free( p_item->ppsz_action_text[i] );
527             }
528             free( p_item->ppf_action );
529             free( p_item->ppsz_action_text );
530         }
531     }
532
533     free (p_module->p_config);
534     p_module->p_config = NULL;
535 }
536
537 /*****************************************************************************
538  * config_SetCallbacks: sets callback functions in the duplicate p_config.
539  *****************************************************************************
540  * Unfortunatly we cannot work directly with the module's config data as
541  * this module might be unloaded from memory at any time (remember HideModule).
542  * This is why we need to duplicate callbacks each time we reload the module.
543  *****************************************************************************/
544 void config_SetCallbacks( module_config_t *p_new, module_config_t *p_orig,
545                           size_t n )
546 {
547     for (size_t i = 0; i < n; i++)
548     {
549         p_new->pf_callback = p_orig->pf_callback;
550         p_new++;
551         p_orig++;
552     }
553 }
554
555 /*****************************************************************************
556  * config_UnsetCallbacks: unsets callback functions in the duplicate p_config.
557  *****************************************************************************
558  * We simply undo what we did in config_SetCallbacks.
559  *****************************************************************************/
560 void config_UnsetCallbacks( module_config_t *p_new, size_t n )
561 {
562     for (size_t i = 0; i < n; i++)
563     {
564         p_new->pf_callback = NULL;
565         p_new++;
566     }
567 }
568
569 /*****************************************************************************
570  * config_ResetAll: reset the configuration data for all the modules.
571  *****************************************************************************/
572 void __config_ResetAll( vlc_object_t *p_this )
573 {
574     int i_index;
575     vlc_list_t *p_list;
576     module_t *p_module;
577
578     /* Acquire config file lock */
579     vlc_mutex_lock( &p_this->p_libvlc->config_lock );
580
581     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
582
583     for( i_index = 0; i_index < p_list->i_count; i_index++ )
584     {
585         p_module = (module_t *)p_list->p_values[i_index].p_object ;
586         if( p_module->b_submodule ) continue;
587
588         for (size_t i = 0; i < p_module->confsize; i++ )
589         {
590             if (IsConfigIntegerType (p_module->p_config[i].i_type))
591                 p_module->p_config[i].value.i = p_module->p_config[i].orig.i;
592             else
593             if (IsConfigFloatType (p_module->p_config[i].i_type))
594                 p_module->p_config[i].value.f = p_module->p_config[i].orig.f;
595             else
596             if (IsConfigStringType (p_module->p_config[i].i_type))
597             {
598                 free ((char *)p_module->p_config[i].value.psz);
599                 p_module->p_config[i].value.psz =
600                         strdupnull (p_module->p_config[i].orig.psz);
601             }
602         }
603     }
604
605     vlc_list_release( p_list );
606     vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
607 }
608
609 /**
610  * config_GetDataDir: find directory where shared data is installed
611  *
612  * @return a string (always succeeds).
613  */
614 const char *config_GetDataDir( void )
615 {
616 #if defined (WIN32) || defined (UNDER_CE)
617     return vlc_global()->psz_vlcpath;
618 #elif defined(__APPLE__) || defined (SYS_BEOS)
619     static char path[PATH_MAX] = "";
620
621     if( *path == '\0' )
622     {
623         snprintf( path, sizeof( path ), "%s/share",
624                   vlc_global()->psz_vlcpath );
625         path[sizeof( path ) - 1] = '\0';
626     }
627     return path;
628 #else
629     return DATA_PATH;
630 #endif
631 }
632
633 /*****************************************************************************
634  * config_GetHomeDir, config_GetUserDir: find the user's home directory.
635  *****************************************************************************
636  * This function will try by different ways to find the user's home path.
637  * Note that this function is not reentrant, it should be called only once
638  * at the beginning of main where the result will be stored for later use.
639  *****************************************************************************/
640 static char *GetDir( vlc_bool_t b_appdata )
641 {
642     const char *psz_localhome = NULL;
643
644 #if defined(WIN32) && !defined(UNDER_CE)
645     typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
646                                                LPWSTR );
647 #ifndef CSIDL_FLAG_CREATE
648 #   define CSIDL_FLAG_CREATE 0x8000
649 #endif
650 #ifndef CSIDL_APPDATA
651 #   define CSIDL_APPDATA 0x1A
652 #endif
653 #ifndef CSIDL_PROFILE
654 #   define CSIDL_PROFILE 0x28
655 #endif
656 #ifndef SHGFP_TYPE_CURRENT
657 #   define SHGFP_TYPE_CURRENT 0
658 #endif
659
660     HINSTANCE shfolder_dll;
661     SHGETFOLDERPATH SHGetFolderPath ;
662
663     /* load the shfolder dll to retrieve SHGetFolderPath */
664     if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
665     {
666         SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
667                                                   _T("SHGetFolderPathW") );
668         if ( SHGetFolderPath != NULL )
669         {
670             wchar_t whomedir[MAX_PATH];
671
672             /* get the "Application Data" folder for the current user */
673             if( S_OK == SHGetFolderPath( NULL,
674                                          (b_appdata ? CSIDL_APPDATA :
675                                            CSIDL_PROFILE) | CSIDL_FLAG_CREATE,
676                                          NULL, SHGFP_TYPE_CURRENT,
677                                          whomedir ) )
678             {
679                 FreeLibrary( shfolder_dll );
680                 return FromWide( whomedir );
681             }
682         }
683         FreeLibrary( shfolder_dll );
684     }
685
686 #elif defined(UNDER_CE)
687
688 #ifndef CSIDL_APPDATA
689 #   define CSIDL_APPDATA 0x1A
690 #endif
691
692     wchar_t whomedir[MAX_PATH];
693
694     /* get the "Application Data" folder for the current user */
695     if( SHGetSpecialFolderPath( NULL, whomedir, CSIDL_APPDATA, 1 ) )
696         return FromWide( whomedir );
697 #endif
698
699     psz_localhome = getenv( "HOME" );
700     if( psz_localhome == NULL )
701     {
702 #if defined(HAVE_GETPWUID)
703         struct passwd *p_pw;
704         (void)b_appdata;
705
706         if( ( p_pw = getpwuid( getuid() ) ) != NULL )
707             psz_localhome = p_pw->pw_dir;
708         else
709 #endif
710         {
711             psz_localhome = getenv( "TMP" );
712             if( psz_localhome == NULL )
713                 psz_localhome = "/tmp";
714         }
715     }
716
717     return FromLocaleDup( psz_localhome );
718 }
719
720 /**
721  * Get the user's home directory
722  */
723 char *config_GetHomeDir( void )
724 {
725     return GetDir( VLC_FALSE );
726 }
727
728 /**
729  * Get the user's main data and config directory:
730  *   - on windows that's the App Data directory;
731  *   - on other OSes it's the same as the home directory.
732  */
733 char *config_GetUserDir( void )
734 {
735     return GetDir( VLC_TRUE );
736 }
737
738 /**
739  * Get the user's VLC configuration directory
740  */
741 char *config_GetConfigDir( libvlc_int_t *p_libvlc )
742 {
743     char *psz_dir;
744 #if defined(WIN32) || defined(__APPLE__) || defined(SYS_BEOS)
745     char *psz_parent = config_GetUserDir();
746     if( !psz_parent ) psz_parent = p_libvlc->psz_homedir;
747     if( asprintf( &psz_dir, "%s" DIR_SEP CONFIG_DIR, psz_parent ) == -1 )
748         return NULL;
749     return psz_dir;
750 #else
751     /* XDG Base Directory Specification - Version 0.6 */
752     char *psz_env = getenv( "XDG_CONFIG_HOME" );
753     if( psz_env )
754     {
755         if( asprintf( &psz_dir, "%s/vlc", psz_env ) == -1 )
756             return NULL;
757         return psz_dir;
758     }
759     psz_env = getenv( "HOME" );
760     if( !psz_env ) psz_env = p_libvlc->psz_homedir; /* not part of XDG spec but we want a sensible fallback */
761     if( asprintf( &psz_dir, "%s/.config/vlc", psz_env ) == -1 )
762         return NULL;
763     return psz_dir;
764 #endif
765 }
766
767 /**
768  * Get the user's VLC data directory
769  * (used for stuff like the skins, custom lua modules, ...)
770  */
771 char *config_GetUserDataDir( libvlc_int_t *p_libvlc )
772 {
773     char *psz_dir;
774 #if defined(WIN32) || defined(__APPLE__) || defined(SYS_BEOS)
775     char *psz_parent = config_GetUserDir();
776     if( !psz_parent ) psz_parent = p_libvlc->psz_homedir;
777     if( asprintf( &psz_dir, "%s" DIR_SEP CONFIG_DIR, psz_parent ) == -1 )
778         return NULL;
779     return psz_dir;
780 #else
781     /* XDG Base Directory Specification - Version 0.6 */
782     char *psz_env = getenv( "XDG_DATA_HOME" );
783     if( psz_env )
784     {
785         if( asprintf( &psz_dir, "%s/vlc", psz_env ) == -1 )
786             return NULL;
787         return psz_dir;
788     }
789     psz_env = getenv( "HOME" );
790     if( !psz_env ) psz_env = p_libvlc->psz_homedir; /* not part of XDG spec but we want a sensible fallback */
791     if( asprintf( &psz_dir, "%s/.local/share/vlc", psz_env ) == -1 )
792         return NULL;
793     return psz_dir;
794 #endif
795 }
796
797 /**
798  * Get the user's VLC cache directory
799  * (used for stuff like the modules cache, the album art cache, ...)
800  */
801 char *config_GetCacheDir( libvlc_int_t *p_libvlc )
802 {
803     char *psz_dir;
804 #if defined(WIN32) || defined(__APPLE__) || defined(SYS_BEOS)
805     char *psz_parent = config_GetUserDir();
806     if( !psz_parent ) psz_parent = p_libvlc->psz_homedir;
807     if( asprintf( &psz_dir, "%s" DIR_SEP CONFIG_DIR, psz_parent ) == -1 )
808         return NULL;
809     return psz_dir;
810 #else
811     /* XDG Base Directory Specification - Version 0.6 */
812     char *psz_env = getenv( "XDG_CACHE_HOME" );
813     if( psz_env )
814     {
815         if( asprintf( &psz_dir, "%s/vlc", psz_env ) == -1 )
816             return NULL;
817         return psz_dir;
818     }
819     psz_env = getenv( "HOME" );
820     if( !psz_env ) psz_env = p_libvlc->psz_homedir; /* not part of XDG spec but we want a sensible fallback */
821     if( asprintf( &psz_dir, "%s/.cache/vlc", psz_env ) == -1 )
822         return NULL;
823     return psz_dir;
824 #endif
825 }
826
827 /* Adds an extra interface to the configuration */
828 void __config_AddIntf( vlc_object_t *p_this, const char *psz_intf )
829 {
830     assert( psz_intf );
831
832     char *psz_config, *psz_parser;
833     size_t i_len = strlen( psz_intf );
834
835     psz_config = psz_parser = config_GetPsz( p_this->p_libvlc, "control" );
836     while( psz_parser )
837     {
838         if( !strncmp( psz_intf, psz_parser, i_len ) )
839         {
840             free( psz_config );
841             return;
842         }
843         psz_parser = strchr( psz_parser, ':' );
844         if( psz_parser ) psz_parser++; /* skip the ':' */
845     }
846     free( psz_config );
847
848     psz_config = psz_parser = config_GetPsz( p_this->p_libvlc, "extraintf" );
849     while( psz_parser )
850     {
851         if( !strncmp( psz_intf, psz_parser, i_len ) )
852         {
853             free( psz_config );
854             return;
855         }
856         psz_parser = strchr( psz_parser, ':' );
857         if( psz_parser ) psz_parser++; /* skip the ':' */
858     }
859
860     /* interface not found in the config, let's add it */
861     if( psz_config && strlen( psz_config ) > 0 )
862     {
863         char *psz_newconfig;
864         if( asprintf( &psz_newconfig, "%s:%s", psz_config, psz_intf ) != -1 )
865         {
866             config_PutPsz( p_this->p_libvlc, "extraintf", psz_newconfig );
867             free( psz_newconfig );
868         }
869     }
870     else
871         config_PutPsz( p_this->p_libvlc, "extraintf", psz_intf );
872
873     free( psz_config );
874 }
875
876 /* Removes an extra interface from the configuration */
877 void __config_RemoveIntf( vlc_object_t *p_this, const char *psz_intf )
878 {
879     assert( psz_intf );
880
881     char *psz_config, *psz_parser;
882     size_t i_len = strlen( psz_intf );
883
884     psz_config = psz_parser = config_GetPsz( p_this->p_libvlc, "extraintf" );
885     while( psz_parser )
886     {
887         if( !strncmp( psz_intf, psz_parser, i_len ) )
888         {
889             char *psz_newconfig;
890             char *psz_end = psz_parser + i_len;
891             if( *psz_end == ':' ) psz_end++;
892             *psz_parser = '\0';
893             if( asprintf( &psz_newconfig, "%s%s", psz_config, psz_end ) != -1 )
894             {
895                 config_PutPsz( p_this->p_libvlc, "extraintf", psz_newconfig );
896                 free( psz_newconfig );
897             }
898             break;
899         }
900         psz_parser = strchr( psz_parser, ':' );
901         if( psz_parser ) psz_parser++; /* skip the ':' */
902     }
903     free( psz_config );
904
905     psz_config = psz_parser = config_GetPsz( p_this->p_libvlc, "control" );
906     while( psz_parser )
907     {
908         if( !strncmp( psz_intf, psz_parser, i_len ) )
909         {
910             char *psz_newconfig;
911             char *psz_end = psz_parser + i_len;
912             if( *psz_end == ':' ) psz_end++;
913             *psz_parser = '\0';
914             if( asprintf( &psz_newconfig, "%s%s", psz_config, psz_end ) != -1 )
915             {
916                 config_PutPsz( p_this->p_libvlc, "control", psz_newconfig );
917                 free( psz_newconfig );
918             }
919             break;
920         }
921         psz_parser = strchr( psz_parser, ':' );
922         if( psz_parser ) psz_parser++; /* skip the ':' */
923     }
924     free( psz_config );
925 }
926
927 /*
928  * Returns VLC_TRUE if the specified extra interface is present in the
929  * configuration, VLC_FALSE if not
930  */
931 vlc_bool_t __config_ExistIntf( vlc_object_t *p_this, const char *psz_intf )
932 {
933     assert( psz_intf );
934
935     char *psz_config, *psz_parser;
936     size_t i_len = strlen( psz_intf );
937
938     psz_config = psz_parser = config_GetPsz( p_this->p_libvlc, "extraintf" );
939     while( psz_parser )
940     {
941         if( !strncmp( psz_parser, psz_intf, i_len ) )
942         {
943             free( psz_config );
944             return VLC_TRUE;
945         }
946         psz_parser = strchr( psz_parser, ':' );
947         if( psz_parser ) psz_parser++; /* skip the ':' */
948     }
949     free( psz_config );
950
951     psz_config = psz_parser = config_GetPsz( p_this->p_libvlc, "control" );
952     while( psz_parser )
953     {
954         if( !strncmp( psz_parser, psz_intf, i_len ) )
955         {
956             free( psz_config );
957             return VLC_TRUE;
958         }
959         psz_parser = strchr( psz_parser, ':' );
960         if( psz_parser ) psz_parser++; /* skip the ':' */
961     }
962     free( psz_config );
963
964     return VLC_FALSE;
965 }
966