configuration.c 36.9 KB
Newer Older
gbazin's avatar
   
gbazin committed
1
2
3
4
/*****************************************************************************
 * configuration.c management of the modules configuration
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
5
 * $Id: configuration.c,v 1.25 2002/05/18 17:53:11 massiot 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
/*****************************************************************************
 * 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,
113
 * and MODULE_CONFIG_ITEM_MODULE).
gbazin's avatar
   
gbazin committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
 *
 * 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
        return NULL;
    }
    if( (p_config->i_type!=MODULE_CONFIG_ITEM_STRING) &&
        (p_config->i_type!=MODULE_CONFIG_ITEM_FILE) &&
134
        (p_config->i_type!=MODULE_CONFIG_ITEM_MODULE) )
gbazin's avatar
   
gbazin committed
135
    {
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

    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,
154
 * and MODULE_CONFIG_ITEM_MODULE).
gbazin's avatar
   
gbazin committed
155
156
157
158
159
160
161
162
163
164
 *****************************************************************************/
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
        return;
    }
    if( (p_config->i_type!=MODULE_CONFIG_ITEM_STRING) &&
        (p_config->i_type!=MODULE_CONFIG_ITEM_FILE) &&
170
        (p_config->i_type!=MODULE_CONFIG_ITEM_MODULE) )
gbazin's avatar
   
gbazin committed
171
    {
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
    if( p_config->p_callback )
    {
        ((void(*)(void))p_config->p_callback)();
    }
gbazin's avatar
   
gbazin committed
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
}

/*****************************************************************************
 * 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
209
        intf_ErrMsg( "config error: option %s doesn't exist", psz_name );
gbazin's avatar
   
gbazin committed
210
211
212
213
214
        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
215
216
        intf_ErrMsg( "config error: option %s doesn't refer to an int",
                     psz_name );
gbazin's avatar
   
gbazin committed
217
218
219
220
        return;
    }

    p_config->i_value = i_value;
221
222
223
224
225

    if( p_config->p_callback )
    {
        ((void(*)(void))p_config->p_callback)();
    }
gbazin's avatar
   
gbazin committed
226
227
}

gbazin's avatar
   
gbazin committed
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*****************************************************************************
 * 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;
254
255
256
257
258

    if( p_config->p_callback )
    {
        ((void(*)(void))p_config->p_callback)();
    }
gbazin's avatar
   
gbazin committed
259
260
}

gbazin's avatar
   
gbazin committed
261
262
263
264
265
266
267
268
/*****************************************************************************
 * 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
269
    module_config_t *p_item;
gbazin's avatar
   
gbazin committed
270
271
272
273
274
275
276

    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
277
278
279
        for( p_item = p_module->p_config;
             p_item->i_type != MODULE_CONFIG_HINT_END;
             p_item++ )
gbazin's avatar
   
gbazin committed
280
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
281
            if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
282
                /* ignore hints */
gbazin's avatar
   
gbazin committed
283
                continue;
Sam Hocevar's avatar
   
Sam Hocevar committed
284
285
            if( !strcmp( psz_name, p_item->psz_name ) )
                return p_item;
gbazin's avatar
   
gbazin committed
286
287
288
289
290
291
292
293
294
295
296
297
298
        }
    }

    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
299
module_config_t *config_Duplicate( module_config_t *p_orig )
gbazin's avatar
   
