configuration.c 60.3 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1 2 3
/*****************************************************************************
 * configuration.c management of the modules configuration
 *****************************************************************************
4
 * Copyright (C) 2001-2007 the VideoLAN team
5
 * $Id$
Gildas Bazin's avatar
 
Gildas Bazin committed
6
 *
7
 * Authors: Gildas Bazin <gbazin@videolan.org>
Gildas Bazin's avatar
 
Gildas Bazin committed
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Gildas Bazin's avatar
 
Gildas Bazin committed
22
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
23

24
#include <vlc/vlc.h>
25
#include "vlc_keys.h"
Clément Stenac's avatar
Clément Stenac committed
26
#include "vlc_charset.h"
Gildas Bazin's avatar
 
Gildas Bazin committed
27

Gildas Bazin's avatar
 
Gildas Bazin committed
28
#include <stdio.h>                                              /* sprintf() */
Gildas Bazin's avatar
 
Gildas Bazin committed
29
#include <stdlib.h>                                      /* free(), strtol() */
Gildas Bazin's avatar
 
Gildas Bazin committed
30
#include <string.h>                                              /* strdup() */
31
#include <errno.h>                                                  /* errno */
Gildas Bazin's avatar
 
Gildas Bazin committed
32

33 34 35 36
#ifdef HAVE_LIMITS_H
#   include <limits.h>
#endif

Gildas Bazin's avatar
 
Gildas Bazin committed
37 38 39
#ifdef HAVE_UNISTD_H
#    include <unistd.h>                                          /* getuid() */
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
40

Gildas Bazin's avatar
 
Gildas Bazin committed
41 42 43 44 45
#ifdef HAVE_GETOPT_LONG
#   ifdef HAVE_GETOPT_H
#       include <getopt.h>                                       /* getopt() */
#   endif
#else
46
#   include "../extras/getopt.h"
Gildas Bazin's avatar
 
Gildas Bazin committed
47 48 49
#endif

#if defined(HAVE_GETPWUID)
50
#   include <pwd.h>                                            /* getpwuid() */
Gildas Bazin's avatar
 
Gildas Bazin committed
51 52
#endif

53 54 55 56 57 58
#if defined( HAVE_SYS_STAT_H )
#   include <sys/stat.h>
#endif
#if defined( HAVE_SYS_TYPES_H )
#   include <sys/types.h>
#endif
59 60 61 62 63
#if defined( WIN32 )
#   if !defined( UNDER_CE )
#       include <direct.h>
#   endif
#include <tchar.h>
64
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
65

Clément Stenac's avatar
Clément Stenac committed
66
#include "configuration.h"
67
#include "modules/modules.h"
Clément Stenac's avatar
Clément Stenac committed
68

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
69
static int ConfigStringToKey( const char * );
70
static char *ConfigKeyToString( int );
71

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
static inline void freenull (const void *p)
{
    if (p != NULL)
        free ((void *)p);
}

static inline char *strdupnull (const char *src)
{
    if (src == NULL)
        return NULL;
    return strdup (src);
}

