]> git.sesse.net Git - vlc/blob - src/misc/configuration.c
b1163474e3cb088bee93a505016a86f46eb3f5a3
[vlc] / src / misc / configuration.c
1 /*****************************************************************************
2  * configuration.c management of the modules configuration
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: configuration.c,v 1.44 2002/11/10 23:41:53 sam Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <vlc/vlc.h>
25
26 #include <stdio.h>                                              /* sprintf() */
27 #include <stdlib.h>                                      /* free(), strtol() */
28 #include <string.h>                                              /* strdup() */
29 #ifdef HAVE_ERRNO_H
30 #   include <errno.h>                                               /* errno */
31 #endif
32
33 #ifdef HAVE_UNISTD_H
34 #    include <unistd.h>                                          /* getuid() */
35 #endif
36
37 #ifdef HAVE_GETOPT_LONG
38 #   ifdef HAVE_GETOPT_H
39 #       include <getopt.h>                                       /* getopt() */
40 #   endif
41 #else
42 #   include "../extras/getopt.h"
43 #endif
44
45 #if defined(HAVE_GETPWUID)
46 #include <pwd.h>                                               /* getpwuid() */
47 #endif
48
49 #if defined( HAVE_SYS_STAT_H )
50 #   include <sys/stat.h>
51 #endif
52 #if defined( HAVE_SYS_TYPES_H )
53 #   include <sys/types.h>
54 #endif
55
56 /*****************************************************************************
57  * config_GetInt: get the value of an int variable
58  *****************************************************************************
59  * This function is used to get the value of variables which are internally
60  * represented by an integer (CONFIG_ITEM_INTEGER and
61  * CONFIG_ITEM_BOOL).
62  *****************************************************************************/
63 int __config_GetInt( vlc_object_t *p_this, const char *psz_name )
64 {
65     module_config_t *p_config;
66
67     p_config = config_FindConfig( p_this, psz_name );
68
69     /* sanity checks */
70     if( !p_config )
71     {
72         msg_Err( p_this, "option %s does not exist", psz_name );
73         return -1;
74     }
75     if( (p_config->i_type!=CONFIG_ITEM_INTEGER) &&
76         (p_config->i_type!=CONFIG_ITEM_BOOL) )
77     {
78         msg_Err( p_this, "option %s does not refer to an int", psz_name );
79         return -1;
80     }
81
82     return p_config->i_value;
83 }
84
85 /*****************************************************************************
86  * config_GetFloat: get the value of a float variable
87  *****************************************************************************
88  * This function is used to get the value of variables which are internally
89  * represented by a float (CONFIG_ITEM_FLOAT).
90  *****************************************************************************/
91 float __config_GetFloat( vlc_object_t *p_this, const char *psz_name )
92 {
93     module_config_t *p_config;
94
95     p_config = config_FindConfig( p_this, psz_name );
96
97     /* sanity checks */
98     if( !p_config )
99     {
100         msg_Err( p_this, "option %s does not exist", psz_name );
101         return -1;
102     }
103     if( p_config->i_type != CONFIG_ITEM_FLOAT )
104     {
105         msg_Err( p_this, "option %s does not refer to a float", psz_name );
106         return -1;
107     }
108
109     return p_config->f_value;
110 }
111
112 /*****************************************************************************
113  * config_GetPsz: get the string value of a string variable
114  *****************************************************************************
115  * This function is used to get the value of variables which are internally
116  * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_FILE,
117  * and CONFIG_ITEM_MODULE).
118  *
119  * Important note: remember to free() the returned char* because it's a
120  *   duplicate of the actual value. It isn't safe to return a pointer to the
121  *   actual value as it can be modified at any time.
122  *****************************************************************************/
123 char * __config_GetPsz( vlc_object_t *p_this, const char *psz_name )
124 {
125     module_config_t *p_config;
126     char *psz_value = NULL;
127
128     p_config = config_FindConfig( p_this, psz_name );
129
130     /* sanity checks */
131     if( !p_config )
132     {
133         msg_Err( p_this, "option %s does not exist", psz_name );
134         return NULL;
135     }
136     if( (p_config->i_type!=CONFIG_ITEM_STRING) &&
137         (p_config->i_type!=CONFIG_ITEM_FILE) &&
138         (p_config->i_type!=CONFIG_ITEM_MODULE) )
139     {
140         msg_Err( p_this, "option %s does not refer to a string", psz_name );
141         return NULL;
142     }
143
144     /* return a copy of the string */
145     vlc_mutex_lock( p_config->p_lock );
146     if( p_config->psz_value ) psz_value = strdup( p_config->psz_value );
147     vlc_mutex_unlock( p_config->p_lock );
148
149     return psz_value;
150 }
151
152 /*****************************************************************************
153  * config_PutPsz: set the string value of a string variable
154  *****************************************************************************
155  * This function is used to set the value of variables which are internally
156  * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_FILE,
157  * and CONFIG_ITEM_MODULE).
158  *****************************************************************************/
159 void __config_PutPsz( vlc_object_t *p_this, 
160                       const char *psz_name, const char *psz_value )
161 {
162     module_config_t *p_config;
163
164     p_config = config_FindConfig( p_this, psz_name );
165
166     /* sanity checks */
167     if( !p_config )
168     {
169         msg_Err( p_this, "option %s does not exist", psz_name );
170         return;
171     }
172     if( (p_config->i_type!=CONFIG_ITEM_STRING) &&
173         (p_config->i_type!=CONFIG_ITEM_FILE) &&
174         (p_config->i_type!=CONFIG_ITEM_MODULE) )
175     {
176         msg_Err( p_this, "option %s does not refer to a string", psz_name );
177         return;
178     }
179
180     vlc_mutex_lock( p_config->p_lock );
181
182     /* free old string */
183     if( p_config->psz_value ) free( p_config->psz_value );
184
185     if( psz_value ) p_config->psz_value = strdup( psz_value );
186     else p_config->psz_value = NULL;
187
188     vlc_mutex_unlock( p_config->p_lock );
189
190     if( p_config->pf_callback )
191     {
192         p_config->pf_callback( p_this );
193     }
194 }
195
196 /*****************************************************************************
197  * config_PutInt: set the integer value of an int variable
198  *****************************************************************************
199  * This function is used to set the value of variables which are internally
200  * represented by an integer (CONFIG_ITEM_INTEGER and
201  * CONFIG_ITEM_BOOL).
202  *****************************************************************************/
203 void __config_PutInt( vlc_object_t *p_this, const char *psz_name, int i_value )
204 {
205     module_config_t *p_config;
206
207     p_config = config_FindConfig( p_this, psz_name );
208
209     /* sanity checks */
210     if( !p_config )
211     {
212         msg_Err( p_this, "option %s does not exist", psz_name );
213         return;
214     }
215     if( (p_config->i_type!=CONFIG_ITEM_INTEGER) &&
216         (p_config->i_type!=CONFIG_ITEM_BOOL) )
217     {
218         msg_Err( p_this, "option %s does not refer to an int", psz_name );
219         return;
220     }
221
222     p_config->i_value = i_value;
223
224     if( p_config->pf_callback )
225     {
226         p_config->pf_callback( p_this );
227     }
228 }
229
230 /*****************************************************************************
231  * config_PutFloat: set the value of a float variable
232  *****************************************************************************
233  * This function is used to set the value of variables which are internally
234  * represented by a float (CONFIG_ITEM_FLOAT).
235  *****************************************************************************/
236 void __config_PutFloat( vlc_object_t *p_this,
237                         const char *psz_name, float f_value )
238 {
239     module_config_t *p_config;
240
241     p_config = config_FindConfig( p_this, psz_name );
242
243     /* sanity checks */
244     if( !p_config )
245     {
246         msg_Err( p_this, "option %s does not exist", psz_name );
247         return;
248     }
249     if( p_config->i_type != CONFIG_ITEM_FLOAT )
250     {
251         msg_Err( p_this, "option %s does not refer to a float", psz_name );
252         return;
253     }
254
255     p_config->f_value = f_value;
256
257     if( p_config->pf_callback )
258     {
259         p_config->pf_callback( p_this );
260     }
261 }
262
263 /*****************************************************************************
264  * config_FindConfig: find the config structure associated with an option.
265  *****************************************************************************
266  * FIXME: This function really needs to be optimized.
267  * FIXME: And now even more.
268  *****************************************************************************/
269 module_config_t *config_FindConfig( vlc_object_t *p_this, const char *psz_name )
270 {
271     vlc_list_t *p_list; 
272     module_t **pp_parser;
273     module_config_t *p_item;
274
275     if( !psz_name ) return NULL;
276
277     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
278
279     for( pp_parser = (module_t **)p_list->pp_objects ;
280          *pp_parser ;
281          pp_parser++ )
282     {
283         if( !(*pp_parser)->i_config_items )
284             continue;
285
286         for( p_item = (*pp_parser)->p_config;
287              p_item->i_type != CONFIG_HINT_END;
288              p_item++ )
289         {
290             if( p_item->i_type & CONFIG_HINT )
291                 /* ignore hints */
292                 continue;
293             if( !strcmp( psz_name, p_item->psz_name ) )
294             {
295                 vlc_list_release( p_list );
296                 return p_item;
297             }
298         }
299     }
300
301     vlc_list_release( p_list );
302
303     return NULL;
304 }
305
306 /*****************************************************************************
307  * config_Duplicate: creates a duplicate of a module's configuration data.
308  *****************************************************************************
309  * Unfortunatly we cannot work directly with the module's config data as
310  * this module might be unloaded from memory at any time (remember HideModule).
311  * This is why we need to create an exact copy of the config data.
312  *****************************************************************************/
313 void config_Duplicate( module_t *p_module, module_config_t *p_orig )
314 {
315     int i, j, i_lines = 1;
316     module_config_t *p_item;
317
318     /* Calculate the structure length */
319     p_module->i_config_items = 0;
320     p_module->i_bool_items = 0;
321
322     for( p_item = p_orig; p_item->i_type != CONFIG_HINT_END; p_item++ )
323     {
324         i_lines++;
325
326         if( p_item->i_type & CONFIG_ITEM )
327         {
328             p_module->i_config_items++;
329         }
330
331         if( p_item->i_type == CONFIG_ITEM_BOOL )
332         {
333             p_module->i_bool_items++;
334         }
335     }
336
337     /* Allocate memory */
338     p_module->p_config = (module_config_t *)malloc( sizeof(module_config_t)
339                                                      * i_lines );
340     if( p_module->p_config == NULL )
341     {
342         msg_Err( p_module, "config error: can't duplicate p_config" );
343         return;
344     }
345
346     /* Do the duplication job */
347     for( i = 0; i < i_lines ; i++ )
348     {
349         p_module->p_config[i].i_type = p_orig[i].i_type;
350         p_module->p_config[i].i_short = p_orig[i].i_short;
351         p_module->p_config[i].i_value = p_orig[i].i_value;
352         p_module->p_config[i].f_value = p_orig[i].f_value;
353         p_module->p_config[i].b_dirty = p_orig[i].b_dirty;
354
355         p_module->p_config[i].psz_type = p_orig[i].psz_type ?
356                                    strdup( _(p_orig[i].psz_type) ) : NULL;
357         p_module->p_config[i].psz_name = p_orig[i].psz_name ?
358                                    strdup( _(p_orig[i].psz_name) ) : NULL;
359         p_module->p_config[i].psz_text = p_orig[i].psz_text ?
360                                    strdup( _(p_orig[i].psz_text) ) : NULL;
361         p_module->p_config[i].psz_longtext = p_orig[i].psz_longtext ?
362                                    strdup( _(p_orig[i].psz_longtext) ) : NULL;
363         p_module->p_config[i].psz_value = p_orig[i].psz_value ?
364                                    strdup( p_orig[i].psz_value ) : NULL;
365
366         p_module->p_config[i].p_lock = &p_module->object_lock;
367
368         /* duplicate the string list */
369         p_module->p_config[i].ppsz_list = NULL;
370         if( p_orig[i].ppsz_list )
371         {
372             for( j = 0; p_orig[i].ppsz_list[j]; j++ );
373             p_module->p_config[i].ppsz_list = malloc( (j+1) *sizeof(char *) );
374             if( p_module->p_config[i].ppsz_list )
375             {
376                 for( j = 0; p_orig[i].ppsz_list[j]; j++ )
377                     p_module->p_config[i].ppsz_list[j] =
378                         strdup( p_orig[i].ppsz_list[j] );
379             }
380             p_module->p_config[i].ppsz_list[j] = NULL;
381         }
382
383         p_module->p_config[i].pf_callback = p_orig[i].pf_callback;
384     }
385 }
386
387 /*****************************************************************************
388  * config_Free: frees a duplicated module's configuration data.
389  *****************************************************************************
390  * This function frees all the data duplicated by config_Duplicate.
391  *****************************************************************************/
392 void config_Free( module_t *p_module )
393 {
394     module_config_t *p_item = p_module->p_config;
395     int i;
396
397     if( p_item == NULL )
398     {
399         return;
400     }
401
402     for( ; p_item->i_type != CONFIG_HINT_END ; p_item++ )
403     {
404         if( p_item->psz_type )
405             free( p_item->psz_type );
406
407         if( p_item->psz_name )
408             free( p_item->psz_name );
409
410         if( p_item->psz_text )
411             free( p_item->psz_text );
412
413         if( p_item->psz_longtext )
414             free( p_item->psz_longtext );
415
416         if( p_item->psz_value )
417             free( p_item->psz_value );
418
419         if( p_item->ppsz_list )
420         {
421             for( i = 0; p_item->ppsz_list[i]; i++ )
422                 free(p_item->ppsz_list[i]);
423             free( p_item->ppsz_list );
424         }
425     }
426
427     free( p_module->p_config );
428     p_module->p_config = NULL;
429 }
430
431 /*****************************************************************************
432  * config_SetCallbacks: sets callback functions in the duplicate p_config.
433  *****************************************************************************
434  * Unfortunatly we cannot work directly with the module's config data as
435  * this module might be unloaded from memory at any time (remember HideModule).
436  * This is why we need to duplicate callbacks each time we reload the module.
437  *****************************************************************************/
438 void config_SetCallbacks( module_config_t *p_new, module_config_t *p_orig )
439 {
440     while( p_new->i_type != CONFIG_HINT_END )
441     {
442         p_new->pf_callback = p_orig->pf_callback;
443         p_new++;
444         p_orig++;
445     }
446 }
447
448 /*****************************************************************************
449  * config_UnsetCallbacks: unsets callback functions in the duplicate p_config.
450  *****************************************************************************
451  * We simply undo what we did in config_SetCallbacks.
452  *****************************************************************************/
453 void config_UnsetCallbacks( module_config_t *p_new )
454 {
455     while( p_new->i_type != CONFIG_HINT_END )
456     {
457         p_new->pf_callback = NULL;
458         p_new++;
459     }
460 }
461
462 /*****************************************************************************
463  * config_LoadConfigFile: loads the configuration file.
464  *****************************************************************************
465  * This function is called to load the config options stored in the config
466  * file.
467  *****************************************************************************/
468 int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
469 {
470     vlc_list_t *p_list; 
471     module_t **pp_parser;
472     module_config_t *p_item;
473     FILE *file;
474     char line[1024];
475     char *p_index, *psz_option_name, *psz_option_value;
476     char *psz_filename, *psz_homedir;
477
478     psz_homedir = p_this->p_vlc->psz_homedir;
479     if( !psz_homedir )
480     {
481         msg_Err( p_this, "psz_homedir is null" );
482         return -1;
483     }
484     psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
485                                    strlen(psz_homedir) + 1 );
486     if( !psz_filename )
487     {
488         msg_Err( p_this, "out of memory" );
489         return -1;
490     }
491     sprintf( psz_filename, "%s/" CONFIG_DIR "/" CONFIG_FILE, psz_homedir );
492
493     msg_Dbg( p_this, "opening config file %s", psz_filename );
494
495     /* Acquire config file lock */
496     vlc_mutex_lock( &p_this->p_vlc->config_lock );
497
498     file = fopen( psz_filename, "rt" );
499     if( !file )
500     {
501         msg_Warn( p_this, "config file %s does not exist yet", psz_filename );
502         free( psz_filename );
503         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
504         return -1;
505     }
506
507     /* Look for the selected module, if NULL then save everything */
508     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
509
510     for( pp_parser = (module_t **)p_list->pp_objects ;
511          *pp_parser ;
512          pp_parser++ )
513     {
514
515         if( psz_module_name
516              && strcmp( psz_module_name, (*pp_parser)->psz_object_name ) )
517         {
518             continue;
519         }
520
521         /* The config file is organized in sections, one per module. Look for
522          * the interesting section ( a section is of the form [foo] ) */
523         fseek( file, 0L, SEEK_SET );
524         while( fgets( line, 1024, file ) )
525         {
526             if( (line[0] == '[')
527                && (p_index = strchr(line,']'))
528                && (p_index - &line[1] == strlen((*pp_parser)->psz_object_name))
529                && !memcmp( &line[1], (*pp_parser)->psz_object_name,
530                            strlen((*pp_parser)->psz_object_name) ) )
531             {
532 #if 0
533                 msg_Dbg( p_this, "loading config for module \"%s\"",
534                                  (*pp_parser)->psz_object_name );
535 #endif
536
537                 break;
538             }
539         }
540         /* either we found the section or we're at the EOF */
541
542         /* Now try to load the options in this section */
543         while( fgets( line, 1024, file ) )
544         {
545             if( line[0] == '[' ) break; /* end of section */
546
547             /* ignore comments or empty lines */
548             if( (line[0] == '#') || (line[0] == '\n') || (line[0] == (char)0) )
549                 continue;
550
551             /* get rid of line feed */
552             if( line[strlen(line)-1] == '\n' )
553                 line[strlen(line)-1] = (char)0;
554
555             /* look for option name */
556             psz_option_name = line;
557             psz_option_value = NULL;
558             p_index = strchr( line, '=' );
559             if( !p_index ) break; /* this ain't an option!!! */
560
561             *p_index = (char)0;
562             psz_option_value = p_index + 1;
563
564             if( !(*pp_parser)->i_config_items )
565             {
566                 continue;
567             }
568
569             /* try to match this option with one of the module's options */
570             for( p_item = (*pp_parser)->p_config;
571                  p_item->i_type != CONFIG_HINT_END;
572                  p_item++ )
573             {
574                 if( p_item->i_type & CONFIG_HINT )
575                     /* ignore hints */
576                     continue;
577
578                 if( !strcmp( p_item->psz_name, psz_option_name ) )
579                 {
580                     /* We found it */
581                     switch( p_item->i_type )
582                     {
583                     case CONFIG_ITEM_BOOL:
584                     case CONFIG_ITEM_INTEGER:
585                         if( !*psz_option_value )
586                             break;                    /* ignore empty option */
587                         p_item->i_value = atoi( psz_option_value);
588 #if 0
589                         msg_Dbg( p_this, "option \"%s\", value %i",
590                                  p_item->psz_name, p_item->i_value );
591 #endif
592                         break;
593
594                     case CONFIG_ITEM_FLOAT:
595                         if( !*psz_option_value )
596                             break;                    /* ignore empty option */
597                         p_item->f_value = (float)atof( psz_option_value);
598 #if O
599                         msg_Dbg( p_this, "option \"%s\", value %f",
600                                  p_item->psz_name, (double)p_item->f_value );
601 #endif
602                         break;
603
604                     default:
605                         vlc_mutex_lock( p_item->p_lock );
606
607                         /* free old string */
608                         if( p_item->psz_value )
609                             free( p_item->psz_value );
610
611                         p_item->psz_value = *psz_option_value ?
612                             strdup( psz_option_value ) : NULL;
613
614                         vlc_mutex_unlock( p_item->p_lock );
615
616 #if 0
617                         msg_Dbg( p_this, "option \"%s\", value \"%s\"",
618                                  p_item->psz_name,
619                                  p_item->psz_value ? p_item->psz_value : "" );
620 #endif
621                         break;
622                     }
623                 }
624             }
625         }
626
627     }
628     
629     vlc_list_release( p_list );
630
631     fclose( file );
632     free( psz_filename );
633
634     vlc_mutex_unlock( &p_this->p_vlc->config_lock );
635
636     return 0;
637 }
638
639 /*****************************************************************************
640  * config_SaveConfigFile: Save a module's config options.
641  *****************************************************************************
642  * This will save the specified module's config options to the config file.
643  * If psz_module_name is NULL then we save all the modules config options.
644  * It's no use to save the config options that kept their default values, so
645  * we'll try to be a bit clever here.
646  *
647  * When we save we mustn't delete the config options of the modules that
648  * haven't been loaded. So we cannot just create a new config file with the
649  * config structures we've got in memory. 
650  * I don't really know how to deal with this nicely, so I will use a completly
651  * dumb method ;-)
652  * I will load the config file in memory, but skipping all the sections of the
653  * modules we want to save. Then I will create a brand new file, dump the file
654  * loaded in memory and then append the sections of the modules we want to
655  * save.
656  * Really stupid no ?
657  *****************************************************************************/
658 int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name )
659 {
660     module_t **pp_parser;
661     vlc_list_t *p_list;
662     module_config_t *p_item;
663     FILE *file;
664     char p_line[1024], *p_index2;
665     int i_sizebuf = 0;
666     char *p_bigbuffer, *p_index;
667     vlc_bool_t b_backup;
668     char *psz_filename, *psz_homedir;
669
670     /* Acquire config file lock */
671     vlc_mutex_lock( &p_this->p_vlc->config_lock );
672
673     psz_homedir = p_this->p_vlc->psz_homedir;
674     if( !psz_homedir )
675     {
676         msg_Err( p_this, "psz_homedir is null" );
677         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
678         return -1;
679     }
680     psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
681                                    strlen(psz_homedir) + 1 );
682     if( !psz_filename )
683     {
684         msg_Err( p_this, "out of memory" );
685         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
686         return -1;
687     }
688     sprintf( psz_filename, "%s/" CONFIG_DIR, psz_homedir );
689
690 #if defined( UNDER_CE )
691     {
692         wchar_t psz_new[ MAX_PATH ];
693         MultiByteToWideChar( CP_ACP, 0, psz_filename, -1, psz_new, MAX_PATH );
694         if( CreateDirectory( psz_new, NULL ) )
695         {
696             msg_Err( p_this, "could not create %s", psz_filename );
697         }
698     }
699
700 #elif defined( HAVE_ERRNO_H )
701 #   if defined( WIN32 )
702     if( mkdir( psz_filename ) && errno != EEXIST )
703 #   else
704     if( mkdir( psz_filename, 0755 ) && errno != EEXIST )
705 #   endif
706     {
707         msg_Err( p_this, "could not create %s (%s)",
708                          psz_filename, strerror(errno) );
709     }
710
711 #else
712     if( mkdir( psz_filename ) )
713     {
714         msg_Err( p_this, "could not create %s", psz_filename );
715     }
716
717 #endif
718
719     strcat( psz_filename, "/" CONFIG_FILE );
720
721
722     msg_Dbg( p_this, "opening config file %s", psz_filename );
723
724     file = fopen( psz_filename, "rt" );
725     if( !file )
726     {
727         msg_Warn( p_this, "config file %s does not exist yet", psz_filename );
728     }
729     else
730     {
731         /* look for file size */
732         fseek( file, 0L, SEEK_END );
733         i_sizebuf = ftell( file );
734         fseek( file, 0L, SEEK_SET );
735     }
736
737     p_bigbuffer = p_index = malloc( i_sizebuf+1 );
738     if( !p_bigbuffer )
739     {
740         msg_Err( p_this, "out of memory" );
741         if( file ) fclose( file );
742         free( psz_filename );
743         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
744         return -1;
745     }
746     p_bigbuffer[0] = 0;
747
748     /* List all available modules */
749     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
750
751     /* backup file into memory, we only need to backup the sections we won't
752      * save later on */
753     b_backup = 0;
754     while( file && fgets( p_line, 1024, file ) )
755     {
756         if( (p_line[0] == '[') && (p_index2 = strchr(p_line,']')))
757         {
758
759             /* we found a section, check if we need to do a backup */
760             for( pp_parser = (module_t **)p_list->pp_objects ;
761                  *pp_parser ;
762                  pp_parser++ )
763             {
764                 if( ((p_index2 - &p_line[1])
765                        == strlen((*pp_parser)->psz_object_name) ) &&
766                     !memcmp( &p_line[1], (*pp_parser)->psz_object_name,
767                              strlen((*pp_parser)->psz_object_name) ) )
768                 {
769                     if( !psz_module_name )
770                         break;
771                     else if( !strcmp( psz_module_name,
772                                       (*pp_parser)->psz_object_name ) )
773                         break;
774                 }
775             }
776
777             if( !(*pp_parser) )
778             {
779                 /* we don't have this section in our list so we need to back
780                  * it up */
781                 *p_index2 = 0;
782                 msg_Dbg( p_this, "backing up config for unknown module \"%s\"",
783                                  &p_line[1] );
784                 *p_index2 = ']';
785
786                 b_backup = 1;
787             }
788             else
789             {
790                 b_backup = 0;
791             }
792         }
793
794         /* save line if requested and line is valid (doesn't begin with a
795          * space, tab, or eol) */
796         if( b_backup && (p_line[0] != '\n') && (p_line[0] != ' ')
797             && (p_line[0] != '\t') )
798         {
799             strcpy( p_index, p_line );
800             p_index += strlen( p_line );
801         }
802     }
803     if( file ) fclose( file );
804
805
806     /*
807      * Save module config in file
808      */
809
810     file = fopen( psz_filename, "wt" );
811     if( !file )
812     {
813         msg_Warn( p_this, "could not open config file %s for writing",
814                           psz_filename );
815         free( psz_filename );
816         vlc_list_release( p_list );
817         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
818         return -1;
819     }
820
821     fprintf( file, "###\n###  " COPYRIGHT_MESSAGE "\n###\n\n" );
822
823     /* Look for the selected module, if NULL then save everything */
824     for( pp_parser = (module_t **)p_list->pp_objects ;
825          *pp_parser ;
826          pp_parser++ )
827     {
828
829         if( psz_module_name && strcmp( psz_module_name,
830                                        (*pp_parser)->psz_object_name ) )
831             continue;
832
833         if( !(*pp_parser)->i_config_items )
834             continue;
835
836         msg_Dbg( p_this, "saving config for module \"%s\"",
837                          (*pp_parser)->psz_object_name );
838
839         fprintf( file, "[%s]", (*pp_parser)->psz_object_name );
840         if( (*pp_parser)->psz_longname )
841             fprintf( file, " # %s\n\n", (*pp_parser)->psz_longname );
842         else
843             fprintf( file, "\n\n" );
844
845         for( p_item = (*pp_parser)->p_config;
846              p_item->i_type != CONFIG_HINT_END;
847              p_item++ )
848         {
849             if( p_item->i_type & CONFIG_HINT )
850                 /* ignore hints */
851                 continue;
852
853             switch( p_item->i_type )
854             {
855             case CONFIG_ITEM_BOOL:
856             case CONFIG_ITEM_INTEGER:
857                 if( p_item->psz_text )
858                     fprintf( file, "# %s (%s)\n", p_item->psz_text,
859                              (p_item->i_type == CONFIG_ITEM_BOOL) ?
860                              _("boolean") : _("integer") );
861                 fprintf( file, "%s=%i\n", p_item->psz_name, p_item->i_value );
862                 break;
863
864             case CONFIG_ITEM_FLOAT:
865                 if( p_item->psz_text )
866                     fprintf( file, "# %s (%s)\n", p_item->psz_text,
867                              _("float") );
868                 fprintf( file, "%s=%f\n", p_item->psz_name,
869                          (double)p_item->f_value );
870                 break;
871
872             default:
873                 if( p_item->psz_text )
874                     fprintf( file, "# %s (%s)\n", p_item->psz_text,
875                              _("string") );
876                 fprintf( file, "%s=%s\n", p_item->psz_name,
877                          p_item->psz_value ? p_item->psz_value : "" );
878             }
879         }
880
881         fprintf( file, "\n" );
882     }
883
884     vlc_list_release( p_list );
885
886     /*
887      * Restore old settings from the config in file
888      */
889     fputs( p_bigbuffer, file );
890     free( p_bigbuffer );
891
892     fclose( file );
893     free( psz_filename );
894     vlc_mutex_unlock( &p_this->p_vlc->config_lock );
895
896     return 0;
897 }
898
899 /*****************************************************************************
900  * config_LoadCmdLine: parse command line
901  *****************************************************************************
902  * Parse command line for configuration options.
903  * Now that the module_bank has been initialized, we can dynamically
904  * generate the longopts structure used by getops. We have to do it this way
905  * because we don't know (and don't want to know) in advance the configuration
906  * options used (ie. exported) by each module.
907  *****************************************************************************/
908 int __config_LoadCmdLine( vlc_object_t *p_this, int *pi_argc, char *ppsz_argv[],
909                           vlc_bool_t b_ignore_errors )
910 {
911     int i_cmd, i_index, i_opts, i_shortopts, flag, i_verbose = 0;
912     module_t **pp_parser;
913     vlc_list_t *p_list;
914     module_config_t *p_item;
915     struct option *p_longopts;
916
917     /* Short options */
918     module_config_t *pp_shortopts[256];
919     char *psz_shortopts;
920
921     /* Set default configuration and copy arguments */
922     p_this->p_vlc->i_argc    = *pi_argc;
923     p_this->p_vlc->ppsz_argv = ppsz_argv;
924
925     p_this->p_vlc->p_channel = NULL;
926
927 #ifdef SYS_DARWIN
928     /* When vlc.app is run by double clicking in Mac OS X, the 2nd arg
929      * is the PSN - process serial number (a unique PID-ish thingie)
930      * still ok for real Darwin & when run from command line */
931     if ( (*pi_argc > 1) && (strncmp( ppsz_argv[ 1 ] , "-psn" , 4 ) == 0) )
932                                         /* for example -psn_0_9306113 */
933     {
934         /* GDMF!... I can't do this or else the MacOSX window server will
935          * not pick up the PSN and not register the app and we crash...
936          * hence the following kludge otherwise we'll get confused w/ argv[1]
937          * being an input file name */
938 #if 0
939         ppsz_argv[ 1 ] = NULL;
940 #endif
941         *pi_argc = *pi_argc - 1;
942         pi_argc--;
943         return 0;
944     }
945 #endif
946
947     /* List all modules */
948     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
949
950     /*
951      * Generate the longopts and shortopts structures used by getopt_long
952      */
953
954     i_opts = 0;
955     for( pp_parser = (module_t **)p_list->pp_objects ;
956          *pp_parser ;
957          pp_parser++ )
958     {
959         /* count the number of exported configuration options (to allocate
960          * longopts). We also need to allocate space for too options when
961          * dealing with boolean to allow for --foo and --no-foo */
962         i_opts += (*pp_parser)->i_config_items
963                      + 2 * (*pp_parser)->i_bool_items;
964     }
965
966     p_longopts = malloc( sizeof(struct option) * (i_opts + 1) );
967     if( p_longopts == NULL )
968     {
969         msg_Err( p_this, "out of memory" );
970         vlc_list_release( p_list );
971         return -1;
972     }
973
974     psz_shortopts = malloc( sizeof( char ) * (2 * i_opts + 1) );
975     if( psz_shortopts == NULL )
976     {
977         msg_Err( p_this, "out of memory" );
978         free( p_longopts );
979         vlc_list_release( p_list );
980         return -1;
981     }
982
983     /* If we are requested to ignore errors, then we must work on a copy
984      * of the ppsz_argv array, otherwise getopt_long will reorder it for
985      * us, ignoring the arity of the options */
986     if( b_ignore_errors )
987     {
988         ppsz_argv = (char**)malloc( *pi_argc * sizeof(char *) );
989         if( ppsz_argv == NULL )
990         {
991             msg_Err( p_this, "out of memory" );
992             free( psz_shortopts );
993             free( p_longopts );
994             vlc_list_release( p_list );
995             return -1;
996         }
997         memcpy( ppsz_argv, p_this->p_vlc->ppsz_argv,
998                 *pi_argc * sizeof(char *) );
999     }
1000
1001     i_shortopts = 0;
1002     for( i_index = 0; i_index < 256; i_index++ )
1003     {
1004         pp_shortopts[i_index] = NULL;
1005     }
1006
1007     /* Fill the p_longopts and psz_shortopts structures */
1008     i_index = 0;
1009     for( pp_parser = (module_t **)p_list->pp_objects ;
1010          *pp_parser ;
1011          pp_parser++ )
1012     {
1013         if( !(*pp_parser)->i_config_items )
1014             continue;
1015
1016         for( p_item = (*pp_parser)->p_config;
1017              p_item->i_type != CONFIG_HINT_END;
1018              p_item++ )
1019         {
1020             /* Ignore hints */
1021             if( p_item->i_type & CONFIG_HINT )
1022                 continue;
1023
1024             /* Add item to long options */
1025             p_longopts[i_index].name = strdup( p_item->psz_name );
1026             if( p_longopts[i_index].name == NULL ) continue;
1027             p_longopts[i_index].has_arg =
1028                 (p_item->i_type == CONFIG_ITEM_BOOL)?
1029                                                no_argument : required_argument;
1030             p_longopts[i_index].flag = &flag;
1031             p_longopts[i_index].val = 0;
1032             i_index++;
1033
1034             /* When dealing with bools we also need to add the --no-foo
1035              * option */
1036             if( p_item->i_type == CONFIG_ITEM_BOOL )
1037             {
1038                 char *psz_name = malloc( strlen(p_item->psz_name) + 3 );
1039                 if( psz_name == NULL ) continue;
1040                 strcpy( psz_name, "no" );
1041                 strcat( psz_name, p_item->psz_name );
1042
1043                 p_longopts[i_index].name = psz_name;
1044                 p_longopts[i_index].has_arg = no_argument;
1045                 p_longopts[i_index].flag = &flag;
1046                 p_longopts[i_index].val = 1;
1047                 i_index++;
1048
1049                 psz_name = malloc( strlen(p_item->psz_name) + 4 );
1050                 if( psz_name == NULL ) continue;
1051                 strcpy( psz_name, "no-" );
1052                 strcat( psz_name, p_item->psz_name );
1053
1054                 p_longopts[i_index].name = psz_name;
1055                 p_longopts[i_index].has_arg = no_argument;
1056                 p_longopts[i_index].flag = &flag;
1057                 p_longopts[i_index].val = 1;
1058                 i_index++;
1059             }
1060
1061             /* If item also has a short option, add it */
1062             if( p_item->i_short )
1063             {
1064                 pp_shortopts[(int)p_item->i_short] = p_item;
1065                 psz_shortopts[i_shortopts] = p_item->i_short;
1066                 i_shortopts++;
1067                 if( p_item->i_type != CONFIG_ITEM_BOOL )
1068                 {
1069                     psz_shortopts[i_shortopts] = ':';
1070                     i_shortopts++;
1071
1072                     if( p_item->i_short == 'v' )
1073                     {
1074                         psz_shortopts[i_shortopts] = ':';
1075                         i_shortopts++;
1076                     }
1077                 }
1078             }
1079         }
1080     }
1081
1082     /* We don't need the module list anymore */
1083     vlc_list_release( p_list );
1084
1085     /* Close the longopts and shortopts structures */
1086     memset( &p_longopts[i_index], 0, sizeof(struct option) );
1087     psz_shortopts[i_shortopts] = '\0';
1088
1089     /*
1090      * Parse the command line options
1091      */
1092     opterr = 0;
1093     optind = 1;
1094     while( ( i_cmd = getopt_long( *pi_argc, ppsz_argv, psz_shortopts,
1095                                   p_longopts, &i_index ) ) != EOF )
1096     {
1097         /* A long option has been recognized */
1098         if( i_cmd == 0 )
1099         {
1100             module_config_t *p_conf;
1101             char *psz_name = (char *)p_longopts[i_index].name;
1102
1103             /* Check if we deal with a --nofoo or --no-foo long option */
1104             if( flag ) psz_name += psz_name[2] == '-' ? 3 : 2;
1105
1106             /* Store the configuration option */
1107             p_conf = config_FindConfig( p_this, psz_name );
1108
1109             if( p_conf ) switch( p_conf->i_type )
1110             {
1111             case CONFIG_ITEM_STRING:
1112             case CONFIG_ITEM_FILE:
1113             case CONFIG_ITEM_MODULE:
1114                 config_PutPsz( p_this, psz_name, optarg );
1115                 break;
1116             case CONFIG_ITEM_INTEGER:
1117                 config_PutInt( p_this, psz_name, atoi(optarg));
1118                 break;
1119             case CONFIG_ITEM_FLOAT:
1120                 config_PutFloat( p_this, psz_name, (float)atof(optarg) );
1121                 break;
1122             case CONFIG_ITEM_BOOL:
1123                 config_PutInt( p_this, psz_name, !flag );
1124                 break;
1125             }
1126
1127             continue;
1128         }
1129
1130         /* A short option has been recognized */
1131         if( pp_shortopts[i_cmd] != NULL )
1132         {
1133             switch( pp_shortopts[i_cmd]->i_type )
1134             {
1135             case CONFIG_ITEM_STRING:
1136             case CONFIG_ITEM_FILE:
1137             case CONFIG_ITEM_MODULE:
1138                 config_PutPsz( p_this, pp_shortopts[i_cmd]->psz_name, optarg );
1139                 break;
1140             case CONFIG_ITEM_INTEGER:
1141                 if( i_cmd == 'v' )
1142                 {
1143                     if( optarg )
1144                     {
1145                         if( *optarg == 'v' ) /* eg. -vvv */
1146                         {
1147                             i_verbose++;
1148                             while( *optarg == 'v' )
1149                             {
1150                                 i_verbose++;
1151                                 optarg++;
1152                             }
1153                         }
1154                         else
1155                         {
1156                             i_verbose += atoi( optarg ); /* eg. -v2 */
1157                         }
1158                     }
1159                     else
1160                     {
1161                         i_verbose++; /* -v */
1162                     }
1163                     config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name,
1164                                            i_verbose );
1165                 }
1166                 else
1167                 {
1168                     config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name,
1169                                            atoi(optarg) );
1170                 }
1171                 break;
1172             case CONFIG_ITEM_BOOL:
1173                 config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name, 1 );
1174                 break;
1175             }
1176
1177             continue;
1178         }
1179
1180         /* Internal error: unknown option */
1181         if( !b_ignore_errors )
1182         {
1183             fprintf( stderr, "unknown option `%s'\n", ppsz_argv[optind-1] );
1184             fprintf( stderr, "Try `%s --help' for more information.\n",
1185                              p_this->p_vlc->psz_object_name );
1186
1187             free( p_longopts );
1188             free( psz_shortopts );
1189             if( b_ignore_errors ) free( ppsz_argv );
1190             return -1;
1191         }
1192     }
1193
1194     /* Free allocated resources */
1195     for( i_index = 0; p_longopts[i_index].name; i_index++ )
1196         free( (char *)p_longopts[i_index].name );
1197     free( p_longopts );
1198     free( psz_shortopts );
1199     if( b_ignore_errors ) free( ppsz_argv );
1200
1201     return 0;
1202 }
1203
1204 /*****************************************************************************
1205  * config_GetHomeDir: find the user's home directory.
1206  *****************************************************************************
1207  * This function will try by different ways to find the user's home path.
1208  * Note that this function is not reentrant, it should be called only once
1209  * at the beginning of main where the result will be stored for later use.
1210  *****************************************************************************/
1211 char *config_GetHomeDir( void )
1212 {
1213     char *p_tmp, *p_homedir = NULL;
1214
1215 #if defined(HAVE_GETPWUID)
1216     struct passwd *p_pw = NULL;
1217 #endif
1218
1219 #ifdef WIN32
1220     typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
1221                                                LPTSTR );
1222 #   define CSIDL_FLAG_CREATE 0x8000
1223 #   define CSIDL_APPDATA 0x1A
1224 #   define SHGFP_TYPE_CURRENT 0
1225
1226     HINSTANCE shfolder_dll;
1227     SHGETFOLDERPATH SHGetFolderPath ;
1228
1229     /* load the shell32 dll to retreive SHGetFolderPath */
1230     if( ( shfolder_dll = LoadLibrary("shfolder.dll") ) != NULL )
1231     {
1232         SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
1233                                                   "SHGetFolderPathA" );
1234         if ( SHGetFolderPath != NULL )
1235         {
1236             p_homedir = (char *)malloc( MAX_PATH );
1237             if( !p_homedir )
1238             {
1239                 return NULL;
1240             }
1241
1242             /* get the "Application Data" folder for the current user */
1243             if( S_OK == SHGetFolderPath( NULL,
1244                                          CSIDL_APPDATA | CSIDL_FLAG_CREATE,
1245                                          NULL, SHGFP_TYPE_CURRENT,
1246                                          p_homedir ) )
1247             {
1248                 FreeLibrary( shfolder_dll );
1249                 return p_homedir;
1250             }
1251             free( p_homedir );
1252         }
1253         FreeLibrary( shfolder_dll );
1254     }
1255 #endif
1256
1257 #if defined(HAVE_GETPWUID)
1258     if( ( p_pw = getpwuid( getuid() ) ) == NULL )
1259 #endif
1260     {
1261         if( ( p_tmp = getenv( "HOME" ) ) == NULL )
1262         {
1263             if( ( p_tmp = getenv( "TMP" ) ) == NULL )
1264             {
1265                 p_tmp = "/tmp";
1266             }
1267         }
1268
1269         p_homedir = strdup( p_tmp );
1270     }
1271 #if defined(HAVE_GETPWUID)
1272     else
1273     {
1274         p_homedir = strdup( p_pw->pw_dir );
1275     }
1276 #endif
1277
1278     return p_homedir;
1279 }