gbazin committed
300
{
Sam Hocevar's avatar
   
Sam Hocevar committed
301
    int i, i_lines;
gbazin's avatar
   
gbazin committed
302
303
    module_config_t *p_config;

Sam Hocevar's avatar
   
Sam Hocevar committed
304
305
306
307
308
309
310
    /* 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
311
312
    if( p_config == NULL )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
313
        intf_ErrMsg( "config error: can't duplicate p_config" );
gbazin's avatar
   
gbazin committed
314
315
316
        return( NULL );
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
317
318
    /* Do the duplication job */
    for( i = 0; i < i_lines ; i++ )
gbazin's avatar
   
gbazin committed
319
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
320
        p_config[i].i_type = p_orig[i].i_type;
Sam Hocevar's avatar
   
Sam Hocevar committed
321
        p_config[i].i_short = p_orig[i].i_short;
Sam Hocevar's avatar
   
Sam Hocevar committed
322
        p_config[i].i_value = p_orig[i].i_value;
gbazin's avatar
   
gbazin committed
323
        p_config[i].f_value = p_orig[i].f_value;
Sam Hocevar's avatar
   
Sam Hocevar committed
324
325
326
327
328
329
330
331
332
333
        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
334
335
336

        /* 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
337
        p_config[i].p_callback = NULL;
gbazin's avatar
   
gbazin committed
338
339
340
341
    }

    return p_config;
}
gbazin's avatar
   
gbazin committed
342

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
/*****************************************************************************
 * config_SetCallbacks: sets callback functions in the duplicate p_config.
 *****************************************************************************
 * 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 duplicate callbacks each time we reload the module.
 *****************************************************************************/
void config_SetCallbacks( module_config_t *p_new, module_config_t *p_orig )
{
    while( p_new->i_type != MODULE_CONFIG_HINT_END )
    {
        p_new->p_callback = p_orig->p_callback;
        p_new++;
        p_orig++;
    }
}

/*****************************************************************************
 * config_UnsetCallbacks: unsets callback functions in the duplicate p_config.
 *****************************************************************************
 * We simply undo what we did in config_SetCallbacks.
 *****************************************************************************/
void config_UnsetCallbacks( module_config_t *p_new )
{
    while( p_new->i_type != MODULE_CONFIG_HINT_END )
    {
        p_new->p_callback = NULL;
        p_new++;
    }
}

gbazin's avatar
   
gbazin committed
374
375
376
377
378
379
380
381
382
/*****************************************************************************
 * 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
383
    module_config_t *p_item;
gbazin's avatar
   
gbazin committed
384
385
386
387
388
389
390
391
    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
392
    psz_homedir = p_main->psz_homedir;
gbazin's avatar
   
gbazin committed
393
394
    if( !psz_homedir )
    {
gbazin's avatar
   
gbazin committed
395
        intf_ErrMsg( "config error: p_main->psz_homedir is null" );
gbazin's avatar
   
gbazin committed
396
397
398
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
399
    psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
gbazin's avatar
   
gbazin committed
400
401
402
                                   strlen(psz_homedir) + 1 );
    if( !psz_filename )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
403
        intf_ErrMsg( "config error: couldn't malloc psz_filename" );
gbazin's avatar
   
gbazin committed
404
405
406
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
407
    sprintf( psz_filename, "%s/" CONFIG_DIR "/" CONFIG_FILE, psz_homedir );
gbazin's avatar
   
gbazin committed
408

Sam Hocevar's avatar
   
Sam Hocevar committed
409
    intf_WarnMsg( 5, "config: opening config file %s", psz_filename );
gbazin's avatar
   
gbazin committed
410

gbazin's avatar
   
gbazin committed
411
    file = fopen( psz_filename, "rt" );
gbazin's avatar
   
gbazin committed
412
413
    if( !file )
    {
gbazin's avatar
   
gbazin committed
414
415
        intf_WarnMsg( 1, "config: config file %s doesn't already exist",
                         psz_filename );
gbazin's avatar
   
gbazin committed
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
        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
439
440
                intf_WarnMsg( 5, "config: loading config for module <%s>",
                                 p_module->psz_name );
gbazin's avatar
   
gbazin committed
441
442
443
444
445
446
447
448
449
450
451
452

                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 */
gbazin's avatar
   
gbazin committed
453
454
            if( (line[0] == '#') || (line[0] == '\n') || (line[0] == (char)0) )
                continue;
gbazin's avatar
   
gbazin committed
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469

            /* 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
470
471
472
            for( p_item = p_module->p_config;
                 p_item->i_type != MODULE_CONFIG_HINT_END;
                 p_item++ )
gbazin's avatar
   
gbazin committed
473
            {
Sam Hocevar's avatar
   
Sam Hocevar committed
474
                if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
475
476
                    /* ignore hints */
                    continue;
Sam Hocevar's avatar
   
Sam Hocevar committed
477
478

                if( !strcmp( p_item->psz_name, psz_option_name ) )
gbazin's avatar
   
gbazin committed
479
480
                {
                    /* We found it */
Sam Hocevar's avatar
   
Sam Hocevar committed
481
                    switch( p_item->i_type )
gbazin's avatar
   
gbazin committed
482
483
484
                    {
                    case MODULE_CONFIG_ITEM_BOOL:
                    case MODULE_CONFIG_ITEM_INTEGER:
gbazin's avatar
   
gbazin committed
485
486
                        if( !*psz_option_value )
                            break;                    /* ignore empty option */
Sam Hocevar's avatar
   
Sam Hocevar committed
487
                        p_item->i_value = atoi( psz_option_value);
Sam Hocevar's avatar
   
Sam Hocevar committed
488
                        intf_WarnMsg( 7, "config: found <%s> option %s=%i",
Sam Hocevar's avatar
   
Sam Hocevar committed
489
490
                                         p_module->psz_name,
                                         p_item->psz_name, p_item->i_value );
gbazin's avatar
   
gbazin committed
491
492
                        break;

gbazin's avatar
   
gbazin committed
493
494
495
496
497
498
499
500
501
                    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
502
                    default:
Sam Hocevar's avatar
   
Sam Hocevar committed
503
                        vlc_mutex_lock( p_item->p_lock );
gbazin's avatar
   
gbazin committed
504
505

                        /* free old string */
Sam Hocevar's avatar
   
Sam Hocevar committed
506
507
                        if( p_item->psz_value )
                            free( p_item->psz_value );
gbazin's avatar
   
gbazin committed
508

Sam Hocevar's avatar
   
Sam Hocevar committed
509
                        p_item->psz_value = *psz_option_value ?
gbazin's avatar
   
gbazin committed
510
                            strdup( psz_option_value ) : NULL;
gbazin's avatar
   
gbazin committed
511

Sam Hocevar's avatar
   
Sam Hocevar committed
512
                        vlc_mutex_unlock( p_item->p_lock );
gbazin's avatar
   
gbazin committed
513

Sam Hocevar's avatar
   
Sam Hocevar committed
514
                        intf_WarnMsg( 7, "config: found <%s> option %s=%s",
Sam Hocevar's avatar
   
Sam Hocevar committed
515
516
517
518
                                         p_module->psz_name,
                                         p_item->psz_name,
                                         p_item->psz_value != NULL ?
                                           p_item->psz_value : "(NULL)" );
gbazin's avatar
   
gbazin committed
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
                        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.
 *
543
 * When we save we mustn't delete the config options of the modules that
gbazin's avatar
   
gbazin committed
544
545
546
547
548
549
550
551
552
553
554
555
556
 * 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
557
    module_config_t *p_item;
gbazin's avatar
   
gbazin committed
558
559
    FILE *file;
    char p_line[1024], *p_index2;
Sam Hocevar's avatar
   
Sam Hocevar committed
560
    int i_sizebuf = 0;
gbazin's avatar
   
gbazin committed
561
562
563
564
565
566
567
    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
568
    psz_homedir = p_main->psz_homedir;
gbazin's avatar
   
gbazin committed
569
570
    if( !psz_homedir )
    {
gbazin's avatar
   
gbazin committed
571
        intf_ErrMsg( "config error: p_main->psz_homedir is null" );
gbazin's avatar
   
gbazin committed
572
573
574
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
575
    psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
gbazin's avatar
   
gbazin committed
576
577
578
                                   strlen(psz_homedir) + 1 );
    if( !psz_filename )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
579
        intf_ErrMsg( "config error: couldn't malloc psz_filename" );
gbazin's avatar
   
gbazin committed
580
581
582
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
583
    sprintf( psz_filename, "%s/" CONFIG_DIR, psz_homedir );
Sam Hocevar's avatar
   
Sam Hocevar committed
584

gbazin's avatar
   
gbazin committed
585
#ifndef WIN32
Sam Hocevar's avatar
   
Sam Hocevar committed
586
    if( mkdir( psz_filename, 0755 ) && errno != EEXIST )
gbazin's avatar
   
gbazin committed
587
#else
Sam Hocevar's avatar
   
Sam Hocevar committed
588
    if( mkdir( psz_filename ) && errno != EEXIST )
gbazin's avatar
   
gbazin committed
589
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
590
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
591
592
        intf_ErrMsg( "config error: couldn't create %s (%s)",
                     psz_filename, strerror(errno) );
Sam Hocevar's avatar
   
Sam Hocevar committed
593
594
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
595
    strcat( psz_filename, "/" CONFIG_FILE );
gbazin's avatar
   
gbazin committed
596
597


Sam Hocevar's avatar
   
Sam Hocevar committed
598
    intf_WarnMsg( 5, "config: opening config file %s", psz_filename );
gbazin's avatar
   
gbazin committed
599

gbazin's avatar
   
gbazin committed
600
    file = fopen( psz_filename, "rt" );
gbazin's avatar
   
gbazin committed
601
602
    if( !file )
    {
gbazin's avatar
   
gbazin committed
603
604
        intf_WarnMsg( 1, "config: config file %s doesn't already exist",
                         psz_filename );
gbazin's avatar
   
gbazin committed
605
606
607
608
609
610
611
612
613
614
615
616
    }
    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
617
        intf_ErrMsg( "config error: couldn't malloc bigbuffer" );
gbazin's avatar
   
gbazin committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
        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
652
653
                intf_WarnMsg( 5, "config: backing up config for "
                                 "unknown module <%s>", &p_line[1] );
gbazin's avatar
   
gbazin committed
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
                *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
     */

gbazin's avatar
   
gbazin committed
680
    file = fopen( psz_filename, "wt" );
gbazin's avatar
   
gbazin committed
681
682
    if( !file )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
683
684
        intf_WarnMsg( 1, "config: couldn't open config file %s for writing",
                         psz_filename );
gbazin's avatar
   
gbazin committed
685
686
687
688
689
        free( psz_filename );
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
690
    fprintf( file, "###\n###  " COPYRIGHT_MESSAGE "\n###\n\n" );
gbazin's avatar
   
gbazin committed
691
692
693
694
695
696
697
698
699
700
701
702

    /* 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
703
704
        intf_WarnMsg( 5, "config: saving config for module <%s>",
                         p_module->psz_name );
gbazin's avatar
   
gbazin committed
705

gbazin's avatar
   
gbazin committed
706
        fprintf( file, "[%s]", p_module->psz_name );
gbazin's avatar
   
gbazin committed
707
        if( p_module->psz_longname )
gbazin's avatar
   
gbazin committed
708
709
710
            fprintf( file, " # %s\n\n", p_module->psz_longname );
        else
            fprintf( file, "\n\n" );
Sam Hocevar's avatar
   
Sam Hocevar committed
711

Sam Hocevar's avatar
   
Sam Hocevar committed
712
713
714
        for( p_item = p_module->p_config;
             p_item->i_type != MODULE_CONFIG_HINT_END;
             p_item++ )
gbazin's avatar
   
gbazin committed
715
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
716
            if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
717
718
719
                /* ignore hints */
                continue;

Sam Hocevar's avatar
   
Sam Hocevar committed
720
            switch( p_item->i_type )
gbazin's avatar
   
gbazin committed
721
722
723
            {
            case MODULE_CONFIG_ITEM_BOOL:
            case MODULE_CONFIG_ITEM_INTEGER:
Sam Hocevar's avatar
   
Sam Hocevar committed
724
                if( p_item->psz_text )
725
                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
gbazin's avatar
   
gbazin committed
726
                             (p_item->i_type == MODULE_CONFIG_ITEM_BOOL) ?
727
                             _("boolean") : _("integer") );
Sam Hocevar's avatar
   
Sam Hocevar committed
728
729
                fprintf( file, "%s=%i\n", p_item->psz_name,
                         p_item->i_value );
gbazin's avatar
   
gbazin committed
730
731
                break;

gbazin's avatar
   
gbazin committed
732
733
            case MODULE_CONFIG_ITEM_FLOAT:
                if( p_item->psz_text )
734
735
                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
                             _("float") );
gbazin's avatar
   
gbazin committed
736
737
738
739
                fprintf( file, "%s=%f\n", p_item->psz_name,
                         (double)p_item->f_value );
                break;

gbazin's avatar
   
gbazin committed
740
            default:
Sam Hocevar's avatar
   
Sam Hocevar committed
741
                if( p_item->psz_text )
742
743
                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
                             _("string") );
Sam Hocevar's avatar
   
Sam Hocevar committed
744
745
                fprintf( file, "%s=%s\n", p_item->psz_name,
                         p_item->psz_value ? p_item->psz_value : "" );
gbazin's avatar
   
gbazin committed
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
            }
        }

        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