static inline char *_strdupnull (const char *src)
{
    if (src == NULL)
        return NULL;
    return strdup (_(src));
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
/* Item types that use a string value (i.e. serialized in the module cache) */
int IsConfigStringType (int type)
{
    static const unsigned char config_types[] = 
    {
        CONFIG_ITEM_STRING, CONFIG_ITEM_FILE, CONFIG_ITEM_MODULE,
        CONFIG_ITEM_DIRECTORY, CONFIG_ITEM_MODULE_CAT,
        CONFIG_ITEM_MODULE_LIST, CONFIG_ITEM_MODULE_LIST_CAT
    };

    /* NOTE: this needs to be changed if we ever get more than 255 types */
    return memchr (config_types, type, sizeof (config_types)) != NULL;
}


static int IsConfigIntegerType (int type)
{
    static const unsigned char config_types[] = 
    {
        CONFIG_ITEM_INTEGER, CONFIG_ITEM_KEY, CONFIG_ITEM_BOOL,
        CONFIG_CATEGORY, CONFIG_SUBCATEGORY
    };

    return memchr (config_types, type, sizeof (config_types)) != NULL;
}


static inline int IsConfigFloatType (int type)
{
    return type == CONFIG_ITEM_FLOAT;
}

124

Gildas Bazin's avatar
 
Gildas Bazin committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
/*****************************************************************************
 * config_GetType: get the type of a variable (bool, int, float, string)
 *****************************************************************************
 * This function is used to get the type of a variable from its name.
 * Beware, this is quite slow.
 *****************************************************************************/
int __config_GetType( vlc_object_t *p_this, const char *psz_name )
{
    module_config_t *p_config;
    int i_type;

    p_config = config_FindConfig( p_this, psz_name );

    /* sanity checks */
    if( !p_config )
    {
        return 0;
    }

    switch( p_config->i_type )
    {
    case CONFIG_ITEM_BOOL:
        i_type = VLC_VAR_BOOL;
        break;

    case CONFIG_ITEM_INTEGER:
        i_type = VLC_VAR_INTEGER;
        break;

    case CONFIG_ITEM_FLOAT:
        i_type = VLC_VAR_FLOAT;
        break;

    case CONFIG_ITEM_MODULE:
159 160 161
    case CONFIG_ITEM_MODULE_CAT:
    case CONFIG_ITEM_MODULE_LIST:
    case CONFIG_ITEM_MODULE_LIST_CAT:
Gildas Bazin's avatar
 
Gildas Bazin committed
162 163 164
        i_type = VLC_VAR_MODULE;
        break;

Gildas Bazin's avatar
 
Gildas Bazin committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
    case CONFIG_ITEM_STRING:
        i_type = VLC_VAR_STRING;
        break;

    case CONFIG_ITEM_FILE:
        i_type = VLC_VAR_FILE;
        break;

    case CONFIG_ITEM_DIRECTORY:
        i_type = VLC_VAR_DIRECTORY;
        break;

    default:
        i_type = 0;
        break;
    }

    return i_type;
}

Gildas Bazin's avatar
 
Gildas Bazin committed
185
/*****************************************************************************
186
 * config_GetInt: get the value of an int variable
Gildas Bazin's avatar
 
Gildas Bazin committed
187 188
 *****************************************************************************
 * This function is used to get the value of variables which are internally
Gildas Bazin's avatar
 
Gildas Bazin committed
189 190
 * represented by an integer (CONFIG_ITEM_INTEGER and
 * CONFIG_ITEM_BOOL).
Gildas Bazin's avatar
 
Gildas Bazin committed
191
 *****************************************************************************/
192
int __config_GetInt( vlc_object_t *p_this, const char *psz_name )
Gildas Bazin's avatar
 
Gildas Bazin committed
193 194 195
{
    module_config_t *p_config;

196
    p_config = config_FindConfig( p_this, psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
197 198 199 200

    /* sanity checks */
    if( !p_config )
    {
201
        msg_Err( p_this, "option %s does not exist", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
202 203
        return -1;
    }
204 205

    if (!IsConfigIntegerType (p_config->i_type))
Gildas Bazin's avatar
 
Gildas Bazin committed
206
    {
207
        msg_Err( p_this, "option %s does not refer to an int", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
208 209 210
        return -1;
    }

211
    return p_config->value.i;
Gildas Bazin's avatar
 
Gildas Bazin committed
212 213
}

Gildas Bazin's avatar
 
Gildas Bazin committed
214
/*****************************************************************************
215
 * config_GetFloat: get the value of a float variable
Gildas Bazin's avatar
 
Gildas Bazin committed
216 217
 *****************************************************************************
 * This function is used to get the value of variables which are internally
Gildas Bazin's avatar
 
Gildas Bazin committed
218
 * represented by a float (CONFIG_ITEM_FLOAT).
Gildas Bazin's avatar
 
Gildas Bazin committed
219
 *****************************************************************************/
220
float __config_GetFloat( vlc_object_t *p_this, const char *psz_name )
Gildas Bazin's avatar
 
Gildas Bazin committed
221 222 223
{
    module_config_t *p_config;

224
    p_config = config_FindConfig( p_this, psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
225 226 227 228

    /* sanity checks */
    if( !p_config )
    {
229
        msg_Err( p_this, "option %s does not exist", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
230 231
        return -1;
    }
232 233

    if (!IsConfigFloatType (p_config->i_type))
Gildas Bazin's avatar
 
Gildas Bazin committed
234
    {
235
        msg_Err( p_this, "option %s does not refer to a float", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
236 237 238
        return -1;
    }

239
    return p_config->value.f;
Gildas Bazin's avatar
 
Gildas Bazin committed
240 241
}

Gildas Bazin's avatar
 
Gildas Bazin committed
242
/*****************************************************************************
243
 * config_GetPsz: get the string value of a string variable
Gildas Bazin's avatar
 
Gildas Bazin committed
244 245
 *****************************************************************************
 * This function is used to get the value of variables which are internally
Gildas Bazin's avatar
 
Gildas Bazin committed
246
 * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_FILE,
Gildas Bazin's avatar
 
Gildas Bazin committed
247
 * CONFIG_ITEM_DIRECTORY, and CONFIG_ITEM_MODULE).
Gildas Bazin's avatar
 
Gildas Bazin committed
248
 *
Gildas Bazin's avatar
 
Gildas Bazin committed
249 250 251
 * Important note: remember to free() the returned char* because it's 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.
Gildas Bazin's avatar
 
Gildas Bazin committed
252
 *****************************************************************************/
253
char * __config_GetPsz( vlc_object_t *p_this, const char *psz_name )
Gildas Bazin's avatar
 
Gildas Bazin committed
254 255 256
{
    module_config_t *p_config;

257
    p_config = config_FindConfig( p_this, psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
258 259 260 261

    /* sanity checks */
    if( !p_config )
    {
262
        msg_Err( p_this, "option %s does not exist", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
263 264
        return NULL;
    }
265 266

    if (!IsConfigStringType (p_config->i_type))
Gildas Bazin's avatar
 
Gildas Bazin committed
267
    {
268
        msg_Err( p_this, "option %s does not refer to a string", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
269 270 271 272
        return NULL;
    }

    /* return a copy of the string */
Gildas Bazin's avatar
 
Gildas Bazin committed
273
    vlc_mutex_lock( p_config->p_lock );
274
    char *psz_value = strdupnull (p_config->value.psz);
Gildas Bazin's avatar
 
Gildas Bazin committed
275
    vlc_mutex_unlock( p_config->p_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
276 277 278 279 280

    return psz_value;
}

/*****************************************************************************
281
 * config_PutPsz: set the string value of a string variable
Gildas Bazin's avatar
 
Gildas Bazin committed
282 283
 *****************************************************************************
 * This function is used to set the value of variables which are internally
Gildas Bazin's avatar
 
Gildas Bazin committed
284
 * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_FILE,
Gildas Bazin's avatar
 
Gildas Bazin committed
285
 * CONFIG_ITEM_DIRECTORY, and CONFIG_ITEM_MODULE).
Gildas Bazin's avatar
 
Gildas Bazin committed
286
 *****************************************************************************/
287
void __config_PutPsz( vlc_object_t *p_this,
288
                      const char *psz_name, const char *psz_value )
Gildas Bazin's avatar
 
Gildas Bazin committed
289 290
{
    module_config_t *p_config;
Gildas Bazin's avatar
 
Gildas Bazin committed
291
    vlc_value_t oldval, val;
Gildas Bazin's avatar
 
Gildas Bazin committed
292

293
    p_config = config_FindConfig( p_this, psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
294

Clément Stenac's avatar
Clément Stenac committed
295

Gildas Bazin's avatar
 
Gildas Bazin committed
296 297 298
    /* sanity checks */
    if( !p_config )
    {
299
        msg_Warn( p_this, "option %s does not exist", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
300 301
        return;
    }
302 303

    if (!IsConfigStringType (p_config->i_type))
Gildas Bazin's avatar
 
Gildas Bazin committed
304
    {
305
        msg_Err( p_this, "option %s does not refer to a string", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
306 307 308
        return;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
309 310
    vlc_mutex_lock( p_config->p_lock );

Gildas Bazin's avatar
 
Gildas Bazin committed
311
    /* backup old value */
312
    oldval.psz_string = (char *)p_config->value.psz;
Gildas Bazin's avatar
 
Gildas Bazin committed
313

314 315 316 317
    if ((psz_value != NULL) && *psz_value)
        p_config->value.psz = strdup (psz_value);
    else
        p_config->value.psz = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
318

319 320
    p_config->b_dirty = VLC_TRUE;

321
    val.psz_string = (char *)p_config->value.psz;
Gildas Bazin's avatar
 
Gildas Bazin committed
322

Gildas Bazin's avatar
 
Gildas Bazin committed
323
    vlc_mutex_unlock( p_config->p_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
324

325
    if( p_config->pf_callback )
326
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
327 328
        p_config->pf_callback( p_this, psz_name, oldval, val,
                               p_config->p_callback_data );
329
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
330 331 332

    /* free old string */
    if( oldval.psz_string ) free( oldval.psz_string );
Gildas Bazin's avatar
 
Gildas Bazin committed
333 334 335
}

/*****************************************************************************
336
 * config_PutInt: set the integer value of an int variable
Gildas Bazin's avatar
 
Gildas Bazin committed
337 338
 *****************************************************************************
 * This function is used to set the value of variables which are internally
Gildas Bazin's avatar
 
Gildas Bazin committed
339 340
 * represented by an integer (CONFIG_ITEM_INTEGER and
 * CONFIG_ITEM_BOOL).
Gildas Bazin's avatar
 
Gildas Bazin committed
341
 *****************************************************************************/
342
void __config_PutInt( vlc_object_t *p_this, const char *psz_name, int i_value )
Gildas Bazin's avatar
 
Gildas Bazin committed
343 344
{
    module_config_t *p_config;
Gildas Bazin's avatar
 
Gildas Bazin committed
345
    vlc_value_t oldval, val;
Gildas Bazin's avatar
 
Gildas Bazin committed
346

347
    p_config = config_FindConfig( p_this, psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
348 349 350 351

    /* sanity checks */
    if( !p_config )
    {
352
        msg_Warn( p_this, "option %s does not exist", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
353 354
        return;
    }
355 356

    if (!IsConfigIntegerType (p_config->i_type))
Gildas Bazin's avatar
 
Gildas Bazin committed
357
    {
358
        msg_Err( p_this, "option %s does not refer to an int", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
359 360 361
        return;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
362
    /* backup old value */
363
    oldval.i_int = p_config->value.i;
Gildas Bazin's avatar
 
Gildas Bazin committed
364

365
    /* if i_min == i_max == 0, then do not use them */
366
    if ((p_config->min.i == 0) && (p_config->max.i == 0))
367
    {
368
        p_config->value.i = i_value;
369
    }
370
    else if (i_value < p_config->min.i)
371
    {
372
        p_config->value.i = p_config->min.i;
373
    }
374
    else if (i_value > p_config->max.i)
375
    {
376
        p_config->value.i = p_config->max.i;
377 378 379
    }
    else
    {
380
        p_config->value.i = i_value;
381
    }
382

383 384
    p_config->b_dirty = VLC_TRUE;

385
    val.i_int = p_config->value.i;
Gildas Bazin's avatar
 
Gildas Bazin committed
386

387
    if( p_config->pf_callback )
388
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
389 390
        p_config->pf_callback( p_this, psz_name, oldval, val,
                               p_config->p_callback_data );
391
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
392 393
}

Gildas Bazin's avatar
 
Gildas Bazin committed
394
/*****************************************************************************
395
 * config_PutFloat: set the value of a float variable
Gildas Bazin's avatar
 
Gildas Bazin committed
396 397
 *****************************************************************************
 * This function is used to set the value of variables which are internally
Gildas Bazin's avatar
 
Gildas Bazin committed
398
 * represented by a float (CONFIG_ITEM_FLOAT).
Gildas Bazin's avatar
 
Gildas Bazin committed
399
 *****************************************************************************/
400 401
void __config_PutFloat( vlc_object_t *p_this,
                        const char *psz_name, float f_value )
Gildas Bazin's avatar
 
Gildas Bazin committed
402 403
{
    module_config_t *p_config;
Gildas Bazin's avatar
 
Gildas Bazin committed
404
    vlc_value_t oldval, val;
Gildas Bazin's avatar
 
Gildas Bazin committed
405

406
    p_config = config_FindConfig( p_this, psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
407 408 409 410

    /* sanity checks */
    if( !p_config )
    {
411
        msg_Warn( p_this, "option %s does not exist", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
412 413
        return;
    }
414 415

    if (!IsConfigFloatType (p_config->i_type))
Gildas Bazin's avatar
 
Gildas Bazin committed
416
    {
417
        msg_Err( p_this, "option %s does not refer to a float", psz_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
418 419 420
        return;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
421
    /* backup old value */
422
    oldval.f_float = p_config->value.f;
Gildas Bazin's avatar
 
Gildas Bazin committed
423

424
    /* if f_min == f_max == 0, then do not use them */
425
    if ((p_config->min.f == 0) && (p_config->max.f == 0))
426
    {
427
        p_config->value.f = f_value;
428
    }
429
    else if (f_value < p_config->min.f)
430
    {
431
        p_config->value.f = p_config->min.f;
432
    }
433
    else if (f_value > p_config->max.f)
434
    {
435
        p_config->value.f = p_config->max.f;
436 437 438
    }
    else
    {
439
        p_config->value.f = f_value;
440
    }
441

442 443
    p_config->b_dirty = VLC_TRUE;

444
    val.f_float = p_config->value.f;
Gildas Bazin's avatar
 
Gildas Bazin committed
445

446
    if( p_config->pf_callback )
447
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
448 449
        p_config->pf_callback( p_this, psz_name, oldval, val,
                               p_config->p_callback_data );
450
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
451 452
}

Gildas Bazin's avatar
 
Gildas Bazin committed
453 454 455 456
/*****************************************************************************
 * config_FindConfig: find the config structure associated with an option.
 *****************************************************************************
 * FIXME: This function really needs to be optimized.
457
 * FIXME: And now even more.
Gildas Bazin's avatar
 
Gildas Bazin committed
458
 *****************************************************************************/
459
module_config_t *config_FindConfig( vlc_object_t *p_this, const char *psz_name )
Gildas Bazin's avatar
 
Gildas Bazin committed
460
{
461
    vlc_list_t *p_list;
Gildas Bazin's avatar
 
Gildas Bazin committed
462
    int i_index;
Gildas Bazin's avatar
 
Gildas Bazin committed
463 464 465

    if( !psz_name ) return NULL;

466
    p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
467

468
    for( i_index = 0; i_index < p_list->i_count; i_index++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
469
    {
470 471
        module_config_t *p_item, *p_end;
        module_t *p_parser = (module_t *)p_list->p_values[i_index].p_object;
Gildas Bazin's avatar
 
Gildas Bazin committed
472 473

        if( !p_parser->i_config_items )
474 475
            continue;

476 477
        for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
             p_item < p_end;
Sam Hocevar's avatar
 
Sam Hocevar committed
478
             p_item++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
479
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
480
            if( p_item->i_type & CONFIG_HINT )
Gildas Bazin's avatar
 
Gildas Bazin committed
481
                /* ignore hints */
Gildas Bazin's avatar
 
Gildas Bazin committed
482
                continue;
Sam Hocevar's avatar
 
Sam Hocevar committed
483
            if( !strcmp( psz_name, p_item->psz_name ) )
484
            {
485
                vlc_list_release( p_list );
Sam Hocevar's avatar
 
Sam Hocevar committed
486
                return p_item;
487
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
488 489 490
        }
    }

491
    vlc_list_release( p_list );
492

Gildas Bazin's avatar
 
Gildas Bazin committed
493 494 495
    return NULL;
}

496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
/*****************************************************************************
 * config_FindModule: find a specific module structure.
 *****************************************************************************/
module_t *config_FindModule( vlc_object_t *p_this, const char *psz_name )
{
    vlc_list_t *p_list;
    module_t *p_module, *p_result = NULL;
    int i_index;

    if( !psz_name ) return NULL;

    p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );

    for( i_index = 0; i_index < p_list->i_count; i_index++ )
    {
        p_module = (module_t *)p_list->p_values[i_index].p_object;
        if( !strcmp( p_module->psz_object_name, psz_name ) )
        {
             p_result = p_module;
             break;
        }
    }

    vlc_list_release( p_list );

    return p_result;
}

Gildas Bazin's avatar
 
Gildas Bazin committed
524 525 526 527 528 529 530
/*****************************************************************************
 * 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.
 *****************************************************************************/
531 532
int config_Duplicate( module_t *p_module, const module_config_t *p_orig,
                      size_t n )
Gildas Bazin's avatar
 
Gildas Bazin committed
533
{
534 535
    int j;
    const module_config_t *p_item, *p_end = p_orig + n;
Gildas Bazin's avatar
 
Gildas Bazin committed
536

Sam Hocevar's avatar
 
Sam Hocevar committed
537
    /* Calculate the structure length */
538 539 540
    p_module->i_config_items = 0;
    p_module->i_bool_items = 0;

541
    for( p_item = p_orig; p_item < p_end; p_item++ )
542
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
543
        if( p_item->i_type & CONFIG_ITEM )
544 545 546 547
        {
            p_module->i_config_items++;
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
548
        if( p_item->i_type == CONFIG_ITEM_BOOL )
549 550 551 552
        {
            p_module->i_bool_items++;
        }
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
553 554

    /* Allocate memory */
555
    p_module->p_config = (module_config_t *)calloc( n, sizeof(*p_orig) );
556
    if( p_module->p_config == NULL )
Gildas Bazin's avatar
 
Gildas Bazin committed
557
    {
558
        msg_Err( p_module, "config error: can't duplicate p_config" );
559
        return VLC_ENOMEM;
Gildas Bazin's avatar
 
Gildas Bazin committed
560
    }
561
    p_module->confsize = n;
Gildas Bazin's avatar
 
Gildas Bazin committed
562

Sam Hocevar's avatar
 
Sam Hocevar committed
563
    /* Do the duplication job */
564
    for( size_t i = 0; i < n ; i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
565
    {
566
        p_module->p_config[i] = p_orig[i];
Sam Hocevar's avatar
 
Sam Hocevar committed
567

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
        if (IsConfigIntegerType (p_module->p_config[i].i_type))
        {
            p_module->p_config[i].orig.i = p_orig[i].value.i;
            p_module->p_config[i].saved.i = p_orig[i].value.i;
        }
        else
        if (IsConfigFloatType (p_module->p_config[i].i_type))
        {
            p_module->p_config[i].orig.f = p_orig[i].value.f;
            p_module->p_config[i].saved.f = p_orig[i].value.f;
        }
        else
        if (IsConfigStringType (p_module->p_config[i].i_type))
        {
            p_module->p_config[i].value.psz = strdupnull (p_orig[i].value.psz);
            p_module->p_config[i].orig.psz = strdupnull (p_orig[i].value.psz);
            p_module->p_config[i].saved.psz = NULL;
        }

        p_module->p_config[i].psz_type = strdupnull (p_orig[i].psz_type);
        p_module->p_config[i].psz_name = strdupnull (p_orig[i].psz_name);
        p_module->p_config[i].psz_current = strdupnull (p_orig[i].psz_current);
        p_module->p_config[i].psz_text = _strdupnull (p_orig[i].psz_text);
        p_module->p_config[i].psz_longtext = _strdupnull (p_orig[i].psz_longtext);
Gildas Bazin's avatar
 
Gildas Bazin committed
592

Sam Hocevar's avatar
Sam Hocevar committed
593
        p_module->p_config[i].p_lock = &p_module->object_lock;
594

Gildas Bazin's avatar
 
Gildas Bazin committed
595
        /* duplicate the string list */
596
        if( p_orig[i].i_list )
Gildas Bazin's avatar
 
Gildas Bazin committed
597
        {
598
            if( p_orig[i].ppsz_list )
Gildas Bazin's avatar
 
Gildas Bazin committed
599
            {
600 601 602 603 604
                p_module->p_config[i].ppsz_list =
                    malloc( (p_orig[i].i_list + 1) * sizeof(char *) );
                if( p_module->p_config[i].ppsz_list )
                {
                    for( j = 0; j < p_orig[i].i_list; j++ )
605 606
                        p_module->p_config[i].ppsz_list[j] =
                                strdupnull (p_orig[i].ppsz_list[j]);
607 608 609 610 611 612
                    p_module->p_config[i].ppsz_list[j] = NULL;
                }
            }
            if( p_orig[i].ppsz_list_text )
            {
                p_module->p_config[i].ppsz_list_text =
613
                    calloc( (p_orig[i].i_list + 1), sizeof(char *) );
614 615 616
                if( p_module->p_config[i].ppsz_list_text )
                {
                    for( j = 0; j < p_orig[i].i_list; j++ )
617 618
                        p_module->p_config[i].ppsz_list_text[j] =
                                strdupnull (_(p_orig[i].ppsz_list_text[j]));
619 620 621 622 623 624 625 626 627 628 629 630 631
                    p_module->p_config[i].ppsz_list_text[j] = NULL;
                }
            }
            if( p_orig[i].pi_list )
            {
                p_module->p_config[i].pi_list =
                    malloc( (p_orig[i].i_list + 1) * sizeof(int) );
                if( p_module->p_config[i].pi_list )
                {
                    for( j = 0; j < p_orig[i].i_list; j++ )
                        p_module->p_config[i].pi_list[j] =
                            p_orig[i].pi_list[j];
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
632 633 634
            }
        }

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
        /* duplicate the actions list */
        if( p_orig[i].i_action )
        {
            int j;

            p_module->p_config[i].ppf_action =
                malloc( p_orig[i].i_action * sizeof(void *) );
            p_module->p_config[i].ppsz_action_text =
                malloc( p_orig[i].i_action * sizeof(char *) );

            for( j = 0; j < p_orig[i].i_action; j++ )
            {
                p_module->p_config[i].ppf_action[j] =
                    p_orig[i].ppf_action[j];
                p_module->p_config[i].ppsz_action_text[j] =
650
                    strdupnull (p_orig[i].ppsz_action_text[j]);
651 652 653
            }
        }

654
        p_module->p_config[i].pf_callback = p_orig[i].pf_callback;
Gildas Bazin's avatar
 
Gildas Bazin committed
655
    }
656
    return VLC_SUCCESS;
657 658
}

659

660 661 662 663 664 665 666
/*****************************************************************************
 * config_Free: frees a duplicated module's configuration data.
 *****************************************************************************
 * This function frees all the data duplicated by config_Duplicate.
 *****************************************************************************/
void config_Free( module_t *p_module )
{
Gildas Bazin's avatar
 
Gildas Bazin committed
667
    int i;
668

669
    for (size_t j = 0; j < p_module->confsize; j++)
670
    {
671
        module_config_t *p_item = p_module->p_config + j;
672

673 674 675 676 677
        free( (char*) p_item->psz_type );
        free( (char*) p_item->psz_name );
        free( (char*) p_item->psz_current );
        free( (char*) p_item->psz_text );
        free( (char*) p_item->psz_longtext );
678

679 680 681 682 683 684
        if (IsConfigStringType (p_item->i_type))
        {
            freenull (p_item->value.psz);
            freenull (p_item->orig.psz);
            freenull (p_item->saved.psz);
        }
685

686
        if( p_item->i_list )
Gildas Bazin's avatar
 
Gildas Bazin committed
687
        {
688 689 690
            for( i = 0; i < p_item->i_list; i++ )
            {
                if( p_item->ppsz_list && p_item->ppsz_list[i] )
691
                    free( (char*) p_item->ppsz_list[i] );
692
                if( p_item->ppsz_list_text && p_item->ppsz_list_text[i] )
693
                    free( (char*) p_item->ppsz_list_text[i] );
694 695 696 697
            }
            if( p_item->ppsz_list ) free( p_item->ppsz_list );
            if( p_item->ppsz_list_text ) free( p_item->ppsz_list_text );
            if( p_item->pi_list ) free( p_item->pi_list );
Gildas Bazin's avatar
 
Gildas Bazin committed
698
        }
699 700 701 702 703

        if( p_item->i_action )
        {
            for( i = 0; i < p_item->i_action; i++ )
            {
704
                free( (char*) p_item->ppsz_action_text[i] );
705 706 707 708
            }
            if( p_item->ppf_action ) free( p_item->ppf_action );
            if( p_item->ppsz_action_text ) free( p_item->ppsz_action_text );
        }
709 710
    }

711 712 713 714 715
    if (p_module->p_config != NULL)
    {
        free (p_module->p_config);
        p_module->p_config = NULL;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
716
}
Gildas Bazin's avatar
 
Gildas Bazin committed
717

718 719 720 721 722 723 724
/*****************************************************************************
 * 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.
 *****************************************************************************/
725 726
void config_SetCallbacks( module_config_t *p_new, module_config_t *p_orig,
                          size_t n )
727
{
728
    for (size_t i = 0; i < n; i++)
729
    {
730
        p_new->pf_callback = p_orig->pf_callback;
731 732 733 734 735 736 737 738 739 740
        p_new++;
        p_orig++;
    }
}

/*****************************************************************************
 * config_UnsetCallbacks: unsets callback functions in the duplicate p_config.
 *****************************************************************************
 * We simply undo what we did in config_SetCallbacks.
 *****************************************************************************/
741
void config_UnsetCallbacks( module_config_t *p_new, size_t n )
742
{
743
    for (size_t i = 0; i < n; i++)
744
    {
745
        p_new->pf_callback = NULL;
746 747 748 749
        p_new++;
    }
}

Gildas Bazin's avatar
 
Gildas Bazin committed
750 751 752 753 754
/*****************************************************************************
 * config_ResetAll: reset the configuration data for all the modules.
 *****************************************************************************/
void __config_ResetAll( vlc_object_t *p_this )
{
755
    int i_index;
Gildas Bazin's avatar
 
Gildas Bazin committed
756 757 758 759
    vlc_list_t *p_list;
    module_t *p_module;

    /* Acquire config file lock */
760
    vlc_mutex_lock( &p_this->p_libvlc->config_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
761 762 763 764 765 766 767 768

    p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );

    for( i_index = 0; i_index < p_list->i_count; i_index++ )
    {
        p_module = (module_t *)p_list->p_values[i_index].p_object ;
        if( p_module->b_submodule ) continue;

769
        for (size_t i = 0; i < p_module->confsize; i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
770
        {
771 772 773 774 775 776 777 778 779 780 781 782
            if (IsConfigIntegerType (p_module->p_config[i].i_type))
                p_module->p_config[i].value.i = p_module->p_config[i].orig.i;
            else
            if (IsConfigFloatType (p_module->p_config[i].i_type))
                p_module->p_config[i].value.f = p_module->p_config[i].orig.f;
            else
            if (IsConfigStringType (p_module->p_config[i].i_type))
            {
                freenull (p_module->p_config[i].value.psz);
                p_module->p_config[i].value.psz =
                        strdupnull (p_module->p_config[i].orig.psz);
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
783 784 785 786
        }
    }

    vlc_list_release( p_list );
787
    vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
788 789
}

790

791
static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode )
792
{
793 794 795 796 797
    static const char psz_subpath[] = DIR_SEP CONFIG_DIR DIR_SEP CONFIG_FILE;
    const char *psz_filename = p_obj->p_libvlc->psz_configfile;
    const char *psz_homedir;
    size_t i_buflen = 0;
    FILE *p_stream;
798

799
    if( psz_filename == NULL )
800
    {
801 802
        psz_homedir = p_obj->p_libvlc->psz_homedir;
        if( psz_homedir == NULL )
803
        {
804
            msg_Err( p_obj, "no home directory defined" );
805 806 807
            return NULL;
        }

808
        i_buflen = strlen(psz_homedir) + sizeof(psz_subpath) + 1;
809 810
    }

811 812
    char buf[i_buflen];
    if( psz_filename == NULL )
813
    {
814 815
        sprintf( buf, "%s%s", psz_homedir, psz_subpath );
        psz_filename = buf;
816 817
    }

818 819 820 821
    msg_Dbg( p_obj, "opening config file (%s)", psz_filename );
    p_stream = utf8_fopen( psz_filename, mode );
    if( p_stream == NULL && errno != ENOENT )
        msg_Err( p_obj, "cannot open config file (%s): %s", psz_filename, strerror(errno) );
822

823
    return p_stream;
824 825 826
}


Gildas Bazin's avatar
 
Gildas Bazin committed
827 828 829 830 831 832
/*****************************************************************************
 * config_LoadConfigFile: loads the configuration file.
 *****************************************************************************
 * This function is called to load the config options stored in the config
 * file.
 *****************************************************************************/
833
int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
Gildas Bazin's avatar
 
Gildas Bazin committed
834
{
835
    vlc_list_t *p_list;
Gildas Bazin's avatar
 
Gildas Bazin committed
836 837
    FILE *file;

838 839 840
    file = config_OpenConfigFile (p_this, "rt");
    if (file == NULL)
        return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
841

842
    /* Acquire config file lock */
843
    vlc_mutex_lock( &p_this->p_libvlc->config_lock );
844

Gildas Bazin's avatar
 
Gildas Bazin committed
845
    /* Look for the selected module, if NULL then save everything */
846
    p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
847

848 849 850
    /* Look for UTF-8 Byte Order Mark */
    char * (*convert) (const char *) = strdupnull;
    char bom[3];
851

852 853 854 855
    if ((fread (bom, 1, 3, file) != 3)
     || memcmp (bom, "\xEF\xBB\xBF", 3))
    {
        convert = FromLocaleDup;
856
        rewind (file); /* no BOM, rewind */
857
    }
858

859 860 861
    module_t *module = NULL;
    char line[1024], section[1022];
    section[0] = '\0';
862

863 864
    while (fgets (line, 1024, file) != NULL)
    {
865
        /* Ignore comments and empty lines */
866
        switch (line[0])
Gildas Bazin's avatar
 
Gildas Bazin committed
867
        {
868 869 870 871
            case '#':
            case '\n':
            case '\0':
                continue;
Gildas Bazin's avatar
 
Gildas Bazin committed
872 873
        }

874
        if (line[0] == '[')
Gildas Bazin's avatar
 
Gildas Bazin committed
875
        {
876 877
            char *ptr = strchr (line, ']');
            if (ptr == NULL)
878
                continue; /* syntax error; */
879
            *ptr = '\0';
Gildas Bazin's avatar
 
Gildas Bazin committed
880

881
            /* New section ( = a given module) */
882 883
            strcpy (section, line + 1);
            module = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
884

885 886
            if ((psz_module_name == NULL)
             || (strcmp (psz_module_name, section) == 0))
887
            {
888
                for (int i = 0; i < p_list->i_count; i++)
Gildas Bazin's avatar
 
Gildas Bazin committed
889
                {
890 891 892
                    module_t *m = (module_t *)p_list->p_values[i].p_object;

                    if ((strcmp (section, m->psz_object_name) == 0)
893
                     && (m->i_config_items > 0)) /* ignore config-less modules */
Gildas Bazin's avatar
 
Gildas Bazin committed
894
                    {
895 896 897 898 899
                        module = m;
                        if (psz_module_name != NULL)
                            msg_Dbg (p_this,
                                     "loading config for module \"%s\"",
                                     section);
Gildas Bazin's avatar
 
Gildas Bazin committed
900
                        break;
901 902 903
                    }
                }
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
904

905 906
            continue;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
907

908
        if (module == NULL)
909
            continue; /* no need to parse if there is no matching module */
Gildas Bazin's avatar
 
Gildas Bazin committed
910

911 912 913
        char *ptr = strchr (line, '\n');
        if (ptr != NULL)
            *ptr = '\0';
914

915 916
        /* look for option name */
        const char *psz_option_name = line;
Gildas Bazin's avatar
 
Gildas Bazin committed
917

918 919
        ptr = strchr (line, '=');
        if (ptr == NULL)
920
            continue; /* syntax error */
Gildas Bazin's avatar
 
Gildas Bazin committed
921

922 923
        *ptr = '\0';
        const char *psz_option_value = ptr + 1;
924

925 926 927 928
        /* try to match this option with one of the module's options */
        for (size_t i = 0; i < module->confsize; i++)
        {
            module_config_t *p_item = module->p_config + i;
Gildas Bazin's avatar
 
Gildas Bazin committed
929

930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968
            if ((p_item->i_type & CONFIG_HINT)
             || strcmp (p_item->psz_name, psz_option_name))
                continue;

            /* We found it */
            switch( p_item->i_type )
            {
                case CONFIG_ITEM_BOOL:
                case CONFIG_ITEM_INTEGER:
                    if( !*psz_option_value )
                        break;                    /* ignore empty option */
                    p_item->value.i = strtol( psz_option_value, 0, 0 );
                    p_item->saved.i = p_item->value.i;

                    /*msg_Dbg (p_this, "option \"%s\", value %i",
                             psz_option_name, p_item->value.i);*/
                    break;

                case CONFIG_ITEM_FLOAT:
                    if( !*psz_option_value )
                        break;                    /* ignore empty option */
                    p_item->value.f = (float)i18n_atof( psz_option_value);
                    p_item->saved.f = p_item->value.f;

                    /*msg_Dbg (p_this, "option \"%s\", value %f",
                             psz_option_name, (double)p_item->value.f);*/
                    break;

                case CONFIG_ITEM_KEY:
                    if( !*psz_option_value )
                        break;                    /* ignore empty option */
                    p_item->value.i = ConfigStringToKey(psz_option_value);
                    p_item->saved.i = p_item->value.i;
                    break;

                default:
                    vlc_mutex_lock( p_item->p_lock );

                    /* free old string */
969 970
                    free( (char*) p_item->value.psz );
                    free( (char*) p_item->saved.psz );
971 972 973 974 975 976 977 978 979

                    p_item->value.psz = convert (psz_option_value);
                    p_item->saved.psz = strdupnull (p_item->value.psz);

                    vlc_mutex_unlock( p_item->p_lock );

                    /*msg_Dbg (p_this, "option \"%s\", value \"%s\"",
                             psz_option_name, psz_option_value ?: "");*/
                    break;
Gildas Bazin's avatar
 
Gildas Bazin committed
980 981
            }

982 983
            break;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
984
    }
985 986

    vlc_list_release( p_list );
987

Gildas Bazin's avatar
 
Gildas Bazin committed
988 989
    fclose( file );

990
    vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
991 992 993
    return 0;
}

994
/*****************************************************************************
995
 * config_CreateDir: Create configuration directory if it doesn't exist.
996
 *****************************************************************************/
997
int config_CreateDir( vlc_object_t *p_this, const char *psz_dirname )
998 999 1000
{
    if( !psz_dirname && !*psz_dirname ) return -1;

1001
    if( utf8_mkdir( psz_dirname ) && ( errno != EEXIST ) )
1002 1003 1004
    {
        msg_Err( p_this, "could not create %s (%s)",
                 psz_dirname, strerror(errno) );
1005
        return -1;
1006 1007 1008 1009 1010
    }

    return 0;
}

Gildas Bazin's avatar
 
Gildas Bazin committed
1011 1012 1013 1014 1015 1016 1017 1018
/*****************************************************************************
 * 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.
 *
1019
 * When we save we mustn't delete the config options of the modules that
Gildas Bazin's avatar
 
Gildas Bazin committed
1020
 * haven't been loaded. So we cannot just create a new config file with the
1021
 * config structures we've got in memory.
Gildas Bazin's avatar
 
Gildas Bazin committed
1022 1023 1024 1025 1026 1027 1028 1029
 * 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 ?
 *****************************************************************************/
1030 1031
static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
                           vlc_bool_t b_autosave )
Gildas Bazin's avatar
 
Gildas Bazin committed
1032
{
Gildas Bazin's avatar
 
Gildas Bazin committed
1033
    module_t *p_parser;
1034
    vlc_list_t *p_list;
Gildas Bazin's avatar
 
Gildas Bazin committed
1035 1036
    FILE *file;
    char p_line[1024], *p_index2;
Sam Hocevar's avatar
 
Sam Hocevar committed
1037
    int i_sizebuf = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
1038
    char *p_bigbuffer, *p_index;
1039
    vlc_bool_t b_backup;
Gildas Bazin's avatar
 
Gildas Bazin committed
1040
    int i_index;
Gildas Bazin's avatar
 
Gildas Bazin committed
1041 1042

    /* Acquire config file lock */
1043
    vlc_mutex_lock( &p_this->p_libvlc->config_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
1044

1045
    if (p_this->p_libvlc->psz_configfile == NULL)
Gildas Bazin's avatar
 
Gildas Bazin committed
1046
    {
1047
        const char *psz_homedir = p_this->p_libvlc->psz_homedir;
Gildas Bazin's avatar
 
Gildas Bazin committed
1048 1049
        if( !psz_homedir )
        {
1050
            msg_Err( p_this, "no home directory defined" );
1051
            vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
1052 1053 1054
            return -1;
        }

1055 1056 1057
        char dirname[strlen (psz_homedir) + sizeof (DIR_SEP CONFIG_DIR)];
        sprintf (dirname, "%s" DIR_SEP CONFIG_DIR, psz_homedir);
        config_CreateDir (p_this, dirname);
Gildas Bazin's avatar
 
Gildas Bazin committed
1058
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
1059

1060 1061
    file = config_OpenConfigFile (p_this, "rt");
    if (file != NULL)
Gildas Bazin's avatar
 
Gildas Bazin committed
1062 1063
    {
        /* look for file size */
1064
        fseek( file, 0L, SEEK_END );
Gildas Bazin's avatar
 
Gildas Bazin committed
1065
        i_sizebuf = ftell( file );
1066
        fseek( file, 0L, SEEK_SET );
Gildas Bazin's avatar
 
Gildas Bazin committed
1067 1068 1069 1070 1071
    }

    p_bigbuffer = p_index = malloc( i_sizebuf+1 );
    if( !p_bigbuffer )
    {
1072
        msg_Err( p_this, "out of memory" );
Gildas Bazin's avatar
 
Gildas Bazin committed
1073
        if( file ) fclose( file );
1074
        vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
1075 1076 1077 1078
        return -1;
    }
    p_bigbuffer[0] = 0;

1079
    /* List all available modules */
1080
    p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
1081

Gildas Bazin's avatar
 
Gildas Bazin committed
1082 1083 1084 1085 1086 1087 1088
    /* 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,']')))
        {
1089

Gildas Bazin's avatar
 
Gildas Bazin committed
1090
            /* we found a section, check if we need to do a backup */
1091
            for( i_index = 0; i_index < p_list->i_count; i_index++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
1092
            {
1093
                p_parser = (module_t *)p_list->p_values[i_index].p_object ;
Gildas Bazin's avatar
 
Gildas Bazin committed
1094

1095
                if( ((p_index2 - &p_line[1])
Gildas Bazin's avatar
 
Gildas Bazin committed
1096 1097 1098
                       == (int)strlen(p_parser->psz_object_name) )
                    && !memcmp( &p_line[1], p_parser->psz_object_name,
                                strlen(p_parser->psz_object_name) ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
1099 1100 1101
                {
                    if( !psz_module_name )
                        break;
1102
                    else if( !strcmp( psz_module_name,
Gildas Bazin's avatar
 
Gildas Bazin committed
1103
                                      p_parser->psz_object_name ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
1104 1105 1106 1107
                        break;
                }
            }

1108
            if( i_index == p_list->i_count )
Gildas Bazin's avatar
 
Gildas Bazin committed
1109 1110 1111 1112
            {
                /* we don't have this section in our list so we need to back
                 * it up */
                *p_index2 = 0;
1113
#if 0
1114
                msg_Dbg( p_this, "backing up config for unknown module \"%s\"",
1115
                                 &p_line[1] );
1116
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
                *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
     */

1143
    file = config_OpenConfigFile (p_this, "wt");
Gildas Bazin's avatar
 
Gildas Bazin committed
1144 1145
    if( !file )
    {
1146
        vlc_list_release( p_list );
1147
        free( p_bigbuffer );
1148
        vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
1149 1150 1151
        return -1;
    }

1152
    fprintf( file, "\xEF\xBB\xBF###\n###  " COPYRIGHT_MESSAGE "\n###\n\n"
1153
       "###\n### lines begining with a '#' character are comments\n###\n\n" );
Gildas Bazin's avatar
 
Gildas Bazin committed
1154 1155

    /* Look for the selected module, if NULL then save everything */
1156
    for( i_index = 0; i_index < p_list->i_count; i_index++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
1157
    {
1158
        module_config_t *p_item, *p_end;
1159
        p_parser = (module_t *)p_list->p_values[i_index].p_object ;
Gildas Bazin's avatar
 
Gildas Bazin committed
1160

1161
        if( psz_module_name && strcmp( psz_module_name,
Gildas Bazin's avatar
 
Gildas Bazin committed
1162
                                       p_parser->psz_object_name ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
1163 1164
            continue;

Gildas Bazin's avatar
 
Gildas Bazin committed
1165
        if( !p_parser->i_config_items )
Gildas Bazin's avatar
 
Gildas Bazin committed
1166 1167
            continue;

1168 1169 1170
        if( psz_module_name )
            msg_Dbg( p_this, "saving config for module \"%s\"",
                     p_parser->psz_object_name );
Gildas Bazin's avatar
 
Gildas Bazin committed
1171

Gildas Bazin's avatar
 
Gildas Bazin committed
1172 1173
        fprintf( file, "[%s]", p_parser->psz_object_name );
        if( p_parser->psz_longname )
1174
            fprintf( file, " # %s\n\n", p_parser->psz_longname );
Gildas Bazin's avatar
 
Gildas Bazin committed
1175 1176
        else
            fprintf( file, "\n\n" );
Sam Hocevar's avatar
 
Sam Hocevar committed
1177

1178 1179
        for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
             p_item < p_end;
Sam Hocevar's avatar
 
Sam Hocevar committed
1180
             p_item++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
1181
        {
1182
            char  *psz_key;
1183 1184 1185
            int   i_value = p_item->value.i;
            float f_value = p_item->value.f;
            const char  *psz_value = p_item->value.psz;
1186

1187 1188 1189
            if( p_item->i_type & CONFIG_HINT )
                /* ignore hints */
                continue;
1190 1191 1192
            /* Ignore deprecated options */
            if( p_item->psz_current )
                continue;
1193 1194 1195
            if( p_item->b_unsaveable )
                /*obvious*/
                continue;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1196

1197 1198
            if( b_autosave && !p_item->b_autosave )
            {
1199 1200 1201 1202
                i_value = p_item->saved.i;
                f_value = p_item->saved.f;
                psz_value = p_item->saved.psz;
                if( !psz_value ) psz_value = p_item->orig.psz;
1203
            }
1204 1205 1206 1207
            else
            {
                p_item->b_dirty = VLC_FALSE;
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
1208

Sam Hocevar's avatar
 
Sam Hocevar committed
1209
            switch( p_item->i_type )
Gildas Bazin's avatar
 
Gildas Bazin committed
1210
            {
Gildas Bazin's avatar
 
Gildas Bazin committed
1211 1212
            case CONFIG_ITEM_BOOL:
            case CONFIG_ITEM_INTEGER:
Sam Hocevar's avatar
 
Sam Hocevar committed
1213
                if( p_item->psz_text )
1214
                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
Gildas Bazin's avatar
 
Gildas Bazin committed
1215
                             (p_item->i_type == CONFIG_ITEM_BOOL) ?
1216
                             _("boolean") : _("integer") );
1217
                if( i_value == p_item->orig.i )
1218
                    fputc ('#', file);
1219 1220
                fprintf( file, "%s=%i\n", p_item->psz_name, i_value );

1221
                p_item->saved.i = i_value;
Gildas Bazin's avatar
 
Gildas Bazin committed
1222
                break;
1223

1224 1225
            case CONFIG_ITEM_KEY:
                if( p_item->psz_text )
1226
                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
1227
                             _("key") );
1228
                if( i_value == p_item->orig.i )
1229
                    fputc ('#', file);
1230
                psz_key = ConfigKeyToString( i_value );
1231 1232
                fprintf( file, "%s=%s\n", p_item->psz_name,
                         psz_key ? psz_key : "" );
1233
                freenull (psz_key);
1234

1235
                p_item->saved.i = i_value;
1236
                break;
Clément Stenac's avatar
Clément Stenac committed
1237

Gildas Bazin's avatar
 
Gildas Bazin committed
1238
            case CONFIG_ITEM_FLOAT:
Gildas Bazin's avatar
 
Gildas Bazin committed
1239
                if( p_item->psz_text )
1240
                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
1241
                             _("float") );
1242
                if( f_value == p_item->orig.f )
1243
                    fputc ('#', file);
1244 1245
                fprintf( file, "%s=%f\n", p_item->psz_name, (double)f_value );

1246
                p_item->saved.f = f_value;
Gildas Bazin's avatar
 
Gildas Bazin committed
1247 1248
                break;

Gildas Bazin's avatar
 
Gildas Bazin committed
1249
            default:
Sam Hocevar's avatar
 
Sam Hocevar committed
1250
                if( p_item->psz_text )
1251
                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
1252
                             _("string") );
1253 1254 1255
                if( (!psz_value && !p_item->orig.psz) ||
                    (psz_value && p_item->orig.psz &&
                     !strcmp( psz_value, p_item->orig.psz )) )
1256
                    fputc ('#', file);
Sam Hocevar's avatar
 
Sam Hocevar committed
1257
                fprintf( file, "%s=%s\n", p_item->psz_name,
1258
                         psz_value ?: "" );
1259

1260 1261
                if( b_autosave && !p_item->b_autosave ) break;

1262 1263 1264 1265 1266 1267 1268
                freenull (p_item->saved.psz);
                if( (psz_value && p_item->orig.psz &&
                     strcmp( psz_value, p_item->orig.psz )) ||
                    !psz_value || !p_item->orig.psz)
                    p_item->saved.psz = strdupnull (psz_value);
                else
                    p_item->saved.psz = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
1269 1270 1271
            }
        }

1272
        fputc ('\n', file);
Gildas Bazin's avatar
 
Gildas Bazin committed
1273 1274
    }

1275
    vlc_list_release( p_list );
Gildas Bazin's avatar
 
Gildas Bazin committed
1276 1277 1278 1279 1280 1281 1282 1283

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

    fclose( file );
1284
    vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
1285 1286 1287 1288

    return 0;
}

1289 1290 1291
int config_AutoSaveConfigFile( vlc_object_t *p_this )
{
    vlc_list_t *p_list;
1292
    int i_index, i_count;
1293

1294 1295
    if( !p_this ) return -1;

1296
    /* Check if there's anything to save */
1297
    vlc_mutex_lock( &p_this->p_libvlc->config_lock );
1298
    p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
1299 1300
    i_count = p_list->i_count;
    for( i_index = 0; i_index < i_count; i_index++ )
1301
    {
1302 1303
        module_t *p_parser = (module_t *)p_list->p_values[i_index].p_object ;
        module_config_t *p_item, *p_end;
1304 1305 1306

        if( !p_parser->i_config_items ) continue;

1307 1308
        for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
             p_item < p_end;
1309 1310 1311 1312
             p_item++ )
        {
            if( p_item->b_autosave && p_item->b_dirty ) break;
        }
1313
        break;
1314 1315
    }
    vlc_list_release( p_list );
1316
    vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
1317

1318
    if( i_index == i_count ) return VLC_SUCCESS;
1319 1320 1321 1322 1323 1324 1325 1326
    return SaveConfigFile( p_this, 0, VLC_TRUE );
}

int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name )
{
    return SaveConfigFile( p_this, psz_module_name, VLC_FALSE );
}

Gildas Bazin's avatar
 
Gildas Bazin committed
1327 1328 1329 1330 1331 1332 1333 1334 1335
/*****************************************************************************
 * 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.
 *****************************************************************************/
1336 1337
int __config_LoadCmdLine( vlc_object_t *p_this, int *pi_argc, char *ppsz_argv[],
                          vlc_bool_t b_ignore_errors )
Gildas Bazin's avatar
 
Gildas Bazin committed
1338
{
1339
    int i_cmd, i_index, i_opts, i_shortopts, flag, i_verbose = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
1340
    module_t *p_parser;
1341
    vlc_list_t *p_list;
Gildas Bazin's avatar
 
Gildas Bazin committed
1342
    struct option *p_longopts;
Gildas Bazin's avatar
 
Gildas Bazin committed
1343
    int i_modules_index;
Gildas Bazin's avatar
 
Gildas Bazin committed
1344 1345

    /* Short options */
Sam Hocevar's avatar
 
Sam Hocevar committed
1346 1347
    module_config_t *pp_shortopts[256];
    char *psz_shortopts;
Gildas Bazin's avatar
 
Gildas Bazin committed
1348 1349

    /* Set default configuration and copy arguments */
1350 1351
    p_this->p_libvlc->i_argc    = *pi_argc;
    p_this->p_libvlc->ppsz_argv = ppsz_argv;
Gildas Bazin's avatar
 
Gildas Bazin committed
1352

1353
#ifdef __APPLE__
1354
    /* When VLC.app is run by double clicking in Mac OS X, the 2nd arg
Gildas Bazin's avatar
 
Gildas Bazin committed
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
     * 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--;
1369
        return 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
1370 1371 1372
    }
#endif

1373
    /* List all modules */
1374
    p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
1375

Gildas Bazin's avatar
 
Gildas Bazin committed
1376
    /*
1377
     * Generate the longopts and shortopts structures used by getopt_long
Gildas Bazin's avatar
 
Gildas Bazin committed
1378
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
1379 1380

    i_opts = 0;
1381
    for( i_modules_index = 0; i_modules_index < p_list->i_count;
Gildas Bazin's avatar
 
Gildas Bazin committed
1382
         i_modules_index++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
1383
    {
1384
        p_parser = (module_t *)p_list->p_values[i_modules_index].p_object ;
Gildas Bazin's avatar
 
Gildas Bazin committed
1385

Gildas Bazin's avatar
 
Gildas Bazin committed
1386
        /* count the number of exported configuration options (to allocate
Antoine Cellerier's avatar
Antoine Cellerier committed
1387
         * longopts). We also need to allocate space for two options when
Gildas Bazin's avatar
 
Gildas Bazin committed
1388
         * dealing with boolean to allow for --foo and --no-foo */
Gildas Bazin's avatar
 
Gildas Bazin committed
1389 1390
        i_opts += p_parser->i_config_items
                     + 2 * p_parser->i_bool_items;
Gildas Bazin's avatar
 
Gildas Bazin committed
1391 1392
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
1393
    p_longopts = malloc( sizeof(struct option) * (i_opts + 1) );
Gildas Bazin's avatar
 
Gildas Bazin committed
1394 1395
    if( p_longopts == NULL )
    {
1396
        msg_Err( p_this, "out of memory" );
1397
        vlc_list_release( p_list );
1398
        return -1;
Gildas Bazin's avatar
 
Gildas Bazin committed
1399 1400
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
1401 1402 1403
    psz_shortopts = malloc( sizeof( char ) * (2 * i_opts + 1) );
    if( psz_shortopts == NULL )
    {
1404
        msg_Err( p_this, "out of memory" );
Sam Hocevar's avatar
 
Sam Hocevar committed
1405
        free( p_longopts );
1406
        vlc_list_release( p_list );
1407
        return -1;
Sam Hocevar's avatar
 
Sam Hocevar committed
1408 1409
    }

1410 1411 1412 1413 1414 1415 1416 1417
    /* 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 )
        {
1418
            msg_Err( p_this, "out of memory" );
1419 1420
            free( psz_shortopts );
            free( p_longopts );
1421
            vlc_list_release( p_list );
1422 1423
            return -1;
        }
1424
        memcpy( ppsz_argv, p_this->p_libvlc->ppsz_argv,
1425
                *pi_argc * sizeof(char *) );
1426 1427
    }

1428
    i_shortopts = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
1429 1430 1431 1432 1433
    for( i_index = 0; i_index < 256; i_index++ )
    {
        pp_shortopts[i_index] = NULL;
    }

1434
    /* Fill the p_longopts and psz_shortopts structures */
Gildas Bazin's avatar
 
Gildas Bazin committed
1435
    i_index = 0;
1436
    for( i_modules_index = 0; i_modules_index < p_list->i_count;
Gildas Bazin's avatar
 
Gildas Bazin committed
1437
         i_modules_index++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
1438
    {
1439
        module_config_t *p_item, *p_end;
1440
        p_parser = (module_t *)p_list->p_values[i_modules_index].p_object ;
Gildas Bazin's avatar
 
Gildas Bazin committed
1441 1442

        if( !p_parser->i_config_items )
1443 1444
            continue;

1445 1446
        for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
             p_item < p_end;
Sam Hocevar's avatar
 
Sam Hocevar committed
1447
             p_item++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
1448
        {
1449
            /* Ignore hints */
Gildas Bazin's avatar
 
Gildas Bazin committed
1450
            if( p_item->i_type & CONFIG_HINT )
Gildas Bazin's avatar
 
Gildas Bazin committed
1451
                continue;
1452 1453

            /* Add item to long options */
Gildas Bazin's avatar
 
Gildas Bazin committed
1454 1455
            p_longopts[i_index].name = strdup( p_item->psz_name );
            if( p_longopts[i_index].name == NULL ) continue;
Gildas Bazin's avatar
 
Gildas Bazin committed
1456
            p_longopts[i_index].has_arg =
Gildas Bazin's avatar
 
Gildas Bazin committed
1457
                (p_item->i_type == CONFIG_ITEM_BOOL)?
Gildas Bazin's avatar
 
Gildas Bazin committed
1458
                                               no_argument : required_argument;
Gildas Bazin's avatar
 
Gildas Bazin committed
1459
            p_longopts[i_index].flag = &flag;
Gildas Bazin's avatar
 
Gildas Bazin committed
1460
            p_longopts[i_index].val = 0;
1461 1462
            i_index++;

Gildas Bazin's avatar
 
Gildas Bazin committed
1463 1464
            /* When dealing with bools we also need to add the --no-foo
             * option */
Gildas Bazin's avatar
 
Gildas Bazin committed
1465
            if( p_item->i_type == CONFIG_ITEM_BOOL )
Gildas Bazin's avatar
 
Gildas Bazin committed
1466
            {
Sam Hocevar's avatar
Sam Hocevar committed
1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
                char *psz_name = malloc( strlen(p_item->psz_name) + 3 );
                if( psz_name == NULL ) continue;
                strcpy( psz_name, "no" );
                strcat( psz_name, p_item->psz_name );

                p_longopts[i_index].name = psz_name;
                p_longopts[i_index].has_arg = no_argument;
                p_longopts[i_index].flag = &flag;
                p_longopts[i_index].val = 1;
                i_index++;

                psz_name = malloc( strlen(p_item->psz_name) + 4 );
Gildas Bazin's avatar
 
Gildas Bazin committed
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
                if( psz_name == NULL ) continue;
                strcpy( psz_name, "no-" );
                strcat( psz_name, p_item->psz_name );

                p_longopts[i_index].name = psz_name;
                p_longopts[i_index].has_arg = no_argument;
                p_longopts[i_index].flag = &flag;
                p_longopts[i_index].val = 1;
                i_index++;
            }

1490
            /* If item also has a short option, add it */
Sam Hocevar's avatar
 
Sam Hocevar committed
1491 1492 1493 1494 1495
            if( p_item->i_short )
            {
                pp_shortopts[(int)p_item->i_short] = p_item;
                psz_shortopts[i_shortopts] = p_item->i_short;
                i_shortopts++;
Gildas Bazin's avatar
 
Gildas Bazin committed
1496
                if( p_item->i_type != CONFIG_ITEM_BOOL )
Sam Hocevar's avatar
 
Sam Hocevar committed
1497 1498 1499
                {
                    psz_shortopts[i_shortopts] = ':';
                    i_shortopts++;
1500 1501 1502 1503 1504 1505

                    if( p_item->i_short == 'v' )
                    {
                        psz_shortopts[i_shortopts] = ':';
                        i_shortopts++;
                    }
Sam Hocevar's avatar
 
Sam Hocevar committed
1506 1507
                }
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
1508 1509 1510
        }
    }

1511
    /* We don't need the module list anymore */
1512
    vlc_list_release( p_list );
1513

Sam Hocevar's avatar
 
Sam Hocevar committed
1514 1515 1516
    /* Close the longopts and shortopts structures */
    memset( &p_longopts[i_index], 0, sizeof(struct option) );
    psz_shortopts[i_shortopts] = '\0';
Gildas Bazin's avatar
 
Gildas Bazin committed
1517 1518 1519 1520 1521

    /*
     * Parse the command line options
     */
    opterr = 0;
1522
    optind = 0; /* set to 0 to tell GNU getopt to reinitialize */
Gildas Bazin's avatar
 
Gildas Bazin committed
1523
    while( ( i_cmd = getopt_long( *pi_argc, ppsz_argv, psz_shortopts,
1524
                                  p_longopts, &i_index ) ) != -1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
1525
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
1526
        /* A long option has been recognized */
Gildas Bazin's avatar
 
Gildas Bazin committed
1527 1528 1529
        if( i_cmd == 0 )
        {
            module_config_t *p_conf;
Gildas Bazin's avatar
 
Gildas Bazin committed
1530 1531
            char *psz_name = (char *)p_longopts[i_index].name;

Sam Hocevar's avatar
Sam Hocevar committed
1532 1533
            /* Check if we deal with a --nofoo or --no-foo long option */
            if( flag ) psz_name += psz_name[2] == '-' ? 3 : 2;
Gildas Bazin's avatar
 
Gildas Bazin committed
1534 1535

            /* Store the configuration option */
1536
            p_conf = config_FindConfig( p_this, psz_name );
1537 1538
            if( p_conf )
            {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1539
                /* Check if the option is deprecated */
1540 1541
                if( p_conf->psz_current )
                {
1542 1543
                    if( !strcmp(p_conf->psz_current,"SUPPRESSED") )
                    {
1544
                        if( !b_ignore_errors )
1545 1546 1547 1548 1549 1550 1551
                        {
                            fprintf(stderr,
                                    "Warning: option --%s is no longer used.\n",
                                    p_conf->psz_name);
                        }
                       continue;
                    }
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
                    if( !b_ignore_errors )
                    {
                        if( p_conf->b_strict )
                        {
                            fprintf( stderr,
                                     "Error: option --%s is deprecated. "
                                     "Use --%s instead.\n",
                                     p_conf->psz_name, p_conf->psz_current);
                            /*free */
                            for( i_index = 0; p_longopts[i_index].name; i_index++ )
                                free( (char *)p_longopts[i_index].name );

                            free( p_longopts );
                            free( psz_shortopts );
                            return -1;
                        }
                        fprintf(stderr,
                                "Warning: option --%s is deprecated. "
                                "You should use --%s instead.\n",
                                p_conf->psz_name, p_conf->psz_current);
                    }
Yoann Peronneau's avatar
Yoann Peronneau committed
1573
                    psz_name = (char *)p_conf->psz_current;
1574 1575
                    p_conf = config_FindConfig( p_this, psz_name );
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
1576

Antoine Cellerier's avatar
Antoine Cellerier committed
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
                switch( p_conf->i_type )
                {
                    case CONFIG_ITEM_STRING:
                    case CONFIG_ITEM_FILE:
                    case CONFIG_ITEM_DIRECTORY:
                    case CONFIG_ITEM_MODULE:
                    case CONFIG_ITEM_MODULE_LIST:
                    case CONFIG_ITEM_MODULE_LIST_CAT:
                    case CONFIG_ITEM_MODULE_CAT:
                        config_PutPsz( p_this, psz_name, optarg );
                        break;
                    case CONFIG_ITEM_INTEGER:
                        config_PutInt( p_this, psz_name, strtol(optarg, 0, 0));
                        break;
                    case CONFIG_ITEM_FLOAT:
                        config_PutFloat( p_this, psz_name, (float)atof(optarg) );
                        break;
                    case CONFIG_ITEM_KEY:
                        config_PutInt( p_this, psz_name, ConfigStringToKey( optarg ) );
                        break;
                    case CONFIG_ITEM_BOOL:
                        config_PutInt( p_this, psz_name, !flag );
                        break;
                }
                continue;
            }
        }

        /* A short option has been recognized */
        if( pp_shortopts[i_cmd] != NULL )
        {
            switch( pp_shortopts[i_cmd]->i_type )
Gildas Bazin's avatar
 
Gildas Bazin committed
1609
            {
1610 1611 1612 1613
                case CONFIG_ITEM_STRING:
                case CONFIG_ITEM_FILE:
                case CONFIG_ITEM_DIRECTORY:
                case CONFIG_ITEM_MODULE:
Antoine Cellerier's avatar
Antoine Cellerier committed
1614
                case CONFIG_ITEM_MODULE_CAT:
1615 1616
                case CONFIG_ITEM_MODULE_LIST:
                case CONFIG_ITEM_MODULE_LIST_CAT:
Antoine Cellerier's avatar
Antoine Cellerier committed
1617
                    config_PutPsz( p_this, pp_shortopts[i_cmd]->psz_name, optarg );
1618 1619
                    break;
                case CONFIG_ITEM_INTEGER:
Antoine Cellerier's avatar
Antoine Cellerier committed
1620
                    if( i_cmd == 'v' )
1621
                    {
Antoine Cellerier's avatar
Antoine Cellerier committed
1622
                        if( optarg )
1623
                        {
Antoine Cellerier's avatar
Antoine Cellerier committed
1624
                            if( *optarg == 'v' ) /* eg. -vvv */
1625 1626
                            {
                                i_verbose++;
Antoine Cellerier's avatar
Antoine Cellerier committed
1627 1628 1629 1630 1631 1632 1633 1634 1635
                                while( *optarg == 'v' )
                                {
                                    i_verbose++;
                                    optarg++;
                                }
                            }
                            else
                            {
                                i_verbose += atoi( optarg ); /* eg. -v2 */
1636 1637 1638 1639
                            }
                        }
                        else
                        {
Antoine Cellerier's avatar
Antoine Cellerier committed
1640
                            i_verbose++; /* -v */
1641
                        }
Antoine Cellerier's avatar
Antoine Cellerier committed
1642 1643
                        config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name,
                                               i_verbose );
1644 1645 1646
                    }
                    else
                    {
Antoine Cellerier's avatar
Antoine Cellerier committed
1647 1648
                        config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name,
                                               strtol(optarg, 0, 0) );
1649
                    }
Antoine Cellerier's avatar
Antoine Cellerier committed
1650 1651 1652 1653
                    break;
                case CONFIG_ITEM_BOOL:
                    config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name, 1 );
                    break;
Sam Hocevar's avatar
 
Sam Hocevar committed
1654 1655 1656 1657
            }

            continue;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
1658 1659

        /* Internal error: unknown option */
Sam Hocevar's avatar
 
Sam Hocevar committed
1660 1661
        if( !b_ignore_errors )
        {
1662 1663
            fprintf( stderr, "%s: unknown option"
                     " or missing mandatory argument ",
1664
                     p_this->p_libvlc->psz_object_name );
1665 1666 1667 1668 1669 1670 1671 1672
            if( optopt )
            {
                fprintf( stderr, "`-%c'\n", optopt );
            }
            else
            {
                fprintf( stderr, "`%s'\n", ppsz_argv[optind-1] );
            }
1673
            fprintf( stderr, "Try `%s --help' for more information.\n",
1674
                             p_this->p_libvlc->psz_object_name );
Sam Hocevar's avatar
 
Sam Hocevar committed
1675

1676 1677
            for( i_index = 0; p_longopts[i_index].name; i_index++ )
                free( (char *)p_longopts[i_index].name );
Sam Hocevar's avatar
 
Sam Hocevar committed
1678 1679
            free( p_longopts );
            free( psz_shortopts );
1680
            return -1;
Gildas Bazin's avatar
 
Gildas Bazin committed
1681 1682 1683
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
1684 1685 1686
    /* Free allocated resources */
    for( i_index = 0; p_longopts[i_index].name; i_index++ )
        free( (char *)p_longopts[i_index].name );
Gildas Bazin's avatar
 
Gildas Bazin committed
1687
    free( p_longopts );
Sam Hocevar's avatar
 
Sam Hocevar committed
1688
    free( psz_shortopts );
1689
    if( b_ignore_errors ) free( ppsz_argv );
Gildas Bazin's avatar
 
Gildas Bazin committed
1690

1691
    return 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
1692
}
Sam Hocevar's avatar
 
Sam Hocevar committed
1693

1694 1695 1696 1697 1698 1699 1700 1701
/**
 * config_GetDataDir: find directory where shared data is installed
 *
 * @return a string (always succeeds).
 */
const char *config_GetDataDir( const vlc_object_t *p_this )
{
#if defined (WIN32) || defined (UNDER_CE)
1702
    return p_this->p_libvlc_global->psz_vlcpath;
1703 1704 1705 1706 1707 1708
#elif defined(__APPLE__) || defined (SYS_BEOS)
    static char path[PATH_MAX] = "";

    if( *path == '\0' )
    {
        snprintf( path, sizeof( path ), "%s/share",
1709
                  p_this->p_libvlc_global->psz_vlcpath );
1710 1711 1712 1713
        path[sizeof( path ) - 1] = '\0';
    }
    return path;
#else
1714
    (void)p_this;
1715 1716 1717 1718
    return DATA_PATH;
#endif
}

Gildas Bazin's avatar
 
Gildas Bazin committed
1719
/*****************************************************************************
1720
 * config_GetHomeDir, config_GetUserDir: find the user's home directory.
Gildas Bazin's avatar
 
Gildas Bazin committed
1721 1722
 *****************************************************************************
 * This function will try by different ways to find the user's home path.
Gildas Bazin's avatar
 
Gildas Bazin committed
1723 1724
 * 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.
Gildas Bazin's avatar
 
Gildas Bazin committed
1725
 *****************************************************************************/
1726
static char *GetDir( vlc_bool_t b_appdata )
Gildas Bazin's avatar
 
Gildas Bazin committed
1727
{
1728
    const char *psz_localhome = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
1729

1730
#if defined(WIN32) && !defined(UNDER_CE)
Gildas Bazin's avatar
 
Gildas Bazin committed
1731
    typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
1732
                                               LPWSTR );
1733
#ifndef CSIDL_FLAG_CREATE
Gildas Bazin's avatar
 
Gildas Bazin committed
1734
#   define CSIDL_FLAG_CREATE 0x8000
1735 1736
#endif
#ifndef CSIDL_APPDATA
Gildas Bazin's avatar
 
Gildas Bazin committed
1737
#   define CSIDL_APPDATA 0x1A
1738
#endif
1739 1740 1741
#ifndef CSIDL_PROFILE
#   define CSIDL_PROFILE 0x28
#endif
1742
#ifndef SHGFP_TYPE_CURRENT
Gildas Bazin's avatar
 
Gildas Bazin committed
1743
#   define SHGFP_TYPE_CURRENT 0
1744
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
1745

Gildas Bazin's avatar
 
Gildas Bazin committed
1746
    HINSTANCE shfolder_dll;
Gildas Bazin's avatar
 
Gildas Bazin committed
1747 1748
    SHGETFOLDERPATH SHGetFolderPath ;

1749
    /* load the shfolder dll to retrieve SHGetFolderPath */
1750
    if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
Gildas Bazin's avatar
 
Gildas Bazin committed
1751
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
1752
        SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
1753
                                                  _T("SHGetFolderPathW") );
Gildas Bazin's avatar
 
Gildas Bazin committed
1754 1755
        if ( SHGetFolderPath != NULL )
        {
1756
            wchar_t whomedir[MAX_PATH];
Gildas Bazin's avatar
 
Gildas Bazin committed
1757 1758 1759

            /* get the "Application Data" folder for the current user */
            if( S_OK == SHGetFolderPath( NULL,
1760 1761
                                         (b_appdata ? CSIDL_APPDATA :
                                           CSIDL_PROFILE) | CSIDL_FLAG_CREATE,
Gildas Bazin's avatar
 
Gildas Bazin committed
1762
                                         NULL, SHGFP_TYPE_CURRENT,
1763
                                         whomedir ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
1764
            {
Gildas Bazin's avatar
 
Gildas Bazin committed
1765
                FreeLibrary( shfolder_dll );
1766
                return FromWide( whomedir );
Gildas Bazin's avatar
 
Gildas Bazin committed
1767 1768
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
1769
        FreeLibrary( shfolder_dll );
Gildas Bazin's avatar
 
Gildas Bazin committed
1770
    }
1771 1772 1773

#elif defined(UNDER_CE)

Gildas Bazin's avatar
Gildas Bazin committed
1774 1775 1776 1777
#ifndef CSIDL_APPDATA
#   define CSIDL_APPDATA 0x1A
#endif

1778
    wchar_t whomedir[MAX_PATH];
1779 1780

    /* get the "Application Data" folder for the current user */
1781 1782
    if( SHGetSpecialFolderPath( NULL, whomedir, CSIDL_APPDATA, 1 ) )
        return FromWide( whomedir );
Gildas Bazin's avatar
 
Gildas Bazin committed
1783 1784
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
1785
#if defined(HAVE_GETPWUID)
1786 1787 1788
    struct passwd *p_pw;
    (void)b_appdata;

Sam Hocevar's avatar
 
Sam Hocevar committed
1789
    if( ( p_pw = getpwuid( getuid() ) ) == NULL )
Gildas Bazin's avatar
 
Gildas Bazin committed
1790
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
1791
    {
1792 1793
        psz_localhome = getenv( "HOME" );
        if( psz_localhome == NULL )
Gildas Bazin's avatar
 
Gildas Bazin committed
1794
        {
1795 1796 1797
            psz_localhome = getenv( "TMP" );
            if( psz_localhome == NULL )
                psz_localhome = "/tmp";
Gildas Bazin's avatar
 
Gildas Bazin committed
1798 1799
        }
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
1800
#if defined(HAVE_GETPWUID)
Gildas Bazin's avatar
 
Gildas Bazin committed
1801
    else
1802
        psz_localhome = p_pw->pw_dir;
Gildas Bazin's avatar
 
Gildas Bazin committed
1803 1804
#endif

1805
    return FromLocaleDup( psz_localhome );
Gildas Bazin's avatar
 
Gildas Bazin committed
1806
}
1807

1808 1809 1810 1811 1812 1813 1814 1815 1816 1817
char *config_GetHomeDir( void )
{
    return GetDir( VLC_TRUE );
}

char *config_GetUserDir( void )
{
    return GetDir( VLC_FALSE );
}

1818

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1819
static int ConfigStringToKey( const char *psz_key )
1820 1821 1822
{
    int i_key = 0;
    unsigned int i;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1823
    const char *psz_parser = strchr( psz_key, '-' );
1824 1825
    while( psz_parser && psz_parser != psz_key )
    {
1826
        for( i = 0; i < sizeof(vlc_modifiers) / sizeof(key_descriptor_t); i++ )
1827
        {
1828 1829
            if( !strncasecmp( vlc_modifiers[i].psz_key_string, psz_key,
                              strlen( vlc_modifiers[i].psz_key_string ) ) )
1830
            {
1831
                i_key |= vlc_modifiers[i].i_key_code;
1832 1833 1834 1835 1836
            }
        }
        psz_key = psz_parser + 1;
        psz_parser = strchr( psz_key, '-' );
    }
1837
    for( i = 0; i < sizeof(vlc_keys) / sizeof( key_descriptor_t ); i++ )
1838
    {
1839
        if( !strcasecmp( vlc_keys[i].psz_key_string, psz_key ) )
1840
        {
1841
            i_key |= vlc_keys[i].i_key_code;
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851
            break;
        }
    }
    return i_key;
}

static char *ConfigKeyToString( int i_key )
{
    char *psz_key = malloc( 100 );
    char *p;
1852
    size_t index;
Gildas Bazin's avatar
 
Gildas Bazin committed
1853

1854 1855 1856 1857 1858 1859
    if ( !psz_key )
    {
        return NULL;
    }
    *psz_key = '\0';
    p = psz_key;
1860
    for( index = 0; index < (sizeof(vlc_modifiers) / sizeof(key_descriptor_t));
1861
         index++ )
1862
    {
1863
        if( i_key & vlc_modifiers[index].i_key_code )
1864
        {
1865
            p += sprintf( p, "%s-", vlc_modifiers[index].psz_key_string );
1866 1867
        }
    }
1868
    for( index = 0; index < (sizeof(vlc_keys) / sizeof( key_descriptor_t));
1869
         index++)
1870
    {
1871
        if( (int)( i_key & ~KEY_MODIFIER ) == vlc_keys[index].i_key_code )
1872
        {
1873
            p += sprintf( p, "%s", vlc_keys[index].psz_key_string );
1874 1875 1876 1877 1878
            break;
        }
    }
    return psz_key;
}