configuration.c 33.1 KB
Newer Older
gbazin's avatar
   
gbazin committed
1
2
3
4
/*****************************************************************************
 * configuration.c management of the modules configuration
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
gbazin's avatar
   
gbazin committed
5
 * $Id: configuration.c,v 1.18 2002/04/21 21:29:20 gbazin Exp $
gbazin's avatar
   
gbazin committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * Authors: Gildas Bazin <gbazin@netcourrier.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
23

gbazin's avatar
   
gbazin committed
24
25
#include <videolan/vlc.h>

gbazin's avatar
   
gbazin committed
26
#include <stdio.h>                                              /* sprintf() */
gbazin's avatar
   
gbazin committed
27
#include <stdlib.h>                                      /* free(), strtol() */
gbazin's avatar
   
gbazin committed
28
#include <string.h>                                              /* strdup() */
gbazin's avatar
   
gbazin committed
29
#include <errno.h>                                                  /* errno */
gbazin's avatar
   
gbazin committed
30

gbazin's avatar
   
gbazin committed
31
32
33
#ifdef HAVE_UNISTD_H
#    include <unistd.h>                                          /* getuid() */
#endif
gbazin's avatar
   
gbazin committed
34

gbazin's avatar
   
gbazin committed
35
36
37
38
39
40
41
42
43
#ifdef HAVE_GETOPT_LONG
#   ifdef HAVE_GETOPT_H
#       include <getopt.h>                                       /* getopt() */
#   endif
#else
#   include "GNUgetopt/getopt.h"
#endif

#if defined(HAVE_GETPWUID)
gbazin's avatar
   
gbazin committed
44
45
46
47
48
49
#include <pwd.h>                                               /* getpwuid() */
#endif

#include <sys/stat.h>
#include <sys/types.h>

gbazin's avatar
   
gbazin committed
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*****************************************************************************
 * config_GetIntVariable: get the value of an int variable
 *****************************************************************************
 * This function is used to get the value of variables which are internally
 * represented by an integer (MODULE_CONFIG_ITEM_INTEGER and
 * MODULE_CONFIG_ITEM_BOOL).
 *****************************************************************************/
int config_GetIntVariable( const char *psz_name )
{
    module_config_t *p_config;

    p_config = config_FindConfig( psz_name );

    /* sanity checks */
    if( !p_config )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
66
        intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
gbazin's avatar
   
gbazin committed
67
68
69
70
71
        return -1;
    }
    if( (p_config->i_type!=MODULE_CONFIG_ITEM_INTEGER) &&
        (p_config->i_type!=MODULE_CONFIG_ITEM_BOOL) )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
72
73
        intf_ErrMsg( "config error: option %s doesn't refer to an int",
                     psz_name );
gbazin's avatar
   
gbazin committed
74
75
76
77
78
79
        return -1;
    }

    return p_config->i_value;
}

gbazin's avatar
   
gbazin committed
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*****************************************************************************
 * config_GetFloatVariable: get the value of a float variable
 *****************************************************************************
 * This function is used to get the value of variables which are internally
 * represented by a float (MODULE_CONFIG_ITEM_FLOAT).
 *****************************************************************************/
float config_GetFloatVariable( const char *psz_name )
{
    module_config_t *p_config;

    p_config = config_FindConfig( psz_name );

    /* sanity checks */
    if( !p_config )
    {
        intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
        return -1;
    }
    if( p_config->i_type != MODULE_CONFIG_ITEM_FLOAT )
    {
        intf_ErrMsg( "config error: option %s doesn't refer to a float",
                     psz_name );
        return -1;
    }

    return p_config->f_value;
}

gbazin's avatar
   
gbazin committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*****************************************************************************
 * config_GetPszVariable: get the string value of a string variable
 *****************************************************************************
 * This function is used to get the value of variables which are internally
 * represented by a string (MODULE_CONFIG_ITEM_STRING, MODULE_CONFIG_ITEM_FILE,
 * and MODULE_CONFIG_ITEM_PLUGIN).
 *
 * Important note: remember to free() the returned char* because it a duplicate
 *   of the actual value. It isn't safe to return a pointer to the actual value
 *   as it can be modified at any time.
 *****************************************************************************/
char * config_GetPszVariable( const char *psz_name )
{
    module_config_t *p_config;
    char *psz_value = NULL;

    p_config = config_FindConfig( psz_name );

    /* sanity checks */
    if( !p_config )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
129
        intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
gbazin's avatar
   
gbazin committed
130
131
132
133
134
135
        return NULL;
    }
    if( (p_config->i_type!=MODULE_CONFIG_ITEM_STRING) &&
        (p_config->i_type!=MODULE_CONFIG_ITEM_FILE) &&
        (p_config->i_type!=MODULE_CONFIG_ITEM_PLUGIN) )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
136
137
        intf_ErrMsg( "config error: option %s doesn't refer to a string",
                     psz_name );
gbazin's avatar
   
gbazin committed
138
139
140
141
        return NULL;
    }

    /* return a copy of the string */
gbazin's avatar
   
gbazin committed
142
    vlc_mutex_lock( p_config->p_lock );
gbazin's avatar
   
gbazin committed
143
    if( p_config->psz_value ) psz_value = strdup( p_config->psz_value );
gbazin's avatar
   