766
767
768
769
770
771
772
773
774
775
/*****************************************************************************
 * 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
776
                        boolean_t b_ignore_errors )
gbazin's avatar
   
gbazin committed
777
{
Sam Hocevar's avatar
   
Sam Hocevar committed
778
    int i_cmd, i_index, i_opts, i_shortopts;
gbazin's avatar
   
gbazin committed
779
    module_t *p_module;
Sam Hocevar's avatar
   
Sam Hocevar committed
780
    module_config_t *p_item;
gbazin's avatar
   
gbazin committed
781
782
783
    struct option *p_longopts;

    /* Short options */
Sam Hocevar's avatar
   
Sam Hocevar committed
784
785
    module_config_t *pp_shortopts[256];
    char *psz_shortopts;
gbazin's avatar
   
gbazin committed
786

787
    /* Reset warning level */
gbazin's avatar
   
gbazin committed
788
789
    p_main->i_warning_level = 0;

gbazin's avatar
   
gbazin committed
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
    /* 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

    /*
817
     * Generate the longopts and shortopts structures used by getopt_long
gbazin's avatar
   
gbazin committed
818
     */
Sam Hocevar's avatar
   
Sam Hocevar committed
819
820

    i_opts = 0;
gbazin's avatar
   
gbazin committed
821
822
823
824
825
826
    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
