configuration.c 36.1 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.22 2002/05/03 20:49:30 sam 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 )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
414
415
        intf_WarnMsg( 1, "config: couldn't open config file %s for reading (%s)",
                         psz_filename, strerror(errno) );
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
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468

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

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

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

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

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

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

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

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

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


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

gbazin's avatar
   
gbazin committed
599
    file = fopen( psz_filename, "rt" );
gbazin's avatar
   
gbazin committed
600
601
    if( !file )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
602
603
        intf_WarnMsg( 1, "config: couldn't open config file %s for reading (%s)",
                         psz_filename, strerror(errno) );
gbazin's avatar
   
gbazin committed
604
605
606
607
608
609
610
611
612
613
614
615
    }
    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
616
        intf_ErrMsg( "config error: couldn't malloc bigbuffer" );
gbazin's avatar
   
gbazin committed
617
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
        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
651
652
                intf_WarnMsg( 5, "config: backing up config for "
                                 "unknown module <%s>", &p_line[1] );
gbazin's avatar
   
gbazin committed
653
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
                *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
679
    file = fopen( psz_filename, "wt" );
gbazin's avatar
   
gbazin committed
680
681
    if( !file )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
682
683
        intf_WarnMsg( 1, "config: couldn't open config file %s for writing",
                         psz_filename );
gbazin's avatar
   
gbazin committed
684
685
686
687
688
        free( psz_filename );
        vlc_mutex_unlock( &p_main->config_lock );
        return -1;
    }

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

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

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

gbazin's avatar
   
gbazin committed
707
        if( p_module->psz_longname )
Sam Hocevar's avatar
   
Sam Hocevar committed
708
709
            fprintf( file, "###\n###  %s\n###\n", p_module->psz_longname );

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

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

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

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

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

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

gbazin's avatar
   
gbazin committed
785
786
787
    /* reset warning level */
    p_main->i_warning_level = 0;

gbazin's avatar
   
gbazin committed
788
789
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
    /* 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
815
     * Generate the longopts and shortopts structure used by getopt_long
gbazin's avatar
   
gbazin committed
816
     */
Sam Hocevar's avatar
   
Sam Hocevar committed
817
818

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

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

Sam Hocevar's avatar
   
Sam Hocevar committed
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
    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
850
851
852
853
854
855
    /* 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
856
857
858
        for( p_item = p_module->p_config;
             p_item->i_type != MODULE_CONFIG_HINT_END;
             p_item++ )
gbazin's avatar
   
gbazin committed
859
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
860
            if( p_item->i_type & MODULE_CONFIG_HINT )
gbazin's avatar
   
gbazin committed
861
862
                /* ignore hints */
                continue;
Sam Hocevar's avatar
   
Sam Hocevar committed
863
            p_longopts[i_index].name = p_item->psz_name;
gbazin's avatar
   
gbazin committed
864
            p_longopts[i_index].has_arg =
Sam Hocevar's avatar
   
Sam Hocevar committed
865
                (p_item->i_type == MODULE_CONFIG_ITEM_BOOL)?
gbazin's avatar
   
gbazin committed
866
867
868
                                               no_argument : required_argument;
            p_longopts[i_index].flag = 0;
            p_longopts[i_index].val = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
869
870
871
872
873
874
875
876
877
878
879
            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
880
881
882
883
            i_index++;
        }
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
884
885
886
    /* 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
887
888
889
890
891
892
893
894
895

    /*
     * 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
896
        /* A long option has been recognized */
gbazin's avatar
   
gbazin committed
897
898
899
900
901
902
903
904
905
906
907
        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:
908
            case MODULE_CONFIG_ITEM_MODULE:
gbazin's avatar
   
gbazin committed
909
910
911
912
913
                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
914
915
916
917
            case MODULE_CONFIG_ITEM_FLOAT:
                config_PutFloatVariable( p_longopts[i_index].name,
                                         (float)atof(optarg) );
                break;
gbazin's avatar
   
gbazin committed
918
919
920
921
922
923
924
925
            case MODULE_CONFIG_ITEM_BOOL:
                config_PutIntVariable( p_longopts[i_index].name, 1 );
                break;
            }

            continue;
        }

Sam Hocevar's avatar
   
