demux: avi: PTSToByte remove useless casts and change type
[vlc.git] / src / config / chain.c
blob2cfc58f640911127aed8b9a8a940900a7f15108c
1 /*****************************************************************************
2 * chain.c : configuration module chain parsing stuff
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
5 * $Id$
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 it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
27 * Preamble
28 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <vlc_common.h>
35 #include "libvlc.h"
36 #include <vlc_charset.h>
37 #include <vlc_plugin.h>
39 #include "vlc_interface.h"
40 #include "configuration.h"
42 /*****************************************************************************
43 * Local prototypes
44 *****************************************************************************/
45 static bool IsEscapeNeeded( char c )
47 return c == '\'' || c == '"' || c == '\\';
49 static bool IsEscape( const char *psz )
51 if( !psz )
52 return false;
53 return psz[0] == '\\' && IsEscapeNeeded( psz[1] );
55 static bool IsSpace( char c )
57 return c == ' ' || c == '\t';
60 #define SKIPSPACE( p ) p += strspn( p, " \t" )
61 #define SKIPTRAILINGSPACE( p, e ) \
62 do { while( e > p && IsSpace( *(e-1) ) ) e--; } while(0)
64 /**
65 * This function will return a pointer after the end of a string element.
66 * It will search the closing element which is
67 * } for { (it will handle nested { ... })
68 * " for "
69 * ' for '
71 static const char *ChainGetEnd( const char *psz_string )
73 const char *p = psz_string;
74 char c;
76 if( !psz_string )
77 return NULL;
79 /* Look for a opening character */
80 SKIPSPACE( p );
82 for( ;; p++)
84 if( *p == '\0' || *p == ',' || *p == '}' )
85 return p;
87 if( *p == '{' || *p == '"' || *p == '\'' )
88 break;
91 /* Set c to the closing character */
92 if( *p == '{' )
93 c = '}';
94 else
95 c = *p;
96 p++;
98 /* Search the closing character, handle nested {..} */
99 for( ;; )
101 if( *p == '\0')
102 return p;
104 if( IsEscape( p ) )
105 p += 2;
106 else if( *p == c )
107 return ++p;
108 else if( *p == '{' && c == '}' )
109 p = ChainGetEnd( p );
110 else
111 p++;
116 * It will extract an option value (=... or {...}).
117 * It will remove the initial = if present but keep the {}
119 static char *ChainGetValue( const char **ppsz_string )
121 const char *p = *ppsz_string;
123 char *psz_value = NULL;
124 const char *end;
125 bool b_keep_brackets = (*p == '{');
127 if( *p == '=' )
128 p++;
130 end = ChainGetEnd( p );
131 if( end <= p )
133 psz_value = NULL;
135 else
137 /* Skip heading and trailing spaces.
138 * This ain't necessary but will avoid simple
139 * user mistakes. */
140 SKIPSPACE( p );
143 if( end <= p )
145 psz_value = NULL;
147 else
149 if( *p == '\'' || *p == '"' || ( !b_keep_brackets && *p == '{' ) )
151 p++;
153 if( *(end-1) != '\'' && *(end-1) == '"' )
154 SKIPTRAILINGSPACE( p, end );
156 if( end - 1 <= p )
157 psz_value = NULL;
158 else
159 psz_value = strndup( p, end -1 - p );
161 else
163 SKIPTRAILINGSPACE( p, end );
164 if( end <= p )
165 psz_value = NULL;
166 else
167 psz_value = strndup( p, end - p );
171 /* */
172 if( psz_value )
173 config_StringUnescape( psz_value );
175 /* */
176 *ppsz_string = end;
177 return psz_value;
180 /* Parse all name=value[,] elements */
181 const char *config_ChainParseOptions( config_chain_t **pp_cfg, const char *psz_opts )
183 config_chain_t **pp_next = pp_cfg;
184 bool first = true;
187 if (!first)
188 psz_opts++; /* skip previous delimiter */
189 SKIPSPACE( psz_opts );
191 first = false;
193 /* Look for the end of the name (,={}_space_) */
194 size_t len = strcspn( psz_opts, "=,{} \t" );
195 if( len == 0 )
196 continue; /* ignore empty parameter */
198 /* Append the new parameter */
199 config_chain_t *p_cfg = malloc( sizeof(*p_cfg) );
200 if( !p_cfg )
201 break;
202 p_cfg->psz_name = strndup( psz_opts, len );
203 psz_opts += len;
204 p_cfg->psz_value = NULL;
205 p_cfg->p_next = NULL;
207 *pp_next = p_cfg;
208 pp_next = &p_cfg->p_next;
210 /* Extract the option value */
211 SKIPSPACE( psz_opts );
212 if( strchr( "={", *psz_opts ) )
214 p_cfg->psz_value = ChainGetValue( &psz_opts );
215 SKIPSPACE( psz_opts );
218 while( !memchr( "}", *psz_opts, 2 ) );
220 if( *psz_opts ) psz_opts++; /* skip '}' */;
221 SKIPSPACE( psz_opts );
223 return psz_opts;
226 char *config_ChainCreate( char **ppsz_name, config_chain_t **pp_cfg,
227 const char *psz_chain )
229 size_t len;
231 *ppsz_name = NULL;
232 *pp_cfg = NULL;
234 if( !psz_chain )
235 return NULL;
236 SKIPSPACE( psz_chain );
238 /* Look for parameter (a {...} or :...) or end of name (space or nul) */
239 len = strcspn( psz_chain, "{: \t" );
240 *ppsz_name = strndup( psz_chain, len );
241 psz_chain += len;
243 /* Parse the parameters */
244 SKIPSPACE( psz_chain );
245 if( *psz_chain == '{' )
246 psz_chain = config_ChainParseOptions( pp_cfg, psz_chain );
248 if( *psz_chain == ':' )
249 return strdup( psz_chain + 1 );
251 return NULL;
254 void config_ChainDestroy( config_chain_t *p_cfg )
256 while( p_cfg != NULL )
258 config_chain_t *p_next;
260 p_next = p_cfg->p_next;
262 FREENULL( p_cfg->psz_name );
263 FREENULL( p_cfg->psz_value );
264 free( p_cfg );
266 p_cfg = p_next;
270 #undef config_ChainParse
271 void config_ChainParse( vlc_object_t *p_this, const char *psz_prefix,
272 const char *const *ppsz_options, config_chain_t *cfg )
274 if( psz_prefix == NULL ) psz_prefix = "";
275 size_t plen = 1 + strlen( psz_prefix );
277 /* First, var_Create all variables */
278 for( size_t i = 0; ppsz_options[i] != NULL; i++ )
280 const char *optname = ppsz_options[i];
281 if (optname[0] == '*')
282 optname++;
284 char name[plen + strlen( optname )];
285 snprintf( name, sizeof (name), "%s%s", psz_prefix, optname );
286 if( var_Create( p_this, name,
287 config_GetType( name ) | VLC_VAR_DOINHERIT ) )
288 return /* VLC_xxx */;
290 module_config_t* p_conf = config_FindConfig( name );
291 if( p_conf )
293 switch( CONFIG_CLASS( p_conf->i_type ) )
295 case CONFIG_ITEM_INTEGER:
296 var_Change( p_this, name, VLC_VAR_SETMINMAX,
297 &(vlc_value_t){ .i_int = p_conf->min.i },
298 &(vlc_value_t){ .i_int = p_conf->max.i } );
299 break;
300 case CONFIG_ITEM_FLOAT:
301 var_Change( p_this, name, VLC_VAR_SETMINMAX,
302 &(vlc_value_t){ .f_float = p_conf->min.f },
303 &(vlc_value_t){ .f_float = p_conf->max.f } );
304 break;
309 /* Now parse options and set value */
310 for(; cfg; cfg = cfg->p_next )
312 vlc_value_t val;
313 bool b_yes = true;
314 bool b_once = false;
315 module_config_t *p_conf;
316 int i_type;
317 size_t i;
319 if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
320 continue;
322 for( i = 0; ppsz_options[i] != NULL; i++ )
324 if( !strcmp( ppsz_options[i], cfg->psz_name ) )
326 break;
328 if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
329 !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
330 ( !strncmp( cfg->psz_name, "no", 2 ) &&
331 !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
333 b_yes = false;
334 break;
337 if( *ppsz_options[i] == '*' &&
338 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
340 b_once = true;
341 break;
346 if( ppsz_options[i] == NULL )
348 msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
349 continue;
352 /* create name */
353 char name[plen + strlen( ppsz_options[i] )];
354 const char *psz_name = name;
355 snprintf( name, sizeof (name), "%s%s", psz_prefix,
356 b_once ? (ppsz_options[i] + 1) : ppsz_options[i] );
358 /* Check if the option is deprecated */
359 p_conf = config_FindConfig( name );
361 /* This is basically cut and paste from src/misc/configuration.c
362 * with slight changes */
363 if( p_conf )
365 if( p_conf->b_removed )
367 msg_Err( p_this, "Option %s is not supported anymore.",
368 name );
369 /* TODO: this should return an error and end option parsing
370 * ... but doing this would change the VLC API and all the
371 * modules so i'll do it later */
372 continue;
375 /* </Check if the option is deprecated> */
377 /* get the type of the variable */
378 i_type = config_GetType( psz_name );
379 if( !i_type )
381 msg_Warn( p_this, "unknown option %s (value=%s)",
382 cfg->psz_name, cfg->psz_value );
383 continue;
386 if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
388 msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
389 continue;
391 if( i_type != VLC_VAR_STRING && b_once )
393 msg_Warn( p_this, "*option_name need to be a string option" );
394 continue;
397 switch( i_type )
399 case VLC_VAR_BOOL:
400 val.b_bool = b_yes;
401 break;
402 case VLC_VAR_INTEGER:
403 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
404 NULL, 0 );
405 break;
406 case VLC_VAR_FLOAT:
407 val.f_float = us_atof( cfg->psz_value ? cfg->psz_value : "0" );
408 break;
409 case VLC_VAR_STRING:
410 val.psz_string = cfg->psz_value;
411 break;
412 default:
413 msg_Warn( p_this, "unhandled config var type (%d)", i_type );
414 memset( &val, 0, sizeof( vlc_value_t ) );
415 break;
417 if( b_once )
419 vlc_value_t val2;
421 var_Get( p_this, psz_name, &val2 );
422 if( *val2.psz_string )
424 free( val2.psz_string );
425 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
426 continue;
428 free( val2.psz_string );
430 var_Set( p_this, psz_name, val );
431 msg_Dbg( p_this, "set config option: %s to %s", psz_name,
432 cfg->psz_value ? cfg->psz_value : "(null)" );
436 config_chain_t *config_ChainDuplicate( const config_chain_t *p_src )
438 config_chain_t *p_dst = NULL;
439 config_chain_t **pp_last = &p_dst;
441 for( ; p_src != NULL; p_src = p_src->p_next )
443 config_chain_t *p = malloc( sizeof(*p) );
444 if( !p )
445 break;
446 p->p_next = NULL;
447 p->psz_name = p_src->psz_name ? strdup( p_src->psz_name ) : NULL;
448 p->psz_value = p_src->psz_value ? strdup( p_src->psz_value ) : NULL;
450 *pp_last = p;
451 pp_last = &p->p_next;
453 return p_dst;
456 char *config_StringUnescape( char *psz_string )
458 char *psz_src = psz_string;
459 char *psz_dst = psz_string;
460 if( !psz_src )
461 return NULL;
463 while( *psz_src )
465 if( IsEscape( psz_src ) )
466 psz_src++;
467 *psz_dst++ = *psz_src++;
469 *psz_dst = '\0';
471 return psz_string;
474 char *config_StringEscape( const char *str )
476 size_t length = 0;
478 if( str == NULL )
479 return NULL;
481 for( const char *p = str; *p; p++ )
482 length += IsEscapeNeeded( *p ) ? 2 : 1;
484 char *ret = malloc( length + 1 ), *dst = ret;
486 if( unlikely( !ret ) )
487 return NULL;
489 for( const char *p = str; *p; p++ )
491 if( IsEscapeNeeded( *p ) )
492 *dst++ = '\\';
493 *dst++ = *p;
495 *dst = '\0';;
496 return ret;