827
        i_opts += p_module->i_config_items;
gbazin's avatar
   
gbazin committed
828
829
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
830
    p_longopts = malloc( sizeof(struct option) * (i_opts + 1) );
gbazin's avatar
   
gbazin committed
831
832
833
834
835
836
    if( p_longopts == NULL )
    {
        intf_ErrMsg( "config error: couldn't allocate p_longopts" );
        return( -1 );
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
837
838
839
840
841
842
843
844
    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 );
    }

845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
    /* If we are requested to ignore errors, then we must work on a copy
     * of the ppsz_argv array, otherwise getopt_long will reorder it for
     * us, ignoring the arity of the options */
    if( b_ignore_errors )
    {
        ppsz_argv = (char**)malloc( *pi_argc * sizeof(char *) );
        if( ppsz_argv == NULL )
        {
            intf_ErrMsg( "config error: couldn't duplicate ppsz_argv" );
            free( psz_shortopts );
            free( p_longopts );
            return -1;
        }
        memcpy( ppsz_argv, p_main->ppsz_argv, *pi_argc * sizeof(char *) );
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
861
862
863
864
865
866
867
    psz_shortopts[0] = 'v';
    i_shortopts = 1;
    for( i_index = 0; i_index < 256; i_index++ )
    {
        pp_shortopts[i_index] = NULL;
    }

868
    /* Fill the p_longopts and psz_shortopts structures */
gbazin's avatar
   
gbazin committed
869
870
871
872
873
    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
874
875
876
        for( p_item = p_module->p_config;
             p_item->i_type != MODULE_CONFIG_HINT_END;
             p_item++ )
gbazin's avatar
   
gbazin committed
877
        {
878
            /* Ignore hints */
Sam Hocevar's avatar
   
Sam Hocevar committed
879
            if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
880
                continue;
881
882

            /* Add item to long options */
Sam Hocevar's avatar
   
Sam Hocevar committed
883
            p_longopts[i_index].name = p_item->psz_name;
gbazin's avatar
   
gbazin committed
884
            p_longopts[i_index].has_arg =
Sam Hocevar's avatar
   
Sam Hocevar committed
885
                (p_item->i_type == MODULE_CONFIG_ITEM_BOOL)?
gbazin's avatar
   
gbazin committed
886
887
888
                                               no_argument : required_argument;
            p_longopts[i_index].flag = 0;
            p_longopts[i_index].val = 0;
889
890
891
            i_index++;

            /* If item also has a short option, add it */
Sam Hocevar's avatar
   
Sam Hocevar committed
892
893
894
895
896
897
898
899
900
901
902
            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
903
904
905
        }
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
906
907
908
    /* 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
909
910
911
912
913
914
915
916
917

    /*
     * 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
918
        /* A long option has been recognized */
gbazin's avatar
   
gbazin committed
919
920
921
922
923
924
925
926
927
928
929
        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:
930
            case MODULE_CONFIG_ITEM_MODULE:
gbazin's avatar
   
gbazin committed
931
932
933
934
935
                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
936
937
938
939
            case MODULE_CONFIG_ITEM_FLOAT:
                config_PutFloatVariable( p_longopts[i_index].name,
                                         (float)atof(optarg) );
                break;
gbazin's avatar
   
gbazin committed
940
941
942
943
944
945
946
947
            case MODULE_CONFIG_ITEM_BOOL:
                config_PutIntVariable( p_longopts[i_index].name, 1 );
                break;
            }

            continue;
        }

