]> git.sesse.net Git - x264/blobdiff - filters/filters.c
cli: Refactor filter option parsing
[x264] / filters / filters.c
index aecd296bd53c4519917b3d1b052425708a8798b4..204dda5396533509b69da23bdd99138f0b221e67 100644 (file)
@@ -5,6 +5,7 @@
  *
  * 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 )
@@ -192,7 +129,7 @@ double x264_otof( char *str, double def )
    return ret;
 }
 
-int x264_otoi( char *str, int def )
+int x264_otoi( const char *str, int def )
 {
     int ret = def;
     if( str )