contrib: schroedinger: remove obsolete patches
[vlc/gmpfix.git] / src / config / chain.c
blob7d0b71d789c5be7ca3d0c381a2bef9fcc1809550
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>
38 #include "vlc_interface.h"
40 /*****************************************************************************
41 * Local prototypes
42 *****************************************************************************/
43 static bool IsEscapeNeeded( char c )
45 return c == '\'' || c == '"' || c == '\\';
47 static bool IsEscape( const char *psz )
49 if( !psz )
50 return false;
51 return psz[0] == '\\' && IsEscapeNeeded( psz[1] );
53 static bool IsSpace( char c )
55 return c == ' ' || c == '\t';
58 #define SKIPSPACE( p ) p += strspn( p, " \t" )
59 #define SKIPTRAILINGSPACE( p, e ) \
60 do { while( e > p && IsSpace( *(e-1) ) ) e--; } while(0)
62 /**
63 * This function will return a pointer after the end of a string element.
64 * It will search the closing element which is
65 * } for { (it will handle nested { ... })
66 * " for "
67 * ' for '
69 static const char *ChainGetEnd( const char *psz_string )
71 const char *p = psz_string;
72 char c;
74 if( !psz_string )
75 return NULL;
77 /* Look for a opening character */
78 SKIPSPACE( p );
80 for( ;; p++)
82 if( *p == '\0' || *p == ',' || *p == '}' )
83 return p;
85 if( *p == '{' || *p == '"' || *p == '\'' )
86 break;
89 /* Set c to the closing character */
90 if( *p == '{' )
91 c = '}';
92 else
93 c = *p;
94 p++;
96 /* Search the closing character, handle nested {..} */
97 for( ;; )
99 if( *p == '\0')
100 return p;
102 if( IsEscape( p ) )
103 p += 2;
104 else if( *p == c )
105 return ++p;
106 else if( *p == '{' && c == '}' )
107 p = ChainGetEnd( p );
108 else
109 p++;
114 * It will extract an option value (=... or {...}).
115 * It will remove the initial = if present but keep the {}
117 static char *ChainGetValue( const char **ppsz_string )
119 const char *p = *ppsz_string;
121 char *psz_value = NULL;
122 const char *end;
123 bool b_keep_brackets = (*p == '{');
125 if( *p == '=' )
126 p++;
128 end = ChainGetEnd( p );
129 if( end <= p )
131 psz_value = NULL;
133 else
135 /* Skip heading and trailing spaces.
136 * This ain't necessary but will avoid simple
137 * user mistakes. */
138 SKIPSPACE( p );
141 if( end <= p )
143 psz_value = NULL;
145 else
147 if( *p == '\'' || *p == '"' || ( !b_keep_brackets && *p == '{' ) )
149 p++;
151 if( *(end-1) != '\'' && *(end-1) == '"' )
152 SKIPTRAILINGSPACE( p, end );
154 if( end - 1 <= p )
155 psz_value = NULL;
156 else
157 psz_value = strndup( p, end -1 - p );
159 else
161 SKIPTRAILINGSPACE( p, end );
162 if( end <= p )
163 psz_value = NULL;
164 else
165 psz_value = strndup( p, end - p );
169 /* */
170 if( psz_value )
171 config_StringUnescape( psz_value );
173 /* */
174 *ppsz_string = end;
175 return psz_value;
178 /* Parse all name=value[,] elements */
179 const char *config_ChainParseOptions( config_chain_t **pp_cfg, const char *psz_opts )
181 config_chain_t **pp_next = pp_cfg;
182 bool first = true;
185 if (!first)
186 psz_opts++; /* skip previous delimiter */
187 SKIPSPACE( psz_opts );
189 first = false;
191 /* Look for the end of the name (,={}_space_) */
192 size_t len = strcspn( psz_opts, "=,{} \t" );
193 if( len == 0 )
194 continue; /* ignore empty parameter */
196 /* Append the new parameter */
197 config_chain_t *p_cfg = malloc( sizeof(*p_cfg) );
198 if( !p_cfg )
199 break;
200 p_cfg->psz_name = strndup( psz_opts, len );
201 psz_opts += len;
202 p_cfg->psz_value = NULL;
203 p_cfg->p_next = NULL;
205 *pp_next = p_cfg;
206 pp_next = &p_cfg->p_next;
208 /* Extract the option value */
209 SKIPSPACE( psz_opts );
210 if( strchr( "={", *psz_opts ) )
212 p_cfg->psz_value = ChainGetValue( &psz_opts );
213 SKIPSPACE( psz_opts );
216 while( !memchr( "}", *psz_opts, 2 ) );
218 if( *psz_opts ) psz_opts++; /* skip '}' */;
219 SKIPSPACE( psz_opts );
221 return psz_opts;
224 char *config_ChainCreate( char **ppsz_name, config_chain_t **pp_cfg,
225 const char *psz_chain )
227 size_t len;
229 *ppsz_name = NULL;
230 *pp_cfg = NULL;
232 if( !psz_chain )
233 return NULL;
234 SKIPSPACE( psz_chain );
236 /* Look for parameter (a {...} or :...) or end of name (space or nul) */
237 len = strcspn( psz_chain, "{: \t" );
238 *ppsz_name = strndup( psz_chain, len );
239 psz_chain += len;
241 /* Parse the parameters */
242 SKIPSPACE( psz_chain );
243 if( *psz_chain == '{' )
244 psz_chain = config_ChainParseOptions( pp_cfg, psz_chain );
246 if( *psz_chain == ':' )
247 return strdup( psz_chain + 1 );
249 return NULL;
252 void config_ChainDestroy( config_chain_t *p_cfg )
254 while( p_cfg != NULL )
256 config_chain_t *p_next;
258 p_next = p_cfg->p_next;
260 FREENULL( p_cfg->psz_name );
261 FREENULL( p_cfg->psz_value );
262 free( p_cfg );
264 p_cfg = p_next;
268 #undef config_ChainParse
269 void config_ChainParse( vlc_object_t *p_this, const char *psz_prefix,
270 const char *const *ppsz_options, config_chain_t *cfg )
272 if( psz_prefix == NULL ) psz_prefix = "";
273 size_t plen = 1 + strlen( psz_prefix );
275 /* First, var_Create all variables */
276 for( size_t i = 0; ppsz_options[i] != NULL; i++ )
278 const char *optname = ppsz_options[i];
279 if (optname[0] == '*')
280 optname++;
282 char name[plen + strlen( optname )];
283 snprintf( name, sizeof (name), "%s%s", psz_prefix, optname );
284 if( var_Create( p_this, name,
285 config_GetType( p_this, name ) | VLC_VAR_DOINHERIT ) )
286 return /* VLC_xxx */;
289 /* Now parse options and set value */
290 for(; cfg; cfg = cfg->p_next )
292 vlc_value_t val;
293 bool b_yes = true;
294 bool b_once = false;
295 module_config_t *p_conf;
296 int i_type;
297 size_t i;
299 if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
300 continue;
302 for( i = 0; ppsz_options[i] != NULL; i++ )
304 if( !strcmp( ppsz_options[i], cfg->psz_name ) )
306 break;
308 if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
309 !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
310 ( !strncmp( cfg->psz_name, "no", 2 ) &&
311 !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
313 b_yes = false;
314 break;
317 if( *ppsz_options[i] == '*' &&
318 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
320 b_once = true;
321 break;
326 if( ppsz_options[i] == NULL )
328 msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
329 continue;
332 /* create name */
333 char name[plen + strlen( ppsz_options[i] )];
334 const char *psz_name = name;
335 snprintf( name, sizeof (name), "%s%s", psz_prefix,
336 b_once ? (ppsz_options[i] + 1) : ppsz_options[i] );
338 /* Check if the option is deprecated */
339 p_conf = config_FindConfig( p_this, name );
341 /* This is basically cut and paste from src/misc/configuration.c
342 * with slight changes */
343 if( p_conf )
345 if( p_conf->b_removed )
347 msg_Err( p_this, "Option %s is not supported anymore.",
348 name );
349 /* TODO: this should return an error and end option parsing
350 * ... but doing this would change the VLC API and all the
351 * modules so i'll do it later */
352 continue;
355 /* </Check if the option is deprecated> */
357 /* get the type of the variable */
358 i_type = config_GetType( p_this, psz_name );
359 if( !i_type )
361 msg_Warn( p_this, "unknown option %s (value=%s)",
362 cfg->psz_name, cfg->psz_value );
363 continue;
366 if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
368 msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
369 continue;
371 if( i_type != VLC_VAR_STRING && b_once )
373 msg_Warn( p_this, "*option_name need to be a string option" );
374 continue;
377 switch( i_type )
379 case VLC_VAR_BOOL:
380 val.b_bool = b_yes;
381 break;
382 case VLC_VAR_INTEGER:
383 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
384 NULL, 0 );
385 break;
386 case VLC_VAR_FLOAT:
387 val.f_float = us_atof( cfg->psz_value ? cfg->psz_value : "0" );
388 break;
389 case VLC_VAR_STRING:
390 val.psz_string = cfg->psz_value;
391 break;
392 default:
393 msg_Warn( p_this, "unhandled config var type (%d)", i_type );
394 memset( &val, 0, sizeof( vlc_value_t ) );
395 break;
397 if( b_once )
399 vlc_value_t val2;
401 var_Get( p_this, psz_name, &val2 );
402 if( *val2.psz_string )
404 free( val2.psz_string );
405 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
406 continue;
408 free( val2.psz_string );
410 var_Set( p_this, psz_name, val );
411 msg_Dbg( p_this, "set config option: %s to %s", psz_name,
412 cfg->psz_value ? cfg->psz_value : "(null)" );
416 config_chain_t *config_ChainDuplicate( const config_chain_t *p_src )
418 config_chain_t *p_dst = NULL;
419 config_chain_t **pp_last = &p_dst;
421 for( ; p_src != NULL; p_src = p_src->p_next )
423 config_chain_t *p = malloc( sizeof(*p) );
424 if( !p )
425 break;
426 p->p_next = NULL;
427 p->psz_name = p_src->psz_name ? strdup( p_src->psz_name ) : NULL;
428 p->psz_value = p_src->psz_value ? strdup( p_src->psz_value ) : NULL;
430 *pp_last = p;
431 pp_last = &p->p_next;
433 return p_dst;
436 char *config_StringUnescape( char *psz_string )
438 char *psz_src = psz_string;
439 char *psz_dst = psz_string;
440 if( !psz_src )
441 return NULL;
443 while( *psz_src )
445 if( IsEscape( psz_src ) )
446 psz_src++;
447 *psz_dst++ = *psz_src++;
449 *psz_dst = '\0';
451 return psz_string;
454 char *config_StringEscape( const char *str )
456 size_t length = 0;
458 if( str == NULL )
459 return NULL;
461 for( const char *p = str; *p; p++ )
462 length += IsEscapeNeeded( *p ) ? 2 : 1;
464 char *ret = xmalloc( length + 1 ), *dst = ret;
465 for( const char *p = str; *p; p++ )
467 if( IsEscapeNeeded( *p ) )
468 *dst++ = '\\';
469 *dst++ = *p;
471 *dst = '\0';;
472 return ret;