gbazin committed
144
    vlc_mutex_unlock( p_config->p_lock );
gbazin's avatar
   
gbazin committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

    return psz_value;
}

/*****************************************************************************
 * config_PutPszVariable: set the string value of a string variable
 *****************************************************************************
 * This function is used to set the value of variables which are internally
 * represented by a string (MODULE_CONFIG_ITEM_STRING, MODULE_CONFIG_ITEM_FILE,
 * and MODULE_CONFIG_ITEM_PLUGIN).
 *****************************************************************************/
void config_PutPszVariable( const char *psz_name, char *psz_value )
{
    module_config_t *p_config;

    p_config = config_FindConfig( psz_name );

    /* sanity checks */
    if( !p_config )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
165
        intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
gbazin's avatar
   
gbazin committed
166
167
168
169
170
171
        return;
    }
    if( (p_config->i_type!=MODULE_CONFIG_ITEM_STRING) &&
        (p_config->i_type!=MODULE_CONFIG_ITEM_FILE) &&
        (p_config->i_type!=MODULE_CONFIG_ITEM_PLUGIN) )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
172
173
        intf_ErrMsg( "config error: option %s doesn't refer to a string",
                     psz_name );
gbazin's avatar
   
gbazin committed
174
175
176
        return;
    }

gbazin's avatar
   
gbazin committed
177
178
179
180
181
    vlc_mutex_lock( p_config->p_lock );

    /* free old string */
    if( p_config->psz_value ) free( p_config->psz_value );

gbazin's avatar
   
gbazin committed
182
183
184
    if( psz_value ) p_config->psz_value = strdup( psz_value );
    else p_config->psz_value = NULL;

gbazin's avatar
   
gbazin committed
185
    vlc_mutex_unlock( p_config->p_lock );
gbazin's avatar
   
gbazin committed
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

}

/*****************************************************************************
 * config_PutIntVariable: set the integer value of an int variable
 *****************************************************************************
 * This function is used to set the value of variables which are internally
 * represented by an integer (MODULE_CONFIG_ITEM_INTEGER and
 * MODULE_CONFIG_ITEM_BOOL).
 *****************************************************************************/
void config_PutIntVariable( const char *psz_name, int i_value )
{
    module_config_t *p_config;

    p_config = config_FindConfig( psz_name );

    /* sanity checks */
    if( !p_config )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
205
        intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
gbazin's avatar
   
gbazin committed
206
207
208
209
210
        return;
    }
    if( (p_config->i_type!=MODULE_CONFIG_ITEM_INTEGER) &&
        (p_config->i_type!=MODULE_CONFIG_ITEM_BOOL) )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
211
212
        intf_ErrMsg( "config error: option %s doesn't refer to an int",
                     psz_name );
gbazin's avatar
   
gbazin committed
213
214
215
216
217
218
        return;
    }

    p_config->i_value = i_value;
}

gbazin's avatar
   
gbazin committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/*****************************************************************************
 * config_PutFloatVariable: set the value of a float variable
 *****************************************************************************
 * This function is used to set the value of variables which are internally
 * represented by a float (MODULE_CONFIG_ITEM_FLOAT).
 *****************************************************************************/
void config_PutFloatVariable( const char *psz_name, float f_value )
{
    module_config_t *p_config;

    p_config = config_FindConfig( psz_name );

    /* sanity checks */
    if( !p_config )
    {
        intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
        return;
    }
    if( p_config->i_type != MODULE_CONFIG_ITEM_FLOAT )
    {
        intf_ErrMsg( "config error: option %s doesn't refer to a float",
                     psz_name );
        return;
    }

    p_config->f_value = f_value;
}

gbazin's avatar
   
gbazin committed
247
248
249
250
251
252
253
254
/*****************************************************************************
 * config_FindConfig: find the config structure associated with an option.
 *****************************************************************************
 * FIXME: This function really needs to be optimized.
 *****************************************************************************/
module_config_t *config_FindConfig( const char *psz_name )
{
    module_t *p_module;
Sam Hocevar's avatar
   
Sam Hocevar committed
255
    module_config_t *p_item;
gbazin's avatar
   
gbazin committed
256
257
258
259
260
261
262

    if( !psz_name ) return NULL;

    for( p_module = p_module_bank->first ;
         p_module != NULL ;
         p_module = p_module->next )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
263
264
265
        for( p_item = p_module->p_config;
             p_item->i_type != MODULE_CONFIG_HINT_END;
             p_item++ )
gbazin's avatar
   
gbazin committed
266
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
267
            if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
268
                /* ignore hints */
gbazin's avatar
   
gbazin committed
269
                continue;
Sam Hocevar's avatar
   
Sam Hocevar committed
270
271
            if( !strcmp( psz_name, p_item->psz_name ) )
                return p_item;
gbazin's avatar
   
gbazin committed
272
273
274
275
276
277
278
279
280
281
282
283
284
        }
    }

    return NULL;
}

