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