* added config_GetFloatVariable() and config_PutFloatVariable() to the config
[vlc.git] / 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.16 2002/04/21 11:23:03 gbazin 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 <videolan/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 "GNUgetopt/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_GetIntVariable: 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 (MODULE_CONFIG_ITEM_INTEGER and
55  * MODULE_CONFIG_ITEM_BOOL).
56  *****************************************************************************/
57 int config_GetIntVariable( const char *psz_name )
58 {
59     module_config_t *p_config;
60
61     p_config = config_FindConfig( psz_name );
62
63     /* sanity checks */
64     if( !p_config )
65     {
66         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
67         return -1;
68     }
69     if( (p_config->i_type!=MODULE_CONFIG_ITEM_INTEGER) &&
70         (p_config->i_type!=MODULE_CONFIG_ITEM_BOOL) )
71     {
72         intf_ErrMsg( "config error: option %s doesn't refer to an int",
73                      psz_name );
74         return -1;
75     }
76
77     return p_config->i_value;
78 }
79
80 /*****************************************************************************
81  * config_GetFloatVariable: get the value of a float variable
82  *****************************************************************************
83  * This function is used to get the value of variables which are internally
84  * represented by a float (MODULE_CONFIG_ITEM_FLOAT).
85  *****************************************************************************/
86 float config_GetFloatVariable( const char *psz_name )
87 {
88     module_config_t *p_config;
89
90     p_config = config_FindConfig( psz_name );
91
92     /* sanity checks */
93     if( !p_config )
94     {
95         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
96         return -1;
97     }
98     if( p_config->i_type != MODULE_CONFIG_ITEM_FLOAT )
99     {
100         intf_ErrMsg( "config error: option %s doesn't refer to a float",
101                      psz_name );
102         return -1;
103     }
104
105     return p_config->f_value;
106 }
107
108 /*****************************************************************************
109  * config_GetPszVariable: get the string value of a string variable
110  *****************************************************************************
111  * This function is used to get the value of variables which are internally
112  * represented by a string (MODULE_CONFIG_ITEM_STRING, MODULE_CONFIG_ITEM_FILE,
113  * and MODULE_CONFIG_ITEM_PLUGIN).
114  *
115  * Important note: remember to free() the returned char* because it a duplicate
116  *   of the actual value. It isn't safe to return a pointer to the actual value
117  *   as it can be modified at any time.
118  *****************************************************************************/
119 char * config_GetPszVariable( const char *psz_name )
120 {
121     module_config_t *p_config;
122     char *psz_value = NULL;
123
124     p_config = config_FindConfig( psz_name );
125
126     /* sanity checks */
127     if( !p_config )
128     {
129         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
130         return NULL;
131     }
132     if( (p_config->i_type!=MODULE_CONFIG_ITEM_STRING) &&
133         (p_config->i_type!=MODULE_CONFIG_ITEM_FILE) &&
134         (p_config->i_type!=MODULE_CONFIG_ITEM_PLUGIN) )
135     {
136         intf_ErrMsg( "config error: option %s doesn't refer to a string",
137                      psz_name );
138         return NULL;
139     }
140
141     /* return a copy of the string */
142     vlc_mutex_lock( p_config->p_lock );
143     if( p_config->psz_value ) psz_value = strdup( p_config->psz_value );
144     vlc_mutex_unlock( p_config->p_lock );
145
146     return psz_value;
147 }
148
149 /*****************************************************************************
150  * config_PutPszVariable: set the string value of a string variable
151  *****************************************************************************
152  * This function is used to set the value of variables which are internally
153  * represented by a string (MODULE_CONFIG_ITEM_STRING, MODULE_CONFIG_ITEM_FILE,
154  * and MODULE_CONFIG_ITEM_PLUGIN).
155  *****************************************************************************/
156 void config_PutPszVariable( const char *psz_name, char *psz_value )
157 {
158     module_config_t *p_config;
159
160     p_config = config_FindConfig( psz_name );
161
162     /* sanity checks */
163     if( !p_config )
164     {
165         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
166         return;
167     }
168     if( (p_config->i_type!=MODULE_CONFIG_ITEM_STRING) &&
169         (p_config->i_type!=MODULE_CONFIG_ITEM_FILE) &&
170         (p_config->i_type!=MODULE_CONFIG_ITEM_PLUGIN) )
171     {
172         intf_ErrMsg( "config error: option %s doesn't refer to a string",
173                      psz_name );
174         return;
175     }
176
177     vlc_mutex_lock( p_config->p_lock );
178
179     /* free old string */
180     if( p_config->psz_value ) free( p_config->psz_value );
181
182     if( psz_value ) p_config->psz_value = strdup( psz_value );
183     else p_config->psz_value = NULL;
184
185     vlc_mutex_unlock( p_config->p_lock );
186
187 }
188
189 /*****************************************************************************
190  * config_PutIntVariable: set the integer value of an int variable
191  *****************************************************************************
192  * This function is used to set the value of variables which are internally
193  * represented by an integer (MODULE_CONFIG_ITEM_INTEGER and
194  * MODULE_CONFIG_ITEM_BOOL).
195  *****************************************************************************/
196 void config_PutIntVariable( const char *psz_name, int i_value )
197 {
198     module_config_t *p_config;
199
200     p_config = config_FindConfig( psz_name );
201
202     /* sanity checks */
203     if( !p_config )
204     {
205         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
206         return;
207     }
208     if( (p_config->i_type!=MODULE_CONFIG_ITEM_INTEGER) &&
209         (p_config->i_type!=MODULE_CONFIG_ITEM_BOOL) )
210     {
211         intf_ErrMsg( "config error: option %s doesn't refer to an int",
212                      psz_name );
213         return;
214     }
215
216     p_config->i_value = i_value;
217 }
218
219 /*****************************************************************************
220  * config_PutFloatVariable: set the value of a float variable
221  *****************************************************************************
222  * This function is used to set the value of variables which are internally
223  * represented by a float (MODULE_CONFIG_ITEM_FLOAT).
224  *****************************************************************************/
225 void config_PutFloatVariable( const char *psz_name, float f_value )
226 {
227     module_config_t *p_config;
228
229     p_config = config_FindConfig( psz_name );
230
231     /* sanity checks */
232     if( !p_config )
233     {
234         intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
235         return;
236     }
237     if( p_config->i_type != MODULE_CONFIG_ITEM_FLOAT )
238     {
239         intf_ErrMsg( "config error: option %s doesn't refer to a float",
240                      psz_name );
241         return;
242     }
243
244     p_config->f_value = f_value;
245 }
246
247 /*****************************************************************************
248  * config_FindConfig: find the config structure associated with an option.
249  *****************************************************************************
250  * FIXME: This function really needs to be optimized.
251  *****************************************************************************/
252 module_config_t *config_FindConfig( const char *psz_name )
253 {
254     module_t *p_module;
255     module_config_t *p_item;
256
257     if( !psz_name ) return NULL;
258
259     for( p_module = p_module_bank->first ;
260          p_module != NULL ;
261          p_module = p_module->next )
262     {
263         for( p_item = p_module->p_config;
264              p_item->i_type != MODULE_CONFIG_HINT_END;
265              p_item++ )
266         {
267             if( p_item->i_type & MODULE_CONFIG_HINT )
268                 /* ignore hints */
269                 continue;
270             if( !strcmp( psz_name, p_item->psz_name ) )
271                 return p_item;
272         }
273     }
274
275     return NULL;
276 }
277
278 /*****************************************************************************
279  * config_Duplicate: creates a duplicate of a module's configuration data.
280  *****************************************************************************
281  * Unfortunatly we cannot work directly with the module's config data as
282  * this module might be unloaded from memory at any time (remember HideModule).
283  * This is why we need to create an exact copy of the config data.
284  *****************************************************************************/
285 module_config_t *config_Duplicate( module_config_t *p_orig )
286 {
287     int i, i_lines;
288     module_config_t *p_config;
289
290     /* Calculate the structure length */
291     for( p_config = p_orig, i_lines = 1;
292          p_config->i_type != MODULE_CONFIG_HINT_END;
293          p_config++, i_lines++ );
294
295     /* Allocate memory */
296     p_config = (module_config_t *)malloc( sizeof(module_config_t) * i_lines );
297     if( p_config == NULL )
298     {
299         intf_ErrMsg( "config error: can't duplicate p_config" );
300         return( NULL );
301     }
302
303     /* Do the duplication job */
304     for( i = 0; i < i_lines ; i++ )
305     {
306         p_config[i].i_type = p_orig[i].i_type;
307         p_config[i].i_value = p_orig[i].i_value;
308         p_config[i].f_value = p_orig[i].f_value;
309         p_config[i].b_dirty = p_orig[i].b_dirty;
310
311         p_config[i].psz_name = p_orig[i].psz_name ?
312                                    strdup( _(p_orig[i].psz_name) ) : NULL;
313         p_config[i].psz_text = p_orig[i].psz_text ?
314                                    strdup( _(p_orig[i].psz_text) ) : NULL;
315         p_config[i].psz_longtext = p_orig[i].psz_longtext ?
316                                    strdup( _(p_orig[i].psz_longtext) ) : NULL;
317         p_config[i].psz_value = p_orig[i].psz_value ?
318                                    strdup( _(p_orig[i].psz_value) ) : NULL;
319
320         /* the callback pointer is only valid when the module is loaded so this
321          * value is set in ActivateModule() and reset in DeactivateModule() */
322         p_config[i].p_callback = NULL;
323     }
324
325     return p_config;
326 }
327
328 /*****************************************************************************
329  * config_LoadConfigFile: loads the configuration file.
330  *****************************************************************************
331  * This function is called to load the config options stored in the config
332  * file.
333  *****************************************************************************/
334 int config_LoadConfigFile( const char *psz_module_name )
335 {
336     module_t *p_module;
337     module_config_t *p_item;
338     FILE *file;
339     char line[1024];
340     char *p_index, *psz_option_name, *psz_option_value;
341     char *psz_filename, *psz_homedir;
342
343     /* Acquire config file lock */
344     vlc_mutex_lock( &p_main->config_lock );
345
346     psz_homedir = p_main->psz_homedir;
347     if( !psz_homedir )
348     {
349         intf_ErrMsg( "config error: p_main->psz_homedir is null" );
350         vlc_mutex_unlock( &p_main->config_lock );
351         return -1;
352     }
353     psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
354                                    strlen(psz_homedir) + 1 );
355     if( !psz_filename )
356     {
357         intf_ErrMsg( "config error: couldn't malloc psz_filename" );
358         vlc_mutex_unlock( &p_main->config_lock );
359         return -1;
360     }
361     sprintf( psz_filename, "%s/" CONFIG_DIR "/" CONFIG_FILE, psz_homedir );
362
363     intf_WarnMsg( 5, "config: opening config file %s", psz_filename );
364
365     file = fopen( psz_filename, "r" );
366     if( !file )
367     {
368         intf_WarnMsg( 1, "config: couldn't open config file %s for reading (%s)",
369                          psz_filename, strerror(errno) );
370         free( psz_filename );
371         vlc_mutex_unlock( &p_main->config_lock );
372         return -1;
373     }
374
375     /* Look for the selected module, if NULL then save everything */
376     for( p_module = p_module_bank->first ; p_module != NULL ;
377          p_module = p_module->next )
378     {
379
380         if( psz_module_name && strcmp( psz_module_name, p_module->psz_name ) )
381             continue;
382
383         /* The config file is organized in sections, one per module. Look for
384          * the interesting section ( a section is of the form [foo] ) */
385         rewind( file );
386         while( fgets( line, 1024, file ) )
387         {
388             if( (line[0] == '[') && (p_index = strchr(line,']')) &&
389                 (p_index - &line[1] == strlen(p_module->psz_name) ) &&
390                 !memcmp( &line[1], p_module->psz_name,
391                          strlen(p_module->psz_name) ) )
392             {
393                 intf_WarnMsg( 5, "config: loading config for module <%s>",
394                                  p_module->psz_name );
395
396                 break;
397             }
398         }
399         /* either we found the section or we're at the EOF */
400
401         /* Now try to load the options in this section */
402         while( fgets( line, 1024, file ) )
403         {
404             if( line[0] == '[' ) break; /* end of section */
405
406             /* ignore comments or empty lines */
407             if( (line[0] == '#') || (line[0] == (char)0) ) continue;
408
409             /* get rid of line feed */
410             if( line[strlen(line)-1] == '\n' )
411                 line[strlen(line)-1] = (char)0;
412
413             /* look for option name */
414             psz_option_name = line;
415             psz_option_value = NULL;
416             p_index = strchr( line, '=' );
417             if( !p_index ) break; /* this ain't an option!!! */
418
419             *p_index = (char)0;
420             psz_option_value = p_index + 1;
421
422             /* try to match this option with one of the module's options */
423             for( p_item = p_module->p_config;
424                  p_item->i_type != MODULE_CONFIG_HINT_END;
425                  p_item++ )
426             {
427                 if( p_item->i_type & MODULE_CONFIG_HINT )
428                     /* ignore hints */
429                     continue;
430
431                 if( !strcmp( p_item->psz_name, psz_option_name ) )
432                 {
433                     /* We found it */
434                     switch( p_item->i_type )
435                     {
436                     case MODULE_CONFIG_ITEM_BOOL:
437                     case MODULE_CONFIG_ITEM_INTEGER:
438                         if( !*psz_option_value )
439                             break;                    /* ignore empty option */
440                         p_item->i_value = atoi( psz_option_value);
441                         intf_WarnMsg( 7, "config: found <%s> option %s=%i",
442                                          p_module->psz_name,
443                                          p_item->psz_name, p_item->i_value );
444                         break;
445
446                     case MODULE_CONFIG_ITEM_FLOAT:
447                         if( !*psz_option_value )
448                             break;                    /* ignore empty option */
449                         p_item->f_value = (float)atof( psz_option_value);
450                         intf_WarnMsg( 7, "config: found <%s> option %s=%f",
451                                          p_module->psz_name, p_item->psz_name,
452                                          (double)p_item->f_value );
453                         break;
454
455                     default:
456                         vlc_mutex_lock( p_item->p_lock );
457
458                         /* free old string */
459                         if( p_item->psz_value )
460                             free( p_item->psz_value );
461
462                         p_item->psz_value = *psz_option_value ?
463                             strdup( psz_option_value ) : NULL;
464
465                         vlc_mutex_unlock( p_item->p_lock );
466
467                         intf_WarnMsg( 7, "config: found <%s> option %s=%s",
468                                          p_module->psz_name,
469                                          p_item->psz_name,
470                                          p_item->psz_value != NULL ?
471                                            p_item->psz_value : "(NULL)" );
472                         break;
473                     }
474                 }
475             }
476         }
477
478     }
479     
480     fclose( file );
481     free( psz_filename );
482
483     vlc_mutex_unlock( &p_main->config_lock );
484
485     return 0;
486 }
487
488 /*****************************************************************************
489  * config_SaveConfigFile: Save a module's config options.
490  *****************************************************************************
491  * This will save the specified module's config options to the config file.
492  * If psz_module_name is NULL then we save all the modules config options.
493  * It's no use to save the config options that kept their default values, so
494  * we'll try to be a bit clever here.
495  *
496  * When we save we mustn't delete the config options of the plugins that
497  * haven't been loaded. So we cannot just create a new config file with the
498  * config structures we've got in memory. 
499  * I don't really know how to deal with this nicely, so I will use a completly
500  * dumb method ;-)
501  * I will load the config file in memory, but skipping all the sections of the
502  * modules we want to save. Then I will create a brand new file, dump the file
503  * loaded in memory and then append the sections of the modules we want to
504  * save.
505  * Really stupid no ?
506  *****************************************************************************/
507 int config_SaveConfigFile( const char *psz_module_name )
508 {
509     module_t *p_module;
510     module_config_t *p_item;
511     FILE *file;
512     char p_line[1024], *p_index2;
513     int i_sizebuf = 0;
514     char *p_bigbuffer, *p_index;
515     boolean_t b_backup;
516     char *psz_filename, *psz_homedir;
517
518     /* Acquire config file lock */
519     vlc_mutex_lock( &p_main->config_lock );
520
521     psz_homedir = p_main->psz_homedir;
522     if( !psz_homedir )
523     {
524         intf_ErrMsg( "config error: p_main->psz_homedir is null" );
525         vlc_mutex_unlock( &p_main->config_lock );
526         return -1;
527     }
528     psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
529                                    strlen(psz_homedir) + 1 );
530     if( !psz_filename )
531     {
532         intf_ErrMsg( "config error: couldn't malloc psz_filename" );
533         vlc_mutex_unlock( &p_main->config_lock );
534         return -1;
535     }
536     sprintf( psz_filename, "%s/" CONFIG_DIR, psz_homedir );
537
538 #ifndef WIN32
539     if( mkdir( psz_filename, 0755 ) && errno != EEXIST )
540 #else
541     if( mkdir( psz_filename ) && errno != EEXIST )
542 #endif
543     {
544         intf_ErrMsg( "config error: couldn't create %s (%s)",
545                      psz_filename, strerror(errno) );
546     }
547
548     strcat( psz_filename, "/" CONFIG_FILE );
549
550
551     intf_WarnMsg( 5, "config: opening config file %s", psz_filename );
552
553     file = fopen( psz_filename, "r" );
554     if( !file )
555     {
556         intf_WarnMsg( 1, "config: couldn't open config file %s for reading (%s)",
557                          psz_filename, strerror(errno) );
558     }
559     else
560     {
561         /* look for file size */
562         fseek( file, 0, SEEK_END );
563         i_sizebuf = ftell( file );
564         rewind( file );
565     }
566
567     p_bigbuffer = p_index = malloc( i_sizebuf+1 );
568     if( !p_bigbuffer )
569     {
570         intf_ErrMsg( "config error: couldn't malloc bigbuffer" );
571         if( file ) fclose( file );
572         free( psz_filename );
573         vlc_mutex_unlock( &p_main->config_lock );
574         return -1;
575     }
576     p_bigbuffer[0] = 0;
577
578     /* backup file into memory, we only need to backup the sections we won't
579      * save later on */
580     b_backup = 0;
581     while( file && fgets( p_line, 1024, file ) )
582     {
583         if( (p_line[0] == '[') && (p_index2 = strchr(p_line,']')))
584         {
585             /* we found a section, check if we need to do a backup */
586             for( p_module = p_module_bank->first; p_module != NULL;
587                  p_module = p_module->next )
588             {
589                 if( ((p_index2 - &p_line[1]) == strlen(p_module->psz_name) ) &&
590                     !memcmp( &p_line[1], p_module->psz_name,
591                              strlen(p_module->psz_name) ) )
592                 {
593                     if( !psz_module_name )
594                         break;
595                     else if( !strcmp( psz_module_name, p_module->psz_name ) )
596                         break;
597                 }
598             }
599
600             if( !p_module )
601             {
602                 /* we don't have this section in our list so we need to back
603                  * it up */
604                 *p_index2 = 0;
605                 intf_WarnMsg( 5, "config: backing up config for "
606                                  "unknown module <%s>", &p_line[1] );
607                 *p_index2 = ']';
608
609                 b_backup = 1;
610             }
611             else
612             {
613                 b_backup = 0;
614             }
615         }
616
617         /* save line if requested and line is valid (doesn't begin with a
618          * space, tab, or eol) */
619         if( b_backup && (p_line[0] != '\n') && (p_line[0] != ' ')
620             && (p_line[0] != '\t') )
621         {
622             strcpy( p_index, p_line );
623             p_index += strlen( p_line );
624         }
625     }
626     if( file ) fclose( file );
627
628
629     /*
630      * Save module config in file
631      */
632
633     file = fopen( psz_filename, "w" );
634     if( !file )
635     {
636         intf_WarnMsg( 1, "config: couldn't open config file %s for writing",
637                          psz_filename );
638         free( psz_filename );
639         vlc_mutex_unlock( &p_main->config_lock );
640         return -1;
641     }
642
643     fprintf( file, "###\n###  " COPYRIGHT_MESSAGE "\n###\n\n" );
644
645     /* Look for the selected module, if NULL then save everything */
646     for( p_module = p_module_bank->first ; p_module != NULL ;
647          p_module = p_module->next )
648     {
649
650         if( psz_module_name && strcmp( psz_module_name, p_module->psz_name ) )
651             continue;
652
653         if( !p_module->i_config_items )
654             continue;
655
656         intf_WarnMsg( 5, "config: saving config for module <%s>",
657                          p_module->psz_name );
658
659         fprintf( file, "[%s]\n", p_module->psz_name );
660
661         if( p_module->psz_longname )
662             fprintf( file, "###\n###  %s\n###\n", p_module->psz_longname );
663
664         for( p_item = p_module->p_config;
665              p_item->i_type != MODULE_CONFIG_HINT_END;
666              p_item++ )
667         {
668             if( p_item->i_type & MODULE_CONFIG_HINT )
669                 /* ignore hints */
670                 continue;
671
672             switch( p_item->i_type )
673             {
674             case MODULE_CONFIG_ITEM_BOOL:
675             case MODULE_CONFIG_ITEM_INTEGER:
676                 if( p_item->psz_text )
677                     fprintf( file, "# %s %s\n", p_item->psz_text,
678                              (p_item->i_type == MODULE_CONFIG_ITEM_BOOL) ?
679                              _("<boolean>") : _("<integer>") );
680                 fprintf( file, "%s=%i\n", p_item->psz_name,
681                          p_item->i_value );
682                 break;
683
684             case MODULE_CONFIG_ITEM_FLOAT:
685                 if( p_item->psz_text )
686                     fprintf( file, _("# %s <float>\n"), p_item->psz_text );
687                 fprintf( file, "%s=%f\n", p_item->psz_name,
688                          (double)p_item->f_value );
689                 break;
690
691             default:
692                 if( p_item->psz_text )
693                     fprintf( file, _("# %s <string>\n"), p_item->psz_text );
694                 fprintf( file, "%s=%s\n", p_item->psz_name,
695                          p_item->psz_value ? p_item->psz_value : "" );
696             }
697         }
698
699         fprintf( file, "\n" );
700     }
701
702
703     /*
704      * Restore old settings from the config in file
705      */
706     fputs( p_bigbuffer, file );
707     free( p_bigbuffer );
708
709     fclose( file );
710     free( psz_filename );
711     vlc_mutex_unlock( &p_main->config_lock );
712
713     return 0;
714 }
715
716 /*****************************************************************************
717  * config_LoadCmdLine: parse command line
718  *****************************************************************************
719  * Parse command line for configuration options.
720  * Now that the module_bank has been initialized, we can dynamically
721  * generate the longopts structure used by getops. We have to do it this way
722  * because we don't know (and don't want to know) in advance the configuration
723  * options used (ie. exported) by each module.
724  *****************************************************************************/
725 int config_LoadCmdLine( int *pi_argc, char *ppsz_argv[],
726                         boolean_t b_ignore_errors )
727 {
728     int i_cmd, i_index, i_longopts_size;
729     module_t *p_module;
730     module_config_t *p_item;
731     struct option *p_longopts;
732
733     /* Short options */
734     const char *psz_shortopts = "hHvlp:";
735
736     /* Set default configuration and copy arguments */
737     p_main->i_argc    = *pi_argc;
738     p_main->ppsz_argv = ppsz_argv;
739
740     p_main->p_channel = NULL;
741
742 #ifdef SYS_DARWIN
743     /* When vlc.app is run by double clicking in Mac OS X, the 2nd arg
744      * is the PSN - process serial number (a unique PID-ish thingie)
745      * still ok for real Darwin & when run from command line */
746     if ( (*pi_argc > 1) && (strncmp( ppsz_argv[ 1 ] , "-psn" , 4 ) == 0) )
747                                         /* for example -psn_0_9306113 */
748     {
749         /* GDMF!... I can't do this or else the MacOSX window server will
750          * not pick up the PSN and not register the app and we crash...
751          * hence the following kludge otherwise we'll get confused w/ argv[1]
752          * being an input file name */
753 #if 0
754         ppsz_argv[ 1 ] = NULL;
755 #endif
756         *pi_argc = *pi_argc - 1;
757         pi_argc--;
758         return( 0 );
759     }
760 #endif
761
762
763     /*
764      * Generate the longopts structure used by getopt_long
765      */
766     i_longopts_size = 0;
767     for( p_module = p_module_bank->first;
768          p_module != NULL ;
769          p_module = p_module->next )
770     {
771         /* count the number of exported configuration options (to allocate
772          * longopts). */
773         i_longopts_size += p_module->i_config_items;
774     }
775
776     p_longopts = (struct option *)malloc( sizeof(struct option)
777                                           * (i_longopts_size + 1) );
778     if( p_longopts == NULL )
779     {
780         intf_ErrMsg( "config error: couldn't allocate p_longopts" );
781         return( -1 );
782     }
783
784     /* Fill the longopts structure */
785     i_index = 0;
786     for( p_module = p_module_bank->first ;
787          p_module != NULL ;
788          p_module = p_module->next )
789     {
790         for( p_item = p_module->p_config;
791              p_item->i_type != MODULE_CONFIG_HINT_END;
792              p_item++ )
793         {
794             if( p_item->i_type & MODULE_CONFIG_HINT )
795                 /* ignore hints */
796                 continue;
797             p_longopts[i_index].name = p_item->psz_name;
798             p_longopts[i_index].has_arg =
799                 (p_item->i_type == MODULE_CONFIG_ITEM_BOOL)?
800                                                no_argument : required_argument;
801             p_longopts[i_index].flag = 0;
802             p_longopts[i_index].val = 0;
803             i_index++;
804         }
805     }
806     /* Close the longopts structure */
807     memset( &p_longopts[i_index], 0, sizeof(struct option) );
808
809
810     /*
811      * Parse the command line options
812      */
813     opterr = 0;
814     optind = 1;
815     while( ( i_cmd = getopt_long( *pi_argc, ppsz_argv, psz_shortopts,
816                                   p_longopts, &i_index ) ) != EOF )
817     {
818
819         if( i_cmd == 0 )
820         {
821             /* A long option has been recognized */
822
823             module_config_t *p_conf;
824
825             /* Store the configuration option */
826             p_conf = config_FindConfig( p_longopts[i_index].name );
827
828             switch( p_conf->i_type )
829             {
830             case MODULE_CONFIG_ITEM_STRING:
831             case MODULE_CONFIG_ITEM_FILE:
832             case MODULE_CONFIG_ITEM_PLUGIN:
833                 config_PutPszVariable( p_longopts[i_index].name, optarg );
834                 break;
835             case MODULE_CONFIG_ITEM_INTEGER:
836                 config_PutIntVariable( p_longopts[i_index].name, atoi(optarg));
837                 break;
838             case MODULE_CONFIG_ITEM_FLOAT:
839                 config_PutFloatVariable( p_longopts[i_index].name,
840                                          (float)atof(optarg) );
841                 break;
842             case MODULE_CONFIG_ITEM_BOOL:
843                 config_PutIntVariable( p_longopts[i_index].name, 1 );
844                 break;
845             }
846
847             continue;
848         }
849
850         /* short options handled here for now */
851         switch( i_cmd )
852         {
853
854         /* General/common options */
855         case 'h':                                              /* -h, --help */
856             config_PutIntVariable( "help", 1 );
857             break;
858         case 'H':                                          /* -H, --longhelp */
859             config_PutIntVariable( "longhelp", 1 );
860             break;
861         case 'l':                                              /* -l, --list */
862             config_PutIntVariable( "list", 1 );
863             break;
864         case 'p':                                            /* -p, --plugin */
865             config_PutPszVariable( "plugin", optarg );
866             break;
867         case 'v':                                           /* -v, --verbose */
868             p_main->i_warning_level++;
869             break;
870
871         /* Internal error: unknown option */
872         case '?':
873         default:
874
875             if( !b_ignore_errors )
876             {
877                 intf_ErrMsg( "config error: unknown option `%s'",
878                              ppsz_argv[optind-1] );
879                 intf_Msg( "Try `%s --help' for more information.\n",
880                           p_main->psz_arg0 );
881
882                 free( p_longopts );
883                 return( -1 );
884             }
885         }
886
887     }
888
889     if( p_main->i_warning_level < 0 )
890     {
891         p_main->i_warning_level = 0;
892     }
893
894     free( p_longopts );
895     return( 0 );
896 }
897
898 /*****************************************************************************
899  * config_GetHomeDir: find the user's home directory.
900  *****************************************************************************
901  * This function will try by different ways to find the user's home path.
902  * Note that this function is not reentrant, it should be called only once
903  * at the beginning of main where the result will be stored for later use.
904  *****************************************************************************/
905 char *config_GetHomeDir( void )
906 {
907     char *p_tmp, *p_homedir = NULL;
908
909 #if defined(HAVE_GETPWUID)
910     struct passwd *p_pw = NULL;
911 #endif
912
913 #if defined(HAVE_GETPWUID)
914     if( ( p_pw = getpwuid( getuid() ) ) == NULL )
915 #endif
916     {
917         if( ( p_tmp = getenv( "HOME" ) ) == NULL )
918         {
919             if( ( p_tmp = getenv( "TMP" ) ) == NULL )
920             {
921                 p_homedir = strdup( "/tmp" );
922             }
923             else p_homedir = strdup( p_tmp );
924
925             intf_ErrMsg( "config error: unable to get home directory, "
926                          "using %s instead", p_homedir );
927
928         }
929         else p_homedir = strdup( p_tmp );
930     }
931 #if defined(HAVE_GETPWUID)
932     else
933     {
934         p_homedir = strdup( p_pw->pw_dir );
935     }
936 #endif
937
938     return p_homedir;
939 }