Sam Hocevar committed
926
927
        /* A short option has been recognized */
        if( pp_shortopts[i_cmd] != NULL )
gbazin's avatar
   
gbazin committed
928
        {
Sam Hocevar's avatar
   
Sam Hocevar committed
929
930
931
932
            switch( pp_shortopts[i_cmd]->i_type )
            {
            case MODULE_CONFIG_ITEM_STRING:
            case MODULE_CONFIG_ITEM_FILE:
933
            case MODULE_CONFIG_ITEM_MODULE:
Sam Hocevar's avatar
   
Sam Hocevar committed
934
935
936
937
938
939
940
941
942
943
944
945
946
                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
947

Sam Hocevar's avatar
   
Sam Hocevar committed
948
949
950
        /* Either it's a -v or it's an unknown short option */
        if( i_cmd == 'v' )
        {
gbazin's avatar
   
gbazin committed
951
            p_main->i_warning_level++;
Sam Hocevar's avatar
   
Sam Hocevar committed
952
953
            continue;
        }
gbazin's avatar
   
gbazin committed
954
955

        /* Internal error: unknown option */
Sam Hocevar's avatar
   
Sam Hocevar committed
956
957
958
959
960
961
962
963
964
965
        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
966
967
968
969
        }
    }

    free( p_longopts );
Sam Hocevar's avatar
   
Sam Hocevar committed
970
    free( psz_shortopts );
gbazin's avatar
   
gbazin committed
971
972
973
974
975
976
977

    /* 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
978
979
    return( 0 );
}
Sam Hocevar's avatar
   
Sam Hocevar committed
980

gbazin's avatar
   
gbazin committed
981
/*****************************************************************************
gbazin's avatar
   
gbazin committed
982
 * config_GetHomeDir: find the user's home directory.
gbazin's avatar
   
gbazin committed
983
984
 *****************************************************************************
 * This function will try by different ways to find the user's home path.
gbazin's avatar
   
gbazin committed
985
986
 * 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
987
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
988
char *config_GetHomeDir( void )
gbazin's avatar
   
gbazin committed
989
990
991
{
    char *p_tmp, *p_homedir = NULL;

gbazin's avatar
   
gbazin committed
992
#if defined(HAVE_GETPWUID)
gbazin's avatar
   
gbazin committed
993
994
995
    struct passwd *p_pw = NULL;
#endif

gbazin's avatar
   
gbazin committed
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
#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

    HINSTANCE shell32_dll;
    SHGETFOLDERPATH SHGetFolderPath ;

    /* load the shell32 dll to retreive SHGetFolderPath */
    if( ( shell32_dll = LoadLibrary("shell32.dll") ) != NULL )
    {
        SHGetFolderPath = (void *)GetProcAddress( shell32_dll,
                                                  "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 ) )
            {
                FreeLibrary( shell32_dll );
                return p_homedir;
            }
            free( p_homedir );
        }
        FreeLibrary( shell32_dll );
    }
#endif

Sam Hocevar's avatar
   
Sam Hocevar committed
1035
1036
#if defined(HAVE_GETPWUID)
    if( ( p_pw = getpwuid( getuid() ) ) == NULL )
gbazin's avatar
   
gbazin committed
1037
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
1038
    {
gbazin's avatar
   
gbazin committed
1039
1040
        if( ( p_tmp = getenv( "HOME" ) ) == NULL )
        {
gbazin's avatar
   
gbazin committed
1041
1042
1043
            if( ( p_tmp = getenv( "TMP" ) ) == NULL )
            {
                p_homedir = strdup( "/tmp" );
gbazin's avatar
   
gbazin committed
1044
            }
gbazin's avatar
   
gbazin committed
1045
1046
            else p_homedir = strdup( p_tmp );

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

gbazin's avatar
   
gbazin committed
1050
1051
1052
        }
        else p_homedir = strdup( p_tmp );
    }
gbazin's avatar
   
gbazin committed
1053
#if defined(HAVE_GETPWUID)
gbazin's avatar
   
gbazin committed
1054
1055
    else
    {
gbazin's avatar
   
gbazin committed
1056
        p_homedir = strdup( p_pw->pw_dir );
gbazin's avatar
   
gbazin committed
1057
1058
1059
1060
1061
    }
#endif

    return p_homedir;
}