/*****************************************************************************
 * config_Duplicate: creates a duplicate of a module's configuration data.
 *****************************************************************************
 * Unfortunatly we cannot work directly with the module's config data as
 * this module might be unloaded from memory at any time (remember HideModule).
 * This is why we need to create an exact copy of the config data.
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
285
module_config_t *config_Duplicate( module_config_t *p_orig )
gbazin's avatar
   
gbazin committed
286
{
Sam Hocevar's avatar
   
Sam Hocevar committed
287
    int i, i_lines;
gbazin's avatar
   
gbazin committed
288
289
    module_config_t *p_config;

Sam Hocevar's avatar
   
Sam Hocevar committed
290
291
292
293
294
295
296
    /* Calculate the structure length */
    for( p_config = p_orig, i_lines = 1;
         p_config->i_type != MODULE_CONFIG_HINT_END;
         p_config++, i_lines++ );

    /* Allocate memory */
    p_config = (module_config_t *)malloc( sizeof(module_config_t) * i_lines );
gbazin's avatar
   
gbazin committed
297
298
    if( p_config == NULL )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
299
        intf_ErrMsg( "config error: can't duplicate p_config" );
gbazin's avatar
   
gbazin committed
300
301
302
        return( NULL );
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
303
304
    /* Do the duplication job */
    for( i = 0; i < i_lines ; i++ )
gbazin's avatar
   
gbazin committed
305
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
306
        p_config[i].i_type = p_orig[i].i_type;
Sam Hocevar's avatar
   
Sam Hocevar committed
307
        p_config[i].i_short = p_orig[i].i_short;
Sam Hocevar's avatar
   
Sam Hocevar committed
308
        p_config[i].i_value = p_orig[i].i_value;
gbazin's avatar
   
gbazin committed
309
        p_config[i].f_value = p_orig[i].f_value;
Sam Hocevar's avatar
   
Sam Hocevar committed
310
311
312
313
314
315
316
317
318
319
        p_config[i].b_dirty = p_orig[i].b_dirty;

        p_config[i].psz_name = p_orig[i].psz_name ?
                                   strdup( _(p_orig[i].psz_name) ) : NULL;
        p_config[i].psz_text = p_orig[i].psz_text ?
                                   strdup( _(p_orig[i].psz_text) ) : NULL;
        p_config[i].psz_longtext = p_orig[i].psz_longtext ?
                                   strdup( _(p_orig[i].psz_longtext) ) : NULL;
        p_config[i].psz_value = p_orig[i].psz_value ?
                                   strdup( _(p_orig[i].psz_value) ) : NULL;
gbazin's avatar
   
gbazin committed
320
321
322

        /* the callback pointer is only valid when the module is loaded so this
         * value is set in ActivateModule() and reset in DeactivateModule() */
gbazin's avatar
   
gbazin committed
323
        p_config[i].p_callback = NULL;
gbazin's avatar
   
gbazin committed
324
325
326
327
    }

    return p_config;
}
gbazin's avatar
   
gbazin committed
328
329
330
331
332
333
334
335
336
337

/*****************************************************************************
 * config_LoadConfigFile: loads the configuration file.
 *****************************************************************************
 * This function is called to load the config options stored in the config
 * file.
 *****************************************************************************/
