1 /*****************************************************************************
2 * chain.c : configuration module chain parsing stuff
3 *****************************************************************************
4 * Copyright (C) 2002-2007 the VideoLAN team
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Laurent Aimar <fenrir@via.ecp.fr>
9 * Eric Petit <titer@videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
33 #include "vlc_interface.h"
35 /*****************************************************************************
37 *****************************************************************************/
40 module{option=*:option=*}[:module{option=*:...}]
42 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
43 #define SKIPTRAILINGSPACE( p, e ) \
44 { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
46 /* go accross " " and { } */
47 static const char *_get_chain_end( const char *str )
56 if( !*p || *p == ',' || *p == '}' ) return p;
58 if( *p != '{' && *p != '"' && *p != '\'' )
64 if( *p == '{' ) c = '}';
72 if( *p == c ) return ++p;
73 else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
79 char *config_ChainCreate( char **ppsz_name, config_chain_t **pp_cfg, const char *psz_chain )
81 config_chain_t *p_cfg = NULL;
82 const char *p = psz_chain;
91 while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) p++;
93 if( p == psz_chain ) return NULL;
95 *ppsz_name = strndup( psz_chain, p - psz_chain );
101 const char *psz_name;
113 while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' &&
114 *p != ' ' && *p != '\t' ) p++;
116 /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */
119 fprintf( stderr, "invalid options (empty)" );
123 cfg.psz_name = strndup( psz_name, p - psz_name );
127 if( *p == '=' || *p == '{' )
130 vlc_bool_t b_keep_brackets = (*p == '{');
134 end = _get_chain_end( p );
137 cfg.psz_value = NULL;
141 /* Skip heading and trailing spaces.
142 * This ain't necessary but will avoid simple
149 cfg.psz_value = NULL;
153 if( *p == '\'' || *p == '"' ||
154 ( !b_keep_brackets && *p == '{' ) )
158 if( *(end-1) != '\'' && *(end-1) == '"' )
159 SKIPTRAILINGSPACE( p, end );
161 if( end - 1 <= p ) cfg.psz_value = NULL;
162 else cfg.psz_value = strndup( p, end -1 - p );
166 SKIPTRAILINGSPACE( p, end );
167 if( end <= p ) cfg.psz_value = NULL;
168 else cfg.psz_value = strndup( p, end - p );
177 cfg.psz_value = NULL;
183 p_cfg->p_next = malloc( sizeof( config_chain_t ) );
184 memcpy( p_cfg->p_next, &cfg, sizeof( config_chain_t ) );
186 p_cfg = p_cfg->p_next;
190 p_cfg = malloc( sizeof( config_chain_t ) );
191 memcpy( p_cfg, &cfg, sizeof( config_chain_t ) );
206 if( *p == ':' ) return( strdup( p + 1 ) );
211 void config_ChainDestroy( config_chain_t *p_cfg )
213 while( p_cfg != NULL )
215 config_chain_t *p_next;
217 p_next = p_cfg->p_next;
219 FREENULL( p_cfg->psz_name );
220 FREENULL( p_cfg->psz_value );
227 void __config_ChainParse( vlc_object_t *p_this, const char *psz_prefix,
228 const char *const *ppsz_options, config_chain_t *cfg )
230 if( psz_prefix == NULL ) psz_prefix = "";
231 size_t plen = 1 + strlen( psz_prefix );
233 /* First, var_Create all variables */
234 for( size_t i = 0; ppsz_options[i] != NULL; i++ )
236 const char *optname = ppsz_options[i];
237 if (optname[0] == '*')
240 char name[plen + strlen( optname )];
241 snprintf( name, sizeof (name), "%s%s", psz_prefix, optname );
242 if( var_Create( p_this, name,
243 config_GetType( p_this, name ) | VLC_VAR_DOINHERIT ) )
244 return /* VLC_xxx */;
247 /* Now parse options and set value */
248 for(; cfg; cfg = cfg->p_next )
251 vlc_bool_t b_yes = VLC_TRUE;
252 vlc_bool_t b_once = VLC_FALSE;
253 module_config_t *p_conf;
257 if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
260 for( i = 0; ppsz_options[i] != NULL; i++ )
262 if( !strcmp( ppsz_options[i], cfg->psz_name ) )
266 if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
267 !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
268 ( !strncmp( cfg->psz_name, "no", 2 ) &&
269 !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
275 if( *ppsz_options[i] == '*' &&
276 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
284 if( ppsz_options[i] == NULL )
286 msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
291 char name[plen + strlen( ppsz_options[i] )];
292 const char *psz_name = name;
293 snprintf( name, sizeof (name), "%s%s", psz_prefix,
294 b_once ? (ppsz_options[i] + 1) : ppsz_options[i] );
296 /* Check if the option is deprecated */
297 p_conf = config_FindConfig( p_this, name );
299 /* This is basically cut and paste from src/misc/configuration.c
300 * with slight changes */
303 if( p_conf->b_removed )
305 msg_Err( p_this, "Option %s is not supported anymore.",
307 /* TODO: this should return an error and end option parsing
308 * ... but doing this would change the VLC API and all the
309 * modules so i'll do it later */
312 if( p_conf->psz_oldname
313 && !strcmp( p_conf->psz_oldname, name ) )
315 psz_name = p_conf->psz_name;
316 msg_Warn( p_this, "Option %s is obsolete. Use %s instead.",
319 if( p_conf->b_unsafe )
321 int policy = config_GetInt( p_this, "security-policy" );
325 msg_Err( p_this, "option %s is unsafe and is blocked by security policy", psz_name );
331 char description[256];
332 snprintf(description, sizeof(description), _("playlist item is making use of the following unsafe option '%s', which may be harmful if used in a malicious way, authorize it ?"), psz_name);
333 if( DIALOG_OK_YES != intf_UserYesNo( p_this, _("WARNING: Unsafe Playlist"), description, _("Yes"), _("No"), NULL) )
335 msg_Err( p_this, "option %s is unsafe and is blocked by security policy", psz_name );
344 /* </Check if the option is deprecated> */
346 /* get the type of the variable */
347 i_type = config_GetType( p_this, psz_name );
350 msg_Warn( p_this, "unknown option %s (value=%s)",
351 cfg->psz_name, cfg->psz_value );
355 i_type &= CONFIG_ITEM;
357 if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
359 msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
362 if( i_type != VLC_VAR_STRING && b_once )
364 msg_Warn( p_this, "*option_name need to be a string option" );
373 case VLC_VAR_INTEGER:
374 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
378 val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" );
382 val.psz_string = cfg->psz_value;
385 msg_Warn( p_this, "unhandled config var type (%d)", i_type );
386 memset( &val, 0, sizeof( vlc_value_t ) );
393 var_Get( p_this, psz_name, &val2 );
394 if( *val2.psz_string )
396 free( val2.psz_string );
397 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
400 free( val2.psz_string );
402 var_Set( p_this, psz_name, val );
403 msg_Dbg( p_this, "set config option: %s to %s", psz_name,
404 cfg->psz_value ? cfg->psz_value : "(null)" );