Sam Hocevar's avatar
   
Sam Hocevar committed
948
949
        /* A short option has been recognized */
        if( pp_shortopts[i_cmd] != NULL )
gbazin's avatar
   
gbazin committed
950
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
951
952
953
954
            switch( pp_shortopts[i_cmd]->i_type )
            {
            case MODULE_CONFIG_ITEM_STRING:
            case MODULE_CONFIG_ITEM_FILE:
955
            case MODULE_CONFIG_ITEM_MODULE:
Sam Hocevar's avatar
   
Sam Hocevar committed
956
957
958
959
960
961
962
963
964
965
966
967
968
                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
969

Sam Hocevar's avatar
   
Sam Hocevar committed
970
971
972
        /* Either it's a -v or it's an unknown short option */
        if( i_cmd == 'v' )
        {
gbazin's avatar
   
gbazin committed
973
            p_main->i_warning_level++;
Sam Hocevar's avatar
   
Sam Hocevar committed
974
975
            continue;
        }
gbazin's avatar
   
gbazin committed
976
977

        /* Internal error: unknown option */
Sam Hocevar's avatar
   
Sam Hocevar committed
978
979
980
981
982
983
984
985
986
        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 );
987
            if( b_ignore_errors ) free( ppsz_argv );
Sam Hocevar's avatar
   