int config_LoadConfigFile( const char *psz_module_name )
{
    module_t *p_module;
Sam Hocevar's avatar
   
Sam Hocevar committed
338
    module_config_t *p_item;
gbazin's avatar
   
gbazin committed
339
340
341
342
343
344
345
346
    FILE *file;
    char line[1024];
    char *p_index, *psz_option_name, *psz_option_value;
    char *psz_filename, *psz_homedir;

    /* Acquire config file lock */
    vlc_mutex_lock( &p_main->config_lock );

gbazin's avatar
   
gbazin committed
347
    psz_homedir = p_main->psz_homedir;
gbazin's avatar
   
gbazin committed
348
349
    if( !psz_homedir )
    {
gbazin's avatar
   
gbazin committed
350
        intf_ErrMsg( "config error: p_main->psz_homedir is null" );
gbazin's avatar
   
gbazin committed
351
352
353
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
354
    psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
gbazin's avatar
   
gbazin committed
355
356
357
                                   strlen(psz_homedir) + 1 );
    if( !psz_filename )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
358
        intf_ErrMsg( "config error: couldn't malloc psz_filename" );
gbazin's avatar
   
gbazin committed
359
360
361
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
362
    sprintf( psz_filename, "%s/" CONFIG_DIR "/" CONFIG_FILE, psz_homedir );
gbazin's avatar
   
gbazin committed
363

Sam Hocevar's avatar
   
Sam Hocevar committed
364
    intf_WarnMsg( 5, "config: opening config file %s", psz_filename );
gbazin's avatar
   
gbazin committed
365
366
367
368

    file = fopen( psz_filename, "r" );
    if( !file )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
369
370
        intf_WarnMsg( 1, "config: couldn't open config file %s for reading (%s)",
                         psz_filename, strerror(errno) );
gbazin's avatar
   
gbazin committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
        free( psz_filename );
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }

    /* Look for the selected module, if NULL then save everything */
    for( p_module = p_module_bank->first ; p_module != NULL ;
         p_module = p_module->next )
    {

        if( psz_module_name && strcmp( psz_module_name, p_module->psz_name ) )
            continue;

        /* The config file is organized in sections, one per module. Look for
         * the interesting section ( a section is of the form [foo] ) */
        rewind( file );
        while( fgets( line, 1024, file ) )
        {
            if( (line[0] == '[') && (p_index = strchr(line,']')) &&
                (p_index - &line[1] == strlen(p_module->psz_name) ) &&
                !memcmp( &line[1], p_module->psz_name,
                         strlen(p_module->psz_name) ) )
            {
Sam Hocevar's avatar
   
Sam Hocevar committed
394
395
                intf_WarnMsg( 5, "config: loading config for module <%s>",
                                 p_module->psz_name );
gbazin's avatar
   
gbazin committed
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423

                break;
            }
        }
        /* either we found the section or we're at the EOF */

        /* Now try to load the options in this section */
        while( fgets( line, 1024, file ) )
        {
            if( line[0] == '[' ) break; /* end of section */

            /* ignore comments or empty lines */
            if( (line[0] == '#') || (line[0] == (char)0) ) continue;

            /* get rid of line feed */
            if( line[strlen(line)-1] == '\n' )
                line[strlen(line)-1] = (char)0;

            /* look for option name */
            psz_option_name = line;
            psz_option_value = NULL;
            p_index = strchr( line, '=' );
            if( !p_index ) break; /* this ain't an option!!! */

            *p_index = (char)0;
            psz_option_value = p_index + 1;

            /* try to match this option with one of the module's options */
Sam Hocevar's avatar
   
Sam Hocevar committed
424
425
426
            for( p_item = p_module->p_config;
                 p_item->i_type != MODULE_CONFIG_HINT_END;
                 p_item++ )
gbazin's avatar
   
gbazin committed
427
            {
Sam Hocevar's avatar
   
Sam Hocevar committed
428
                if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
429
430
                    /* ignore hints */
                    continue;
Sam Hocevar's avatar
   
Sam Hocevar committed
431
432

                if( !strcmp( p_item->psz_name, psz_option_name ) )
gbazin's avatar
   
gbazin committed
433
434
                {
                    /* We found it */
Sam Hocevar's avatar
   
Sam Hocevar committed
435
                    switch( p_item->i_type )
gbazin's avatar
   
gbazin committed
436
437
438
                    {
                    case MODULE_CONFIG_ITEM_BOOL:
                    case MODULE_CONFIG_ITEM_INTEGER:
gbazin's avatar
   
gbazin committed
439
440
                        if( !*psz_option_value )
                            break;                    /* ignore empty option */
Sam Hocevar's avatar
   
Sam Hocevar committed
441
                        p_item->i_value = atoi( psz_option_value);
Sam Hocevar's avatar
   
Sam Hocevar committed
442
                        intf_WarnMsg( 7, "config: found <%s> option %s=%i",
Sam Hocevar's avatar
   
Sam Hocevar committed
443
444
                                         p_module->psz_name,
                                         p_item->psz_name, p_item->i_value );
gbazin's avatar
   
gbazin committed
445
446
                        break;

gbazin's avatar
   
gbazin committed
447
448
449
450
451
452
453
454
455
                    case MODULE_CONFIG_ITEM_FLOAT:
                        if( !*psz_option_value )
                            break;                    /* ignore empty option */
                        p_item->f_value = (float)atof( psz_option_value);
                        intf_WarnMsg( 7, "config: found <%s> option %s=%f",
                                         p_module->psz_name, p_item->psz_name,
                                         (double)p_item->f_value );
                        break;

gbazin's avatar
   
gbazin committed
456
                    default:
Sam Hocevar's avatar
   
Sam Hocevar committed
457
                        vlc_mutex_lock( p_item->p_lock );
gbazin's avatar
   
gbazin committed
458
459

                        /* free old string */
Sam Hocevar's avatar
   
Sam Hocevar committed
460
461
                        if( p_item->psz_value )
                            free( p_item->psz_value );
gbazin's avatar
   
gbazin committed
462

Sam Hocevar's avatar
   
Sam Hocevar committed
463
                        p_item->psz_value = *psz_option_value ?
gbazin's avatar
   
gbazin committed
464
                            strdup( psz_option_value ) : NULL;
gbazin's avatar
   
gbazin committed
465

Sam Hocevar's avatar
   
Sam Hocevar committed
466
                        vlc_mutex_unlock( p_item->p_lock );
gbazin's avatar
   
gbazin committed
467

Sam Hocevar's avatar
   
Sam Hocevar committed
468
                        intf_WarnMsg( 7, "config: found <%s> option %s=%s",
Sam Hocevar's avatar
   
Sam Hocevar committed
469
470
471
472
                                         p_module->psz_name,
                                         p_item->psz_name,
                                         p_item->psz_value != NULL ?
                                           p_item->psz_value : "(NULL)" );
gbazin's avatar
   
gbazin committed
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
                        break;
                    }
                }
            }
        }

    }
    
    fclose( file );
    free( psz_filename );

    vlc_mutex_unlock( &p_main->config_lock );

    return 0;
}

/*****************************************************************************
 * config_SaveConfigFile: Save a module's config options.
 *****************************************************************************
 * This will save the specified module's config options to the config file.
 * If psz_module_name is NULL then we save all the modules config options.
 * It's no use to save the config options that kept their default values, so
 * we'll try to be a bit clever here.
 *
 * When we save we mustn't delete the config options of the plugins that
 * haven't been loaded. So we cannot just create a new config file with the
 * config structures we've got in memory. 
 * I don't really know how to deal with this nicely, so I will use a completly
 * dumb method ;-)
 * I will load the config file in memory, but skipping all the sections of the
 * modules we want to save. Then I will create a brand new file, dump the file
 * loaded in memory and then append the sections of the modules we want to
 * save.
 * Really stupid no ?
 *****************************************************************************/
