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