From 571abddd988f4240faf3ea8125f080d4ee65ee51 Mon Sep 17 00:00:00 2001 From: Jan Vidar Krey Date: Wed, 23 May 2012 23:38:19 +0200 Subject: [PATCH] Cleaned up code generator for config file parsing. --- src/core/config.pl | 401 ++++++++++++++++++++++-------------------- src/core/config.xml | 6 +- src/core/gen_config.c | 57 ++++-- src/core/gen_config.h | 22 +-- 4 files changed, 268 insertions(+), 218 deletions(-) diff --git a/src/core/config.pl b/src/core/config.pl index 0037ffd..bb92f74 100755 --- a/src/core/config.pl +++ b/src/core/config.pl @@ -1,241 +1,270 @@ #!/usr/bin/perl -w use strict; -use XML::Twig; +use XML::DOM; sub write_c_header(@); -sub write_c_impl_defaults(@); -sub write_c_impl_apply(@); -sub write_c_impl_free(@); -sub write_c_impl_dump(@); +sub write_sql_dump(@); sub get_data($); +my $dump_to_sql = 0; + # initialize parser and read the file my $input = "./config.xml"; -my $parser = XML::Twig->new(); +my $parser = new XML::DOM::Parser; my $tree = $parser->parsefile($input) || die "Unable to parse XML file."; -# Write header file -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")) +# Get data +my $nodes = $tree->getElementsByTagName("option"); +my @options = (); +for (my $i = 0; $i < $nodes->getLength; $i++) { - write_c_header(get_data($p)); + my @data = get_data($nodes->item($i)); + push @options, \@data; } -print GENHEAD "};\n\n"; -# Write c source file -open GENIMPL, ">gen_config.c" || die "Unable to write source file"; -print GENIMPL "/* THIS FILE IS AUTOGENERATED - DO NOT CHANGE IT! */\n\n"; +write_c_header(@options); +write_sql_dump(@options) if ($dump_to_sql); -# The defaults function -print GENIMPL "void config_defaults(struct hub_config* config)\n{\n"; -foreach my $p ($tree->root->children("option")) +my $config_defaults = "void config_defaults(struct hub_config* config)\n{\n"; +my $config_apply = "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"; +my $config_free = "void free_config(struct hub_config* config)\n{\n"; +my $config_dump = "void dump_config(struct hub_config* config, int ignore_defaults)\n{\n"; + +foreach my $option (@options) { - write_c_impl_defaults(get_data($p)); -} -print GENIMPL "}\n\n"; + my ($type, $name, $default, $advanced, $short, $desc, $since, $example, $check) = @$option; + my $string = ($type =~ /(string|file|message)/); + my $min = undef; + my $max = undef; + my $regexp = undef; -# apply function -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)); -} -print GENIMPL "\t/* Still here -- unknown directive */\n"; -print GENIMPL "\tLOG_ERROR(\"Unknown configuration directive: '%s'\", key);\n"; -print GENIMPL "\t\treturn -1;\n"; -print GENIMPL "}\n\n"; - -# free function (for strings) -print GENIMPL "void free_config(struct hub_config* config)\n{\n"; -foreach my $p ($tree->root->children("option")) -{ - write_c_impl_free(get_data($p)); -} -print GENIMPL "}\n\n"; - -# dump function -print GENIMPL "void dump_config(struct hub_config* config, int ignore_defaults)\n{\n"; -foreach my $p ($tree->root->children("option")) -{ - write_c_impl_dump(get_data($p)); -} -print GENIMPL "}\n\n"; - - - -sub write_c_header(@) -{ - my @output = @_; - my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @output; - - print GENHEAD "\t"; - print GENHEAD "int " if ($type eq "int"); - print GENHEAD "int " if ($type eq "boolean"); - print GENHEAD "char*" if ($type =~ /(string|file|message)/); - print GENHEAD " " . $name . ";"; - - my $comment = ""; - if ($type eq "message") + if (defined $check) { - $comment = "\"" . $default . "\""; - } - elsif (defined $short && length $short > 0) - { - $comment = $short; - $comment .= " (default: " . $default . ")" if (defined $default); + $min = $check->getAttribute("min"); + $max = $check->getAttribute("max"); + $regexp = $check->getAttribute("regexp"); + + $max = undef if ($max eq ""); + $min = undef if ($min eq ""); + $regexp = undef if ($regexp eq ""); } - if (length $comment > 0) - { - my $pad = ""; - for (my $i = length $name; $i < 32; $i++) - { - $pad .= " "; - } - $comment = $pad . "/*<<< " . $comment . " */"; - } + $config_defaults .= "\tconfig->$name = "; + $config_defaults .= "hub_strdup(\"" if ($string); + $config_defaults .= $default; + $config_defaults .= "\")" if ($string); + $config_defaults .= ";\n"; - print GENHEAD $comment . "\n"; -} - -sub write_c_impl_defaults(@) -{ - my @output = @_; - my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @output; - my $prefix = ""; - my $suffix = ""; - - print GENIMPL "\tconfig->$name = "; - if ($type =~ /(string|file|message)/) - { - $prefix = "hub_strdup(\""; - $suffix = "\")" - } - print GENIMPL $prefix . $default . $suffix . ";\n"; -} - -sub write_c_impl_apply(@) -{ - my @output = @_; - my ($type, $name, $default, $advanced, $short, $desc, $since, $example, $p) = @output; - - 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"; + $config_apply .= "\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"; + $config_apply .= "\t\tmin = $min;\n" if (defined $min); + $config_apply .= "\t\tmax = $max;\n" if (defined $max); + $config_apply .= "\t\tif (!apply_integer(key, data, &config->$name, "; + if (defined $min) { $config_apply .= "&min"; } else { $config_apply .= "0"; } + $config_apply .= ", "; + if (defined $max) { $config_apply .= "&max"; } else { $config_apply .= "0"; } + $config_apply .= "))\n"; } elsif ($type eq "boolean") { - print GENIMPL "\t\tif (!apply_boolean(key, data, &config->$name))\n"; + $config_apply .= "\t\tif (!apply_boolean(key, data, &config->$name))\n"; } - elsif ($type =~ /(string|file|message)/) + elsif ($string) { - print GENIMPL "\t\tif (!apply_string(key, data, &config->$name, (char*) \"\"))\n"; + $config_apply .="\t\tif (!apply_string(key, data, &config->$name, (char*) \"\"))\n"; } - print GENIMPL "\t\t{\n" . + $config_apply .= "\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(@) -{ - my @output = @_; - my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @output; + $config_free .= "\thub_free(config->" . $name . ");\n\n" if ($string); - 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 $out = "%s"; my $val = "config->$name"; my $test = "config->$name != $default"; - if ($type eq "int") - { - $out = "%d"; - } - elsif ($type eq "boolean") - { - $out = "%s"; - $val = "config->$name ? \"yes\" : \"no\""; - } - elsif ($type =~ /(string|file|message)/) + $out = "%d" if ($type eq "int"); + $val = "config->$name ? \"yes\" : \"no\"" if ($type eq "boolean"); + + if ($string) { $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"; + $config_dump .= "\tif (!ignore_defaults || $test)\n"; + $config_dump .= "\t\tfprintf(stdout, \"$name = $out\\n\", $val);\n\n"; } +$config_apply .= "\t/* Still here -- unknown directive */\n"; +$config_apply .= "\tLOG_ERROR(\"Unknown configuration directive: '%s'\", key);\n"; +$config_apply .= "\treturn -1;\n"; +$config_apply .= "}\n\n"; +$config_defaults .= "}\n\n"; +$config_free .= "}\n\n"; +$config_dump .= "}\n\n"; + +open GENIMPL, ">gen_config.c" || die "Unable to write source file"; +print GENIMPL "/* THIS FILE IS AUTOGENERATED - DO NOT CHANGE IT! */\n\n"; +print GENIMPL $config_defaults; +print GENIMPL $config_apply; +print GENIMPL $config_free; +print GENIMPL $config_dump; + + sub get_data($) { my $p = shift; - 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); + + my $short = ""; + my $example = ""; + my $description = ""; + my $since = ""; + + $short = $p->getElementsByTagName("short")->item(0)->getFirstChild()->getData() if ($p->getElementsByTagName("short")->getLength()); + $since = $p->getElementsByTagName("since")->item(0)->getFirstChild()->getData() if ($p->getElementsByTagName("since")->getLength()); + $example = $p->getElementsByTagName("example")->item(0)->getFirstChild()->getData() if ($p->getElementsByTagName("example")->getLength()); + $description = $p->getElementsByTagName("description")->item(0)->getFirstChild()->getData() if ($p->getElementsByTagName("description")->getLength()); + my $check = $p->getElementsByTagName("check")->item(0); + + my @data = ( + $p->getAttribute("type"), + $p->getAttribute("name"), + $p->getAttribute("default"), + $p->getAttribute("advanced"), + $short, + $description, + $since, + $example, + $check + ); return @data; } +# Write header file +sub write_c_header(@) +{ + my @data = @_; + + open GENHEAD, ">gen_config.h" || die "Unable to write header file"; + print GENHEAD "/* THIS FILE IS AUTOGENERATED - DO NOT CHANGE IT! */\n\n"; + print GENHEAD "struct hub_config\n{\n"; + + foreach my $option (@data) + { + my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @$option; + + my $string = ($type =~ /(string|file|message)/); + + print GENHEAD "\t"; + print GENHEAD "int " if ($type eq "int"); + print GENHEAD "int " if ($type eq "boolean"); + print GENHEAD "char*" if ($string); + print GENHEAD " " . $name . ";"; + + my $comment = ""; + if ($type eq "message") + { + $comment = "\"" . $default . "\""; + } + elsif (defined $short && length $short > 0) + { + $comment = $short; + if (defined $default) + { + $comment .= " (default: "; + $comment .= "\"" if ($string); + $comment .= $default; + $comment .= "\"" if ($string); + $comment .= ")"; + } + } + + if (length $comment > 0) + { + my $pad = ""; + for (my $i = length $name; $i < 32; $i++) + { + $pad .= " "; + } + $comment = $pad . "/*<<< " . $comment . " */"; + } + print GENHEAD $comment . "\n"; + } + + print GENHEAD "};\n\n"; +} + + +sub write_sql_dump(@) +{ + my @data = @_; + + # Write SQL dump code + open GENSQL, ">gen_config.sql" || die "Unable to write SQL dump"; + print GENSQL "START TRANSACTION;\n\n + DROP TABLE uhub_config IF EXISTS;\n\n + CREATE TABLE uhub_config ( + name VARCHAR(32) UNIQUE NOT NULL, + defaultValue TINYTEXT NOT NULL, + description LONGTEXT NOT NULL, + type TINYTEXT NOT NULL, + advanced BOOLEAN, + example LONGTEXT, + since TINYTEXT + );\n\n"; + + foreach my $option (@data) + { + my ($type, $name, $default, $advanced, $short, $desc, $since, $example) = @$option; + + if ($type =~ /(string|file|message)/ ) + { + $default = "\\\"$default\\\""; + } + + $desc =~ s/\"/\\\"/g; + $type =~ s/^int$/integer/; + + my $stmt = "INSERT INTO uhub_config VALUES("; + $stmt .= "\"$name\", "; + $stmt .= "\"$default\", "; + $stmt .= "\"$desc\", "; + $stmt .= "\"$type\", "; + + if (defined $example) + { + my $example_str = $example; + $example_str =~ s/\\/\\\\/g; + $example_str =~ s/\"/\\\"/g; + $stmt .= "\"$example_str\", "; + } else { + $stmt .= "NULL, "; + } + + if (defined $since) { + $stmt .= "\"$since\", "; + } else { + $stmt .= "NULL, "; + } + + if (defined $advanced) { + $stmt .= "\"$advanced\""; + } else { + $stmt .= "NULL"; + } + + $stmt .= ");\n"; + + print GENSQL $stmt; + } + print GENSQL "\n\nCOMMIT;\n\n"; +} diff --git a/src/core/config.xml b/src/core/config.xml index 40e4932..b5e949d 100644 --- a/src/core/config.xml +++ b/src/core/config.xml @@ -13,7 +13,7 @@ 0.1.0 Server port to bind to - +