int config_SaveConfigFile( const char *psz_module_name )
{
    module_t *p_module;
Sam Hocevar's avatar
   
Sam Hocevar committed
511
    module_config_t *p_item;
gbazin's avatar
   
gbazin committed
512
513
    FILE *file;
    char p_line[1024], *p_index2;
Sam Hocevar's avatar
   
Sam Hocevar committed
514
    int i_sizebuf = 0;
gbazin's avatar
   
gbazin committed
515
516
517
518
519
520
521
    char *p_bigbuffer, *p_index;
    boolean_t b_backup;
    char *psz_filename, *psz_homedir;

    /* Acquire config file lock */
    vlc_mutex_lock( &p_main->config_lock );

gbazin's avatar
   
gbazin committed
522
    psz_homedir = p_main->psz_homedir;
gbazin's avatar
   
gbazin committed
523
524
    if( !psz_homedir )
    {
gbazin's avatar
   
gbazin committed
525
        intf_ErrMsg( "config error: p_main->psz_homedir is null" );
gbazin's avatar
   
gbazin committed
526
527
528
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
529
    psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
gbazin's avatar
   
gbazin committed
530
531
532
                                   strlen(psz_homedir) + 1 );
    if( !psz_filename )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
533
        intf_ErrMsg( "config error: couldn't malloc psz_filename" );
gbazin's avatar
   
gbazin committed
534
535
536
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
537
    sprintf( psz_filename, "%s/" CONFIG_DIR, psz_homedir );
Sam Hocevar's avatar
   
Sam Hocevar committed
538

gbazin's avatar
   
gbazin committed
539
#ifndef WIN32
Sam Hocevar's avatar
   
Sam Hocevar committed
540
    if( mkdir( psz_filename, 0755 ) && errno != EEXIST )
gbazin's avatar
   
gbazin committed
541
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
542
    if( mkdir( psz_filename ) && errno != EEXIST )
gbazin's avatar
   
gbazin committed
543
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
544
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
545
546
        intf_ErrMsg( "config error: couldn't create %s (%s)",
                     psz_filename, strerror(errno) );
Sam Hocevar's avatar
   
Sam Hocevar committed
547
548
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
549
    strcat( psz_filename, "/" CONFIG_FILE );
gbazin's avatar
   
gbazin committed
550
551


Sam Hocevar's avatar
   
Sam Hocevar committed
552
    intf_WarnMsg( 5, "config: opening config file %s", psz_filename );
gbazin's avatar
   
gbazin committed
553
554
555
556

    file = fopen( psz_filename, "r" );
    if( !file )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
557
558
        intf_WarnMsg( 1, "config: couldn't open config file %s for reading (%s)",
                         psz_filename, strerror(errno) );
gbazin's avatar
   
gbazin committed
559
560
561
562
563
564
565
566
567
568
569
570
    }
    else
    {
        /* look for file size */
        fseek( file, 0, SEEK_END );
        i_sizebuf = ftell( file );
        rewind( file );
    }

    p_bigbuffer = p_index = malloc( i_sizebuf+1 );
    if( !p_bigbuffer )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
571
        intf_ErrMsg( "config error: couldn't malloc bigbuffer" );
gbazin's avatar
   
gbazin committed
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
        if( file ) fclose( file );
        free( psz_filename );
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
    p_bigbuffer[0] = 0;

    /* backup file into memory, we only need to backup the sections we won't
     * save later on */
    b_backup = 0;
    while( file && fgets( p_line, 1024, file ) )
    {
        if( (p_line[0] == '[') && (p_index2 = strchr(p_line,']')))
        {
            /* we found a section, check if we need to do a backup */
            for( p_module = p_module_bank->first; p_module != NULL;
                 p_module = p_module->next )
            {
                if( ((p_index2 - &p_line[1]) == strlen(p_module->psz_name) ) &&
                    !memcmp( &p_line[1], p_module->psz_name,
                             strlen(p_module->psz_name) ) )
                {
                    if( !psz_module_name )
                        break;
                    else if( !strcmp( psz_module_name, p_module->psz_name ) )
                        break;
                }
            }

            if( !p_module )
            {
                /* we don't have this section in our list so we need to back
                 * it up */
                *p_index2 = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
606
607
                intf_WarnMsg( 5, "config: backing up config for "
                                 "unknown module <%s>", &p_line[1] );
gbazin's avatar
   
gbazin committed
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
                *p_index2 = ']';

                b_backup = 1;
            }
            else
            {
                b_backup = 0;
            }
        }

        /* save line if requested and line is valid (doesn't begin with a
         * space, tab, or eol) */
        if( b_backup && (p_line[0] != '\n') && (p_line[0] != ' ')
            && (p_line[0] != '\t') )
        {
            strcpy( p_index, p_line );
            p_index += strlen( p_line );
        }
    }
    if( file ) fclose( file );


    /*
     * Save module config in file
     */

    file = fopen( psz_filename, "w" );
    if( !file )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
637
638
        intf_WarnMsg( 1, "config: couldn't open config file %s for writing",
                         psz_filename );
