From 201acad409d89fcec2a8ad62a97cba0a86cbdbc7 Mon Sep 17 00:00:00 2001 From: Jan Vidar Krey Date: Thu, 15 Apr 2010 19:49:23 +0200 Subject: [PATCH] Do not use C macros for configuration files. --- src/core/config.c | 125 ++-- src/core/config.pl | 129 +++- src/core/config.xml | 21 +- src/core/gen_config.c | 1413 ++++++++++++++++++++++++++++++++++------- src/core/gen_config.h | 82 --- 5 files changed, 1325 insertions(+), 445 deletions(-) diff --git a/src/core/config.c b/src/core/config.c index 63f37d6..8ab295d 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -29,101 +29,52 @@ #define INT_MIN (-0x7fffffff - 1) #endif -#define CFG_APPLY_BOOLEAN(KEY, TARGET) \ - if (strcmp(KEY, key) == 0) \ - { \ - if (strlen(data) == 1 && (data[0] == '1')) TARGET = 1; \ - else if (strlen(data) == 1 && (data[0] == '0')) TARGET = 0; \ - else if (strncasecmp(data, "true", 4) == 0) TARGET = 1; \ - else if (strncasecmp(data, "false", 5) == 0) TARGET = 0; \ - else if (strncasecmp(data, "yes", 3) == 0) TARGET = 1; \ - else if (strncasecmp(data, "no", 2) == 0) TARGET = 0; \ - else if (strncasecmp(data, "on", 2) == 0) TARGET = 1; \ - else if (strncasecmp(data, "off", 3) == 0) TARGET = 0; \ - else\ - { \ - LOG_FATAL("Configuration error on line %d: '%s' must be either '1' or '0'", line_count, key); \ - return -1; \ - } \ - return 0; \ - } - -#define CFG_APPLY_STRING(KEY, TARGET) \ - if (strcmp(KEY, key) == 0) \ - { \ - TARGET = hub_strdup(data); \ - return 0; \ - } - - -#define CFG_APPLY_INTEGER(KEY, TARGET) \ - if (strcmp(KEY, key) == 0) \ - { \ - char* endptr; \ - int val; \ - errno = 0; \ - val = strtol(data, &endptr, 10); \ - if (((errno == ERANGE && (val == INT_MAX || val == INT_MIN)) || (errno != 0 && val == 0)) || endptr == data) { \ - LOG_FATAL("Configuration error on line %d: '%s' must be a number", line_count, key); \ - return -1; \ - } \ - TARGET = val; \ - return 0; \ - } - - -#define DEFAULT_STRING(KEY, VALUE) \ -{ \ - if (config->KEY == 0) \ - config->KEY = hub_strdup(VALUE); \ +static int apply_boolean(const char* key, const char* data, int* target) +{ + if (strlen(data) == 1 && (data[0] == '1')) *target = 1; + else if (strlen(data) == 1 && (data[0] == '0')) *target = 0; + else if (strncasecmp(data, "true", 4) == 0) *target = 1; + else if (strncasecmp(data, "false", 5) == 0) *target = 0; + else if (strncasecmp(data, "yes", 3) == 0) *target = 1; + else if (strncasecmp(data, "no", 2) == 0) *target = 0; + else if (strncasecmp(data, "on", 2) == 0) *target = 1; + else if (strncasecmp(data, "off", 3) == 0) *target = 0; + else + return 0; + return 1; } -#define DEFAULT_INTEGER(KEY, VALUE) \ -{ \ - if (config->KEY == 0) \ - config->KEY = VALUE; \ +static int apply_string(const char* key, const char* data, char** target, char* regexp) +{ + (void) regexp; + // FIXME: Add regexp checks for correct data + + if (*target) + hub_free(*target); + + *target = hub_strdup(data); + return 1; } -#define DEFAULT_BOOLEAN(KEY, VALUE) \ - config->KEY = config->KEY & 0x000000ff; +static int apply_integer(const char* key, const char* data, int* target, int* min, int* max) +{ + char* endptr; + int val; + errno = 0; + val = strtol(data, &endptr, 10); -#define GET_STR(NAME) CFG_APPLY_STRING ( #NAME , config->NAME ) -#define GET_INT(NAME) CFG_APPLY_INTEGER( #NAME , config->NAME ) -#define GET_BOOL(NAME) CFG_APPLY_BOOLEAN( #NAME , config->NAME ) -#define IGNORED(NAME) \ - if (strcmp(#NAME, key) == 0) \ - { \ - LOG_WARN("Configuration option %s deprecated and ingnored.", key); \ - return 0; \ - } + if (((errno == ERANGE && (val == INT_MAX || val == INT_MIN)) || (errno != 0 && val == 0)) || endptr == data) + return 0; -#define DUMP_STR(NAME, DEFAULT) \ - if (ignore_defaults) \ - { \ - if (strcmp(config->NAME, DEFAULT) != 0) \ - fprintf(stdout, "%s = \"%s\"\n", #NAME , config->NAME); \ - } \ - else \ - fprintf(stdout, "%s = \"%s\"\n", #NAME , config->NAME); \ - -#define DUMP_INT(NAME, DEFAULT) \ - if (ignore_defaults) \ - { \ - if (config->NAME != DEFAULT) \ - fprintf(stdout, "%s = %d\n", #NAME , config->NAME); \ - } \ - else \ - fprintf(stdout, "%s = %d\n", #NAME , config->NAME); \ + if (min && val < *min) + return 0; -#define DUMP_BOOL(NAME, DEFAULT) \ - if (ignore_defaults) \ - { \ - if (config->NAME != DEFAULT) \ - fprintf(stdout, "%s = %s\n", #NAME , (config->NAME ? "yes" : "no")); \ - } \ - else \ - fprintf(stdout, "%s = %s\n", #NAME , (config->NAME ? "yes" : "no")); + if (max && val > *max) + return 0; + *target = val; + return 1; +} #include "gen_config.c" diff --git a/src/core/config.pl b/src/core/config.pl index 2f5ec16..0037ffd 100755 --- a/src/core/config.pl +++ b/src/core/config.pl @@ -20,8 +20,7 @@ open GENHEAD, ">gen_config.h" || die "Unable to write header file"; print GENHEAD "/* THIS FILE IS AUTOGENERATED - DO NOT CHANGE IT! */\n\nstruct hub_config\n{\n"; foreach my $p ($tree->root->children("option")) { - my @data = ($p->att("type"), $p->att("name"), $p->att("default"), $p->att("advanced"), $p->children_text("short"), $p->children_text("description"), $p->children_text("since"), $p->children_text("example")); - write_c_header(@data); + write_c_header(get_data($p)); } print GENHEAD "};\n\n"; @@ -38,7 +37,8 @@ foreach my $p ($tree->root->children("option")) print GENIMPL "}\n\n"; # apply function -print GENIMPL "static int apply_config(struct hub_config* config, char* key, char* data, int line_count)\n{\n"; +print GENIMPL "static int apply_config(struct hub_config* config, char* key, char* data, int line_count)\n{\n\tint max = 0;\n\tint min = 0;\n\n"; + foreach my $p ($tree->root->children("option")) { write_c_impl_apply(get_data($p)); @@ -105,29 +105,92 @@ sub write_c_impl_defaults(@) { my @output = @_; my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @output; + my $prefix = ""; + my $suffix = ""; - print GENIMPL "\t"; - print GENIMPL "DEFAULT_INTEGER" if ($type eq "int"); - print GENIMPL "DEFAULT_BOOLEAN" if ($type eq "boolean"); - + print GENIMPL "\tconfig->$name = "; if ($type =~ /(string|file|message)/) { - print GENIMPL "DEFAULT_STRING "; - $default = "\"" . $default . "\""; + $prefix = "hub_strdup(\""; + $suffix = "\")" } - print GENIMPL "(" . $name . ", " . $default . ");\n"; + print GENIMPL $prefix . $default . $suffix . ";\n"; } sub write_c_impl_apply(@) { my @output = @_; - my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @output; + my ($type, $name, $default, $advanced, $short, $desc, $since, $example, $p) = @output; - print GENIMPL "\t"; - print GENIMPL "GET_INT " if ($type eq "int"); - print GENIMPL "GET_BOOL" if ($type eq "boolean"); - print GENIMPL "GET_STR " if ($type =~ /(string|file|message)/); - print GENIMPL "(" . $name . ");\n"; + my $min; + my $max; + my $regexp; + + if (defined $p) + { + $min = $p->att("min"); + $max = $p->att("max"); + $regexp = $p->att("regexp"); + + print "'check' is defined for option $name"; + print ", min=$min" if (defined $min); + print ", max=$max" if (defined $max); + print ", regexp=\"$regexp\"" if (defined $regexp); + print "\n"; + } + + print GENIMPL "\tif (!strcmp(key, \"" . $name . "\"))\n\t{\n"; + + if ($type eq "int") + { + if (defined $min) + { + print GENIMPL "\t\tmin = $min;\n" + } + if (defined $max) + { + print GENIMPL "\t\tmax = $max;\n" + } + + print GENIMPL "\t\tif (!apply_integer(key, data, &config->$name, "; + + if (defined $min) + { + print GENIMPL "&min"; + } + else + { + print GENIMPL "0"; + } + + print GENIMPL ", "; + + if (defined $max) + { + print GENIMPL "&max"; + } + else + { + print GENIMPL "0"; + } + + print GENIMPL "))\n"; + } + elsif ($type eq "boolean") + { + print GENIMPL "\t\tif (!apply_boolean(key, data, &config->$name))\n"; + } + elsif ($type =~ /(string|file|message)/) + { + print GENIMPL "\t\tif (!apply_string(key, data, &config->$name, (char*) \"\"))\n"; + } + + print GENIMPL "\t\t{\n" . + "\t\t\tLOG_ERROR(\"Configuration parse error on line %d\", line_count);\n" . + "\t\t\treturn -1;\n" . + "\t\t}\n" . + "\t\treturn 0;\n" . + "\t}\n\n"; } sub write_c_impl_free(@) @@ -135,30 +198,44 @@ sub write_c_impl_free(@) my @output = @_; my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @output; - print GENIMPL "\thub_free(config->" . $name . ");\n" if ($type =~ /(string|file|message)/) + if ($type =~ /(string|file|message)/) + { + print GENIMPL "\thub_free(config->" . $name . ");\n\n" + } } sub write_c_impl_dump(@) { my @output = @_; my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @output; + my $out; + my $val = "config->$name"; + my $test = "config->$name != $default"; - print GENIMPL "\t"; - print GENIMPL "DUMP_INT " if ($type eq "int"); - print GENIMPL "DUMP_BOOL" if ($type eq "boolean"); - - if ($type =~ /(string|file|message)/) + if ($type eq "int") { - print GENIMPL "DUMP_STR"; - $default = "\"" . $default . "\""; + $out = "%d"; } - print GENIMPL "(" . $name . ", " . $default . ");\n" + elsif ($type eq "boolean") + { + $out = "%s"; + $val = "config->$name ? \"yes\" : \"no\""; + } + elsif ($type =~ /(string|file|message)/) + { + $out = "\\\"%s\\\""; + $test = "strcmp(config->$name, \"$default\") != 0"; + } + + print GENIMPL "\tif (!ignore_defaults || $test)\n"; + print GENIMPL "\t\tfprintf(stdout, \"$name = $out\\n\", $val);\n\n"; } sub get_data($) { my $p = shift; - my @data = ($p->att("type"), $p->att("name"), $p->att("default"), $p->att("advanced"), $p->children_text("short"), $p->children_text("description"), $p->children_text("since"), $p->children_text("example")); + my $check = $p->first_child_matches("check"); + my @data = ($p->att("type"), $p->att("name"), $p->att("default"), $p->att("advanced"), $p->children_text("short"), $p->children_text("description"), $p->children_text("since"), $p->children_text("example"), $check); return @data; } diff --git a/src/core/config.xml b/src/core/config.xml index 287b9d3..5789b49 100644 --- a/src/core/config.xml +++ b/src/core/config.xml @@ -1,5 +1,14 @@ + + + - -