Sam Hocevar committed
988
            return( -1 );
gbazin's avatar
   
gbazin committed
989
990
991
992
        }
    }

    free( p_longopts );
Sam Hocevar's avatar
   
Sam Hocevar committed
993
    free( psz_shortopts );
994
    if( b_ignore_errors ) free( ppsz_argv );
gbazin's avatar
   
gbazin committed
995
996

    /* Update the warning level */
997
998
999
1000
    if( !p_main->i_warning_level )
    {
        p_main->i_warning_level += config_GetIntVariable( "warning" );
    }
gbazin's avatar
   
gbazin committed
1001
1002
1003
1004
    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
1005
1006
    return( 0 );
}
Sam Hocevar's avatar
   
Sam Hocevar committed
1007

gbazin's avatar
   
gbazin committed
1008
/*****************************************************************************
gbazin's avatar
   
gbazin committed
1009
 * config_GetHomeDir: find the user's home directory.
gbazin's avatar
   
gbazin committed
1010
1011
 *****************************************************************************
 * This function will try by different ways to find the user's home path.
gbazin's avatar
   
gbazin committed
1012
1013
 * 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
1014
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
1015
char *config_GetHomeDir( void )
gbazin's avatar
   
gbazin committed
1016
1017
1018
{
    char *p_tmp, *p_homedir = NULL;

gbazin's avatar
   
gbazin committed
1019
#if defined(HAVE_GETPWUID)
gbazin's avatar
   
gbazin committed
1020
1021
1022
    struct passwd *p_pw = NULL;
#endif

gbazin's avatar
   
gbazin committed
1023
1024
1025
1026
1027
1028
1029
#ifdef WIN32
    typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
                                               LPTSTR );
#   define CSIDL_FLAG_CREATE 0x8000
#   define CSIDL_APPDATA 0x1A
#   define SHGFP_TYPE_CURRENT 0

gbazin's avatar
   
gbazin committed
1030
    HINSTANCE shfolder_dll;
gbazin's avatar
   
gbazin committed
1031
1032
1033
    SHGETFOLDERPATH SHGetFolderPath ;

    /* load the shell32 dll to retreive SHGetFolderPath */