gbazin's avatar
   
gbazin committed
639
640
641
642
643
        free( psz_filename );
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
644
    fprintf( file, "###\n###  " COPYRIGHT_MESSAGE "\n###\n\n" );
gbazin's avatar
   
gbazin committed
645
646
647
648
649
650
651
652
653
654
655
656

    /* Look for the selected module, if NULL then save everything */
    for( p_module = p_module_bank->first ; p_module != NULL ;
         p_module = p_module->next )
    {

        if( psz_module_name && strcmp( psz_module_name, p_module->psz_name ) )
            continue;

        if( !p_module->i_config_items )
            continue;

Sam Hocevar's avatar
   
Sam Hocevar committed
657
658
        intf_WarnMsg( 5, "config: saving config for module <%s>",
                         p_module->psz_name );
gbazin's avatar
   
gbazin committed
659

gbazin's avatar
   
gbazin committed
660
661
        fprintf( file, "[%s]\n", p_module->psz_name );

gbazin's avatar
   
gbazin committed
662
        if( p_module->psz_longname )
Sam Hocevar's avatar
   
Sam Hocevar committed
663
664
            fprintf( file, "###\n###  %s\n###\n", p_module->psz_longname );

Sam Hocevar's avatar
   
Sam Hocevar committed
665
666
667
        for( p_item = p_module->p_config;
             p_item->i_type != MODULE_CONFIG_HINT_END;
             p_item++ )
gbazin's avatar
   
gbazin committed
668
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
669
            if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
670
671
672
                /* ignore hints */
                continue;

Sam Hocevar's avatar
   
Sam Hocevar committed
673
            switch( p_item->i_type )
gbazin's avatar
   
gbazin committed
674
675
676
            {
            case MODULE_CONFIG_ITEM_BOOL:
            case MODULE_CONFIG_ITEM_INTEGER:
Sam Hocevar's avatar
   
Sam Hocevar committed
677
678
                if( p_item->psz_text )
                    fprintf( file, "# %s %s\n", p_item->psz_text,
gbazin's avatar
   
gbazin committed
679
680
                             (p_item->i_type == MODULE_CONFIG_ITEM_BOOL) ?
                             _("<boolean>") : _("<integer>") );
Sam Hocevar's avatar
   
Sam Hocevar committed
681
682
                fprintf( file, "%s=%i\n", p_item->psz_name,
                         p_item->i_value );
gbazin's avatar
   
gbazin committed
683
684
                break;

gbazin's avatar
   
gbazin committed
685
686
687
688
689
690
691
            case MODULE_CONFIG_ITEM_FLOAT:
                if( p_item->psz_text )
                    fprintf( file, _("# %s <float>\n"), p_item->psz_text );
                fprintf( file, "%s=%f\n", p_item->psz_name,
                         (double)p_item->f_value );
                break;

gbazin's avatar
   
gbazin committed
692
            default:
Sam Hocevar's avatar
   
Sam Hocevar committed
693
694
695
696
                if( p_item->psz_text )
                    fprintf( file, _("# %s <string>\n"), p_item->psz_text );
                fprintf( file, "%s=%s\n", p_item->psz_name,
                         p_item->psz_value ? p_item->psz_value : "" );
gbazin's avatar
   
gbazin committed
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
            }
        }

        fprintf( file, "\n" );
    }


    /*
     * Restore old settings from the config in file
     */
    fputs( p_bigbuffer, file );
    free( p_bigbuffer );

    fclose( file );
    free( psz_filename );
    vlc_mutex_unlock( &p_main->config_lock );

    return 0;
}

gbazin's avatar
   
gbazin committed
717
718
719
720
721
722
723
724
725
726
/*****************************************************************************
 * config_LoadCmdLine: parse command line
 *****************************************************************************
 * Parse command line for configuration options.
 * Now that the module_bank has been initialized, we can dynamically
 * generate the longopts structure used by getops. We have to do it this way
 * because we don't know (and don't want to know) in advance the configuration
 * options used (ie. exported) by each module.
 *****************************************************************************/
int config_LoadCmdLine( int *pi_argc, char *ppsz_argv[],
gbazin's avatar
   
gbazin committed
727
                        boolean_t b_ignore_errors )
gbazin's avatar
   
