*
* Authors: Diogo Franco <diogomfranco@gmail.com>
* Steven Walters <kemuri9@gmail.com>
+ * Henrik Gramner <henrik@gramner.com>
*
* 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
#include "filters.h"
#define RETURN_IF_ERROR( cond, ... ) RETURN_IF_ERR( cond, "options", NULL, __VA_ARGS__ )
-char **x264_split_string( char *string, char *sep, int limit )
+char **x264_split_options( const char *opt_str, const char * const *options )
{
- if( !string )
+ int opt_count = 0, options_count = 0, found_named = 0, size = 0;
+ const char *opt = opt_str;
+
+ if( !opt_str )
return NULL;
- int sep_count = 0;
- int sep_len = strlen( sep );
- char *tmp = string;
- while( ( tmp = ( tmp = strstr( tmp, sep ) ) ? tmp + sep_len : 0 ) )
- ++sep_count;
- if( sep_count == 0 )
- {
- if( string[0] == '\0' )
- return calloc( 1, sizeof( char* ) );
- char **ret = calloc( 2, sizeof( char* ) );
- ret[0] = strdup( string );
- return ret;
- }
- char **split = calloc( ( limit > 0 ? limit : sep_count ) + 2, sizeof(char*) );
- int i = 0;
- char *str = strdup( string );
- assert( str );
- char *esc = NULL;
- char *tok = str, *nexttok = str;
+ while( options[options_count] )
+ options_count++;
+
do
{
- nexttok = strstr( nexttok, sep );
- if( nexttok )
- *nexttok++ = '\0';
- if( ( limit > 0 && i >= limit ) ||
- ( i > 0 && ( ( esc = strrchr( split[i-1], '\\' ) ) ? esc[1] == '\0' : 0 ) ) ) // Allow escaping
+ int length = strcspn( opt, "=," );
+ if( opt[length] == '=' )
{
- int j = i-1;
- if( esc )
- esc[0] = '\0';
- split[j] = realloc( split[j], strlen( split[j] ) + sep_len + strlen( tok ) + 1 );
- assert( split[j] );
- strcat( split[j], sep );
- strcat( split[j], tok );
- esc = NULL;
+ const char * const *option = options;
+ while( *option && (strlen( *option ) != length || strncmp( opt, *option, length )) )
+ option++;
+
+ RETURN_IF_ERROR( !*option, "Invalid option '%.*s'\n", length, opt )
+ found_named = 1;
+ length += strcspn( opt + length, "," );
}
else
{
- split[i++] = strdup( tok );
- assert( split[i-1] );
+ RETURN_IF_ERROR( opt_count >= options_count, "Too many options given\n" )
+ RETURN_IF_ERROR( found_named, "Ordered option given after named\n" )
+ size += strlen( options[opt_count] ) + 1;
}
- tok = nexttok;
- } while ( tok );
- free( str );
- assert( !split[i] );
+ opt_count++;
+ opt += length;
+ } while( *opt++ );
- return split;
-}
+ int offset = 2 * (opt_count+1) * sizeof(char*);
+ size += offset + (opt - opt_str);
+ char **opts = calloc( 1, size );
+ RETURN_IF_ERROR( !opts, "malloc failed\n" )
-void x264_free_string_array( char **array )
-{
- if( !array )
- return;
- for( int i = 0; array[i] != NULL; i++ )
- free( array[i] );
- free( array );
-}
+#define insert_opt( src, length )\
+do {\
+ opts[i++] = memcpy( (char*)opts + offset, src, length );\
+ offset += length + 1;\
+ src += length + 1;\
+} while( 0 )
-char **x264_split_options( const char *opt_str, const char *options[] )
-{
- if( !opt_str )
- return NULL;
- char *opt_str_dup = strdup( opt_str );
- char **split = x264_split_string( opt_str_dup, ",", 0 );
- free( opt_str_dup );
- int split_count = 0;
- while( split[split_count] != NULL )
- ++split_count;
-
- int options_count = 0;
- while( options[options_count] != NULL )
- ++options_count;
-
- char **opts = calloc( split_count * 2 + 2, sizeof( char * ) );
- char **arg = NULL;
- int opt = 0, found_named = 0, invalid = 0;
- for( int i = 0; split[i] != NULL; i++, invalid = 0 )
+ for( int i = 0; i < 2*opt_count; )
{
- arg = x264_split_string( split[i], "=", 2 );
- if( arg == NULL )
+ int length = strcspn( opt_str, "=," );
+ if( opt_str[length] == '=' )
{
- if( found_named )
- invalid = 1;
- else RETURN_IF_ERROR( i > options_count || options[i] == NULL, "Too many options given\n" )
- else
- {
- opts[opt++] = strdup( options[i] );
- opts[opt++] = strdup( "" );
- }
- }
- else if( arg[0] == NULL || arg[1] == NULL )
- {
- if( found_named )
- invalid = 1;
- else RETURN_IF_ERROR( i > options_count || options[i] == NULL, "Too many options given\n" )
- else
- {
- opts[opt++] = strdup( options[i] );
- if( arg[0] )
- opts[opt++] = strdup( arg[0] );
- else
- opts[opt++] = strdup( "" );
- }
+ insert_opt( opt_str, length );
+ length = strcspn( opt_str, "," );
}
else
{
- found_named = 1;
- int j = 0;
- while( options[j] != NULL && strcmp( arg[0], options[j] ) )
- ++j;
- RETURN_IF_ERROR( options[j] == NULL, "Invalid option '%s'\n", arg[0] )
- else
- {
- opts[opt++] = strdup( arg[0] );
- opts[opt++] = strdup( arg[1] );
- }
+ const char *option = options[i/2];
+ int option_length = strlen( option );
+ insert_opt( option, option_length );
}
- RETURN_IF_ERROR( invalid, "Ordered option given after named\n" )
- x264_free_string_array( arg );
+ insert_opt( opt_str, length );
}
- x264_free_string_array( split );
+
+ assert( offset == size );
return opts;
}
char *x264_get_option( const char *name, char **split_options )
{
- if( !split_options )
- return NULL;
- int last_i = -1;
- for( int i = 0; split_options[i] != NULL; i += 2 )
- if( !strcmp( split_options[i], name ) )
- last_i = i;
- if( last_i >= 0 )
- return split_options[last_i+1][0] ? split_options[last_i+1] : NULL;
+ if( split_options )
+ {
+ int last_i = -1;
+ for( int i = 0; split_options[i]; i += 2 )
+ if( !strcmp( split_options[i], name ) )
+ last_i = i;
+ if( last_i >= 0 && split_options[last_i+1][0] )
+ return split_options[last_i+1];
+ }
return NULL;
}
-int x264_otob( char *str, int def )
+int x264_otob( const char *str, int def )
{
- int ret = def;
if( str )
- ret = !strcasecmp( str, "true" ) ||
- !strcmp( str, "1" ) ||
- !strcasecmp( str, "yes" );
- return ret;
+ return !strcasecmp( str, "true" ) || !strcmp( str, "1" ) || !strcasecmp( str, "yes" );
+ return def;
}
-double x264_otof( char *str, double def )
+double x264_otof( const char *str, double def )
{
double ret = def;
if( str )
return ret;
}
-int x264_otoi( char *str, int def )
+int x264_otoi( const char *str, int def )
{
int ret = def;
if( str )