X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fconfig%2Fchain.c;h=ee94af1a975dad863b94d996e82a2e8d2136e184;hb=80b17e25cc1287ca582520f6a48e68ca465bf8db;hp=6ac8d2d045490b0d697b714df3c3951067a3a490;hpb=262c049bddab97077b49e00600a33ccd242d052d;p=vlc diff --git a/src/config/chain.c b/src/config/chain.c index 6ac8d2d045..ee94af1a97 100644 --- a/src/config/chain.c +++ b/src/config/chain.c @@ -31,183 +31,211 @@ # include "config.h" #endif -#include +#include #include "libvlc.h" +#include #include "vlc_interface.h" /***************************************************************************** * Local prototypes *****************************************************************************/ +static bool IsEscapeNeeded( char c ) +{ + return c == '\'' || c == '"' || c == '\\'; +} +static bool IsEscape( const char *psz ) +{ + if( !psz ) + return false; + return psz[0] == '\\' && IsEscapeNeeded( psz[1] ); +} +static bool IsSpace( char c ) +{ + return c == ' ' || c == '\t'; +} -/* chain format: - module{option=*:option=*}[:module{option=*:...}] - */ -#define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; } +#define SKIPSPACE( p ) p += strspn( p, " \t" ) #define SKIPTRAILINGSPACE( p, e ) \ - { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; } - -/* go accross " " and { } */ -static const char *_get_chain_end( const char *str ) + do { while( e > p && IsSpace( *(e-1) ) ) e--; } while(0) + +/** + * This function will return a pointer after the end of a string element. + * It will search the closing element which is + * } for { (it will handle nested { ... }) + * " for " + * ' for ' + */ +static const char *ChainGetEnd( const char *psz_string ) { + const char *p = psz_string; char c; - const char *p = str; + if( !psz_string ) + return NULL; + + /* Look for a opening character */ SKIPSPACE( p ); - for( ;; ) + for( ;; p++) { - if( !*p || *p == ',' || *p == '}' ) return p; + if( *p == '\0' || *p == ',' || *p == '}' ) + return p; - if( *p != '{' && *p != '"' && *p != '\'' ) - { - p++; - continue; - } - - if( *p == '{' ) c = '}'; - else c = *p; - p++; + if( *p == '{' || *p == '"' || *p == '\'' ) + break; + } - for( ;; ) - { - if( !*p ) return p; + /* Set c to the closing character */ + if( *p == '{' ) + c = '}'; + else + c = *p; + p++; - if( *p == c ) return ++p; - else if( *p == '{' && c == '}' ) p = _get_chain_end( p ); - else p++; - } + /* Search the closing character, handle nested {..} */ + for( ;; ) + { + if( *p == '\0') + return p; + + if( IsEscape( p ) ) + p += 2; + else if( *p == c ) + return ++p; + else if( *p == '{' && c == '}' ) + p = ChainGetEnd( p ); + else + p++; } } -char *config_ChainCreate( char **ppsz_name, config_chain_t **pp_cfg, const char *psz_chain ) +/** + * It will extract an option value (=... or {...}). + * It will remove the initial = if present but keep the {} + */ +static char *ChainGetValue( const char **ppsz_string ) { - config_chain_t *p_cfg = NULL; - const char *p = psz_chain; + const char *p = *ppsz_string; - *ppsz_name = NULL; - *pp_cfg = NULL; - - if( !p ) return NULL; - - SKIPSPACE( p ); - - while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) p++; - - if( p == psz_chain ) return NULL; + char *psz_value = NULL; + const char *end; + bool b_keep_brackets = (*p == '{'); - *ppsz_name = strndup( psz_chain, p - psz_chain ); + if( *p == '=' ) + p++; - SKIPSPACE( p ); + end = ChainGetEnd( p ); + if( end <= p ) + { + psz_value = NULL; + } + else + { + /* Skip heading and trailing spaces. + * This ain't necessary but will avoid simple + * user mistakes. */ + SKIPSPACE( p ); + } - if( *p == '{' ) + if( end <= p ) + { + psz_value = NULL; + } + else { - const char *psz_name; + if( *p == '\'' || *p == '"' || ( !b_keep_brackets && *p == '{' ) ) + { + p++; - p++; + if( *(end-1) != '\'' && *(end-1) == '"' ) + SKIPTRAILINGSPACE( p, end ); - for( ;; ) + if( end - 1 <= p ) + psz_value = NULL; + else + psz_value = strndup( p, end -1 - p ); + } + else { - config_chain_t cfg; - - SKIPSPACE( p ); + SKIPTRAILINGSPACE( p, end ); + if( end <= p ) + psz_value = NULL; + else + psz_value = strndup( p, end - p ); + } + } - psz_name = p; + /* */ + if( psz_value ) + config_StringUnescape( psz_value ); - while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' && - *p != ' ' && *p != '\t' ) p++; + /* */ + *ppsz_string = end; + return psz_value; +} - /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */ - if( p == psz_name ) - { - fprintf( stderr, "invalid options (empty)" ); - break; - } +char *config_ChainCreate( char **ppsz_name, config_chain_t **pp_cfg, + const char *psz_chain ) +{ + config_chain_t **pp_next = pp_cfg; + size_t len; - cfg.psz_name = strndup( psz_name, p - psz_name ); + *ppsz_name = NULL; + *pp_cfg = NULL; - SKIPSPACE( p ); + if( !psz_chain ) + return NULL; + SKIPSPACE( psz_chain ); - if( *p == '=' || *p == '{' ) - { - const char *end; - vlc_bool_t b_keep_brackets = (*p == '{'); - - if( *p == '=' ) p++; - - end = _get_chain_end( p ); - if( end <= p ) - { - cfg.psz_value = NULL; - } - else - { - /* Skip heading and trailing spaces. - * This ain't necessary but will avoid simple - * user mistakes. */ - SKIPSPACE( p ); - } - - if( end <= p ) - { - cfg.psz_value = NULL; - } - else - { - if( *p == '\'' || *p == '"' || - ( !b_keep_brackets && *p == '{' ) ) - { - p++; - - if( *(end-1) != '\'' && *(end-1) == '"' ) - SKIPTRAILINGSPACE( p, end ); - - if( end - 1 <= p ) cfg.psz_value = NULL; - else cfg.psz_value = strndup( p, end -1 - p ); - } - else - { - SKIPTRAILINGSPACE( p, end ); - if( end <= p ) cfg.psz_value = NULL; - else cfg.psz_value = strndup( p, end - p ); - } - } - - p = end; - SKIPSPACE( p ); - } - else - { - cfg.psz_value = NULL; - } + /* Look for parameter (a {...} or :...) or end of name (space or nul) */ + len = strcspn( psz_chain, "{: \t" ); + *ppsz_name = strndup( psz_chain, len ); + psz_chain += len; - cfg.p_next = NULL; - if( p_cfg ) - { - p_cfg->p_next = malloc( sizeof( config_chain_t ) ); - memcpy( p_cfg->p_next, &cfg, sizeof( config_chain_t ) ); + /* Parse the parameters */ + SKIPSPACE( psz_chain ); + if( *psz_chain == '{' ) + { + /* Parse all name=value[,] elements */ + do + { + psz_chain++; /* skip previous delimiter */ + SKIPSPACE( psz_chain ); - p_cfg = p_cfg->p_next; - } - else - { - p_cfg = malloc( sizeof( config_chain_t ) ); - memcpy( p_cfg, &cfg, sizeof( config_chain_t ) ); + /* Look for the end of the name (,={}_space_) */ + len = strcspn( psz_chain, "=,{} \t" ); + if( len == 0 ) + continue; /* ignore empty parameter */ - *pp_cfg = p_cfg; - } + /* Append the new parameter */ + config_chain_t *p_cfg = malloc( sizeof(*p_cfg) ); + if( !p_cfg ) + break; + p_cfg->psz_name = strndup( psz_chain, len ); + psz_chain += len; + p_cfg->psz_value = NULL; + p_cfg->p_next = NULL; - if( *p == ',' ) p++; + *pp_next = p_cfg; + pp_next = &p_cfg->p_next; - if( *p == '}' ) + /* Extract the option value */ + SKIPSPACE( psz_chain ); + if( strchr( "={", *psz_chain ) ) { - p++; - break; + p_cfg->psz_value = ChainGetValue( &psz_chain ); + SKIPSPACE( psz_chain ); } } + while( !memchr( "}", *psz_chain, 2 ) ); + + if( *psz_chain ) psz_chain++; /* skip '}' */; + SKIPSPACE( psz_chain ); } - if( *p == ':' ) return( strdup( p + 1 ) ); + if( *psz_chain == ':' ) + return strdup( psz_chain + 1 ); return NULL; } @@ -252,8 +280,8 @@ void __config_ChainParse( vlc_object_t *p_this, const char *psz_prefix, for(; cfg; cfg = cfg->p_next ) { vlc_value_t val; - vlc_bool_t b_yes = VLC_TRUE; - vlc_bool_t b_once = VLC_FALSE; + bool b_yes = true; + bool b_once = false; module_config_t *p_conf; int i_type; size_t i; @@ -272,14 +300,14 @@ void __config_ChainParse( vlc_object_t *p_this, const char *psz_prefix, ( !strncmp( cfg->psz_name, "no", 2 ) && !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) ) { - b_yes = VLC_FALSE; + b_yes = false; break; } if( *ppsz_options[i] == '*' && !strcmp( &ppsz_options[i][1], cfg->psz_name ) ) { - b_once = VLC_TRUE; + b_once = true; break; } @@ -320,30 +348,6 @@ void __config_ChainParse( vlc_object_t *p_this, const char *psz_prefix, msg_Warn( p_this, "Option %s is obsolete. Use %s instead.", name, psz_name ); } - if( p_conf->b_safe ) - { - int policy = config_GetInt( p_this, "security-policy" ); - switch( policy ) - { - case 0: /* block */ - msg_Err( p_this, "option %s is unsafe and is blocked by security policy", psz_name ); - return; - case 1: /* allow */ - break; - case 2: /* prompt */ - { - char description[256]; - 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); - if( DIALOG_OK_YES != intf_UserYesNo( p_this, _("WARNING: Unsafe Playlist"), description, _("Yes"), _("No"), NULL) ) - { - msg_Err( p_this, "option %s is unsafe and is blocked by security policy", psz_name ); - return; - } - } - default: - ; - } - } } /* */ @@ -379,7 +383,7 @@ void __config_ChainParse( vlc_object_t *p_this, const char *psz_prefix, NULL, 0 ); break; case VLC_VAR_FLOAT: - val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" ); + val.f_float = us_atof( cfg->psz_value ? cfg->psz_value : "0" ); break; case VLC_VAR_STRING: case VLC_VAR_MODULE: @@ -408,3 +412,71 @@ void __config_ChainParse( vlc_object_t *p_this, const char *psz_prefix, cfg->psz_value ? cfg->psz_value : "(null)" ); } } + +config_chain_t *config_ChainDuplicate( const config_chain_t *p_src ) +{ + config_chain_t *p_dst = NULL; + config_chain_t **pp_last = &p_dst; + + for( ; p_src != NULL; p_src = p_src->p_next ) + { + config_chain_t *p = malloc( sizeof(*p) ); + if( !p ) + break; + p->p_next = NULL; + p->psz_name = p_src->psz_name ? strdup( p_src->psz_name ) : NULL; + p->psz_value = p_src->psz_value ? strdup( p_src->psz_value ) : NULL; + + *pp_last = p; + pp_last = &p->p_next; + } + return p_dst; +} + +char *config_StringUnescape( char *psz_string ) +{ + char *psz_src = psz_string; + char *psz_dst = psz_string; + if( !psz_src ) + return NULL; + + while( *psz_src ) + { + if( IsEscape( psz_src ) ) + psz_src++; + *psz_dst++ = *psz_src++; + } + *psz_dst = '\0'; + + return psz_string; +} + +char *config_StringEscape( const char *psz_string ) +{ + char *psz_return; + char *psz_dst; + int i_escape; + + if( !psz_string ) + return NULL; + + i_escape = 0; + for( const char *p = psz_string; *p; p++ ) + { + if( IsEscapeNeeded( *p ) ) + i_escape++; + } + + psz_return = psz_dst = malloc( strlen( psz_string ) + i_escape + 1 ); + for( const char *p = psz_string; *p; p++ ) + { + if( IsEscapeNeeded( *p ) ) + *psz_dst++ = '\\'; + *psz_dst++ = *p; + } + *psz_dst = '\0'; + + return psz_return; +} + +