gbazin committed
728
{
Sam Hocevar's avatar
   
Sam Hocevar committed
729
    int i_cmd, i_index, i_opts, i_shortopts;
gbazin's avatar
   
gbazin committed
730
    module_t *p_module;
Sam Hocevar's avatar
   
Sam Hocevar committed
731
    module_config_t *p_item;
gbazin's avatar
   
gbazin committed
732
733
734
    struct option *p_longopts;

    /* Short options */
Sam Hocevar's avatar
   
Sam Hocevar committed
735
736
    module_config_t *pp_shortopts[256];
    char *psz_shortopts;
gbazin's avatar
   
gbazin committed
737

gbazin's avatar
   
gbazin committed
738
739
740
    /* reset warning level */
    p_main->i_warning_level = 0;

gbazin's avatar
   
gbazin committed
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
    /* Set default configuration and copy arguments */
    p_main->i_argc    = *pi_argc;
    p_main->ppsz_argv = ppsz_argv;

    p_main->p_channel = NULL;

#ifdef SYS_DARWIN
    /* When vlc.app is run by double clicking in Mac OS X, the 2nd arg
     * is the PSN - process serial number (a unique PID-ish thingie)
     * still ok for real Darwin & when run from command line */
    if ( (*pi_argc > 1) && (strncmp( ppsz_argv[ 1 ] , "-psn" , 4 ) == 0) )
                                        /* for example -psn_0_9306113 */
    {
        /* GDMF!... I can't do this or else the MacOSX window server will
         * not pick up the PSN and not register the app and we crash...
         * hence the following kludge otherwise we'll get confused w/ argv[1]
         * being an input file name */
#if 0
        ppsz_argv[ 1 ] = NULL;
#endif
        *pi_argc = *pi_argc - 1;
        pi_argc--;
        return( 0 );
    }
#endif

    /*
Sam Hocevar's avatar
   
Sam Hocevar committed
768
     * Generate the longopts and shortopts structure used by getopt_long
gbazin's avatar
   
gbazin committed
769
     */
Sam Hocevar's avatar
   
Sam Hocevar committed
770
771

    i_opts = 0;
gbazin's avatar
   
gbazin committed
772
773
774
775
776
777
    for( p_module = p_module_bank->first;
         p_module != NULL ;
         p_module = p_module->next )
    {
        /* count the number of exported configuration options (to allocate
         * longopts). */
Sam Hocevar's avatar
   
Sam Hocevar committed
778
        i_opts += p_module->i_config_items;
gbazin's avatar
   
gbazin committed
779
780
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
781
    p_longopts = malloc( sizeof(struct option) * (i_opts + 1) );
gbazin's avatar
   
gbazin committed
782
783
784
785
786
787
    if( p_longopts == NULL )
    {
        intf_ErrMsg( "config error: couldn't allocate p_longopts" );
        return( -1 );
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
    psz_shortopts = malloc( sizeof( char ) * (2 * i_opts + 1) );
    if( psz_shortopts == NULL )
    {
        intf_ErrMsg( "config error: couldn't allocate psz_shortopts" );
        free( p_longopts );
        return( -1 );
    }

    psz_shortopts[0] = 'v';
    i_shortopts = 1;
    for( i_index = 0; i_index < 256; i_index++ )
    {
        pp_shortopts[i_index] = NULL;
    }

gbazin's avatar
   
gbazin committed
803
804
805
806
807
808
    /* Fill the longopts structure */
    i_index = 0;
    for( p_module = p_module_bank->first ;
         p_module != NULL ;
         p_module = p_module->next )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
809
810
811
        for( p_item = p_module->p_config;
             p_item->i_type != MODULE_CONFIG_HINT_END;
             p_item++ )
gbazin's avatar
   
gbazin committed
812
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
813
            if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
814
815
                /* ignore hints */
                continue;
Sam Hocevar's avatar
   
Sam Hocevar committed
816
            p_longopts[i_index].name = p_item->psz_name;
gbazin's avatar
   
gbazin committed
817
            p_longopts[i_index].has_arg =
Sam Hocevar's avatar
   
Sam Hocevar committed
818
                (p_item->i_type == MODULE_CONFIG_ITEM_BOOL)?
gbazin's avatar
   
gbazin committed
819
820
821
                                               no_argument : required_argument;
            p_longopts[i_index].flag = 0;
            p_longopts[i_index].val = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
822
823
824
825
826
827
828
829
830
831
832
            if( p_item->i_short )
            {
                pp_shortopts[(int)p_item->i_short] = p_item;
                psz_shortopts[i_shortopts] = p_item->i_short;
                i_shortopts++;
                if( p_item->i_type != MODULE_CONFIG_ITEM_BOOL )
                {
                    psz_shortopts[i_shortopts] = ':';
                    i_shortopts++;
                }
            }
gbazin's avatar
   
gbazin committed
833
834
835
836
            i_index++;
        }
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
837
838
839
    /* Close the longopts and shortopts structures */
    memset( &p_longopts[i_index], 0, sizeof(struct option) );
    psz_shortopts[i_shortopts] = '\0';
gbazin's avatar
   
gbazin committed
840
841
842
843
844
845
846
847
848

    /*
     * Parse the command line options
     */
    opterr = 0;
    optind = 1;
    while( ( i_cmd = getopt_long( *pi_argc, ppsz_argv, psz_shortopts,
                                  p_longopts, &i_index ) ) != EOF )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
849
        /* A long option has been recognized */
gbazin's avatar
   
gbazin committed
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
        if( i_cmd == 0 )
        {
            module_config_t *p_conf;

            /* Store the configuration option */
            p_conf = config_FindConfig( p_longopts[i_index].name );

            switch( p_conf->i_type )
            {
            case MODULE_CONFIG_ITEM_STRING:
            case MODULE_CONFIG_ITEM_FILE:
            case MODULE_CONFIG_ITEM_PLUGIN:
                config_PutPszVariable( p_longopts[i_index].name, optarg );
                break;
            case MODULE_CONFIG_ITEM_INTEGER:
                config_PutIntVariable( p_longopts[i_index].name, atoi(optarg));
                break;
gbazin's avatar
   
gbazin committed
867
868
869
870
            case MODULE_CONFIG_ITEM_FLOAT:
                config_PutFloatVariable( p_longopts[i_index].name,
                                         (float)atof(optarg) );
                break;
gbazin's avatar
   
gbazin committed
871
872
873
874
875
876
877
878
            case MODULE_CONFIG_ITEM_BOOL:
                config_PutIntVariable( p_longopts[i_index].name, 1 );
                break;
            }

            continue;
        }

Sam Hocevar's avatar
   
Sam Hocevar committed
879
880
        /* A short option has been recognized */
        if( pp_shortopts[i_cmd] != NULL )
gbazin's avatar
   
gbazin committed
881
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
            switch( pp_shortopts[i_cmd]->i_type )
            {
            case MODULE_CONFIG_ITEM_STRING:
            case MODULE_CONFIG_ITEM_FILE:
            case MODULE_CONFIG_ITEM_PLUGIN:
                config_PutPszVariable( pp_shortopts[i_cmd]->psz_name, optarg );
                break;
            case MODULE_CONFIG_ITEM_INTEGER:
                config_PutIntVariable( pp_shortopts[i_cmd]->psz_name,
                                       atoi(optarg));
                break;
            case MODULE_CONFIG_ITEM_BOOL:
                config_PutIntVariable( pp_shortopts[i_cmd]->psz_name, 1 );
                break;
            }

            continue;
        }
gbazin's avatar
   
gbazin committed
900

Sam Hocevar's avatar
   
Sam Hocevar committed
901
902
903
        /* Either it's a -v or it's an unknown short option */
        if( i_cmd == 'v' )
        {
gbazin's avatar
   
gbazin committed
904
            p_main->i_warning_level++;
Sam Hocevar's avatar
   
Sam Hocevar committed
905
906
            continue;
        }
gbazin's avatar
   
gbazin committed
907
908

        /* Internal error: unknown option */
Sam Hocevar's avatar
   
Sam Hocevar committed
909
910
911
912
913
914
915
916
917
918
        if( !b_ignore_errors )
        {
            intf_ErrMsg( "config error: unknown option `%s'",
                         ppsz_argv[optind-1] );
            intf_Msg( "Try `%s --help' for more information.\n",
                      p_main->psz_arg0 );

            free( p_longopts );
            free( psz_shortopts );
            return( -1 );
gbazin's avatar
   
gbazin committed
919
920
921
922
        }
    }

    free( p_longopts );