gbazin's avatar
   
gbazin committed
1034
    if( ( shfolder_dll = LoadLibrary("shfolder.dll") ) != NULL )
gbazin's avatar
   
gbazin committed
1035
    {
gbazin's avatar
   
gbazin committed
1036
        SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
gbazin's avatar
   
gbazin committed
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
                                                  "SHGetFolderPathA" );
        if ( SHGetFolderPath != NULL )
        {
            p_homedir = (char *)malloc( MAX_PATH );
            if( !p_homedir )
            {
                intf_ErrMsg( "config error: couldn't malloc p_homedir" );
                return NULL;
            }

            /* get the "Application Data" folder for the current user */
            if( S_OK == SHGetFolderPath( NULL,
                                         CSIDL_APPDATA | CSIDL_FLAG_CREATE,
                                         NULL, SHGFP_TYPE_CURRENT,
                                         p_homedir ) )
            {
gbazin's avatar
   
gbazin committed
1053
                FreeLibrary( shfolder_dll );
gbazin's avatar
   
gbazin committed
1054
1055
1056
1057
                return p_homedir;
            }
            free( p_homedir );
        }
gbazin's avatar
   
gbazin committed
1058
        FreeLibrary( shfolder_dll );
gbazin's avatar
   
gbazin committed
1059
1060
1061
    }
#endif

Sam Hocevar's avatar
   
Sam Hocevar committed
1062
1063
#if defined(HAVE_GETPWUID)
    if( ( p_pw = getpwuid( getuid() ) ) == NULL )
gbazin's avatar
   
gbazin committed
1064
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
1065
    {
gbazin's avatar
   
gbazin committed
1066
1067
        if( ( p_tmp = getenv( "HOME" ) ) == NULL )
        {
gbazin's avatar
   
gbazin committed
1068
1069
1070
            if( ( p_tmp = getenv( "TMP" ) ) == NULL )
            {
                p_homedir = strdup( "/tmp" );
gbazin's avatar
   
gbazin committed
1071
            }
gbazin's avatar
   
gbazin committed
1072
1073
            else p_homedir = strdup( p_tmp );

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

gbazin's avatar
   
gbazin committed
1077
1078
1079
        }
        else p_homedir = strdup( p_tmp );
    }
gbazin's avatar
   
gbazin committed
1080
#if defined(HAVE_GETPWUID)
gbazin's avatar
   
gbazin committed
1081
1082
    else
    {
gbazin's avatar
   
gbazin committed
1083
        p_homedir = strdup( p_pw->pw_dir );
gbazin's avatar
   
gbazin committed
1084
1085
1086
1087
1088
    }
#endif

    return p_homedir;
}