Sam Hocevar's avatar
   
Sam Hocevar committed
923
    free( psz_shortopts );
gbazin's avatar
   
gbazin committed
924
925
926
927
928
929
930

    /* Update the warning level */
    p_main->i_warning_level += config_GetIntVariable( "warning" );
    p_main->i_warning_level = ( p_main->i_warning_level < 0 ) ? 0 :
        p_main->i_warning_level;
    config_PutIntVariable( "warning", p_main->i_warning_level );

gbazin's avatar
   
gbazin committed
931
932
    return( 0 );
}
Sam Hocevar's avatar
   
Sam Hocevar committed
933

gbazin's avatar
   
gbazin committed
934
/*****************************************************************************
gbazin's avatar
   
gbazin committed
935
 * config_GetHomeDir: find the user's home directory.
gbazin's avatar
   
gbazin committed
936
937
 *****************************************************************************
 * This function will try by different ways to find the user's home path.
gbazin's avatar
   
gbazin committed
938
939
 * Note that this function is not reentrant, it should be called only once
 * at the beginning of main where the result will be stored for later use.
gbazin's avatar
   
gbazin committed
940
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
941
char *config_GetHomeDir( void )
gbazin's avatar
   
gbazin committed
942
943
944
{
    char *p_tmp, *p_homedir = NULL;

gbazin's avatar
   
gbazin committed
945
#if defined(HAVE_GETPWUID)
gbazin's avatar
   
gbazin committed
946
947
948
    struct passwd *p_pw = NULL;
#endif

Sam Hocevar's avatar
   
Sam Hocevar committed
949
950
#if defined(HAVE_GETPWUID)
    if( ( p_pw = getpwuid( getuid() ) ) == NULL )
gbazin's avatar
   
gbazin committed
951
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
952
    {
gbazin's avatar
   
gbazin committed
953
954
        if( ( p_tmp = getenv( "HOME" ) ) == NULL )
        {
gbazin's avatar
   
gbazin committed
955
956
957
            if( ( p_tmp = getenv( "TMP" ) ) == NULL )
            {
                p_homedir = strdup( "/tmp" );
gbazin's avatar
   
gbazin committed
958
            }
gbazin's avatar
   
gbazin committed
959
960
            else p_homedir = strdup( p_tmp );

Sam Hocevar's avatar
   
Sam Hocevar committed
961
            intf_ErrMsg( "config error: unable to get home directory, "
gbazin's avatar
   
gbazin committed
962
963
                         "using %s instead", p_homedir );

gbazin's avatar
   
gbazin committed
964
965
966
        }
        else p_homedir = strdup( p_tmp );
    }
gbazin's avatar
   
gbazin committed
967
#if defined(HAVE_GETPWUID)
gbazin's avatar
   
gbazin committed
968
969
    else
    {
gbazin's avatar
   
gbazin committed
970
        p_homedir = strdup( p_pw->pw_dir );
gbazin's avatar
   
gbazin committed
971
972
973
974
975
    }
#endif

    return p_homedir;
}