#!/usr/bin/perl use strict; use integer; use File::Basename; sub c_name($) { my($s) = @_; $s =~ s/[^A-Za-z0-9_]+/_/g; return $s; } die "Usage: $0 infile hfile cfile\n" unless (scalar @ARGV >= 3); my($infile, $hfile, $cfile) = @ARGV; my $err = 0; open(my $in, '<', $infile) or die "$0: $infile: $!\n"; my $ns; my %vars; my %nsprefix; my $line = 0; while (defined(my $l = <$in>)) { $line++; $l =~ s/^\s+//; $l =~ s/\s+$//; next if ($l =~ /^(\#.*)?$/); if ($l =~ /^\@(\w+)(\s+([\w\.]+))?/) { $ns = $1; if (!defined($vars{$ns})) { $vars{$ns} = {}; } $nsprefix{$ns} = $3; next; } if (!defined{$ns}) { print STDERR "$0:$infile:$line: variable without namespace\n"; $err++; next; } my($var,$type,$defval) = split(/\s+/, $l); if (!defined($type)) { print STDERR "$0:$infile:$line: variable $var lacks type\n"; $err++; next; } $vars{$ns}->{$var} = [$type, $defval]; } close($in); exit 1 if ($err); my @nslist = sort keys(%vars); my %nsfirst; my %nscount; my @varname = (undef); my @varenum = ('sysvar_null'); my %vartype = ('sysvar_null' => 'SYSVAR_NULLTYPE'); my @vardef; my $cnt = 1; foreach my $ns (@nslist) { $nsfirst{$ns} = $cnt; foreach my $var (sort keys(%{$vars{$ns}})) { my($type, $defval) = @{$vars{$ns}->{$var}}; push(@varname, $nsprefix{$ns}.$var); my $ename = c_name($ns.'.'.$var); push(@varenum, $ename); $vartype{$ename} = "SYSVAR_TYPE(_$type)"; if (defined($defval)) { # Add mangling here if needed push(@vardef, "\t[$ename] = { .v_$type = $defval },\n"); } $cnt++; } $nscount{$ns} = $cnt - $nsfirst{$ns}; } open(my $h, '>', $hfile) or die "$0:$hfile: $!\n"; my $htag = c_name(uc(basename($hfile))); print $h "#ifndef $htag\n"; print $h "#define $htag\n\n"; print $h "enum sysvar_ns_enum {\n"; print $h map { "\tsysvar_ns_$_,\n" } @nslist; print $h "\tsysvar_nscount\n};\n\n"; print $h "enum sysvar_enum {\n"; print $h map { "\t$_,\n" } @varenum; print $h "\tsysvar_count\n};\n\n"; push(@varenum, 'sysvar_count'); print $h "\n"; # Sometimes it is convenient to have this as a preprocessor symbol print $h "#define SYSVAR_COUNT $cnt\n\n"; print $h "extern_c const char * const sysvar_name[sysvar_count];\n"; print $h "extern_c const sysvar_type_t sysvar_types[sysvar_count];\n"; print $h "extern_c const sysvar_t sysvar_defval[sysvar_count];\n"; print $h "extern_c sysvar_t sysvar_val[sysvar_count];\n"; print $h "extern_c bool sysvar_isset[sysvar_count];\n\n"; print $h "static inline sysvar_type_t sysvar_type(size_t var)\n"; print $h "{\n"; print $h "\tif (!__builtin_constant_p(var)) {\n"; print $h "\t\tif(var >= (size_t)sysvar_count)\n"; print $h "\t\t\treturn SYSVAR_NULLTYPE;\n"; print $h "\t\telse\n"; print $h "\t\t\treturn sysvar_types[var];\n"; print $h "\t}\n\n"; print $h "\tswitch(var) {\n"; foreach my $v (@varenum) { next unless (defined($vartype{$v})); print $h "\t\tcase ", $v, ":\n"; print $h "\t\t\treturn ", $vartype{$v}, ";\n"; } print $h "\t\tdefault:\n"; print $h "\t\t\treturn SYSVAR_NULLTYPE;\n"; print $h "\t};\n"; print $h "}\n\n"; print $h "#endif /* $htag */\n"; close($h); open(my $c, '>', $cfile) or die "$0:$cfile: $!\n"; print $c "#include \"sysvars.h\"\n\n"; printf $c "const sysvar_ns_t sysvar_ns[%d] = {\n", scalar(@nslist)+1; foreach my $ns (@nslist) { printf $c "\t{ \"%s\", %d },\n", $ns, $nsfirst{$ns}, $nscount{$ns}; } printf $c "\t{ NULL, %d }\n", $cnt; printf $c "};\n"; print $c "const char * const sysvar_name[$cnt] = {\n"; print $c "\tNULL,\n"; foreach my $ns (@nslist) { print $c "\n\t/* ---- $ns ---- */\n"; my $v_end = $nsfirst{$ns} + $nscount{$ns}; for (my $v = $nsfirst{$ns}; $v < $v_end; $v++) { print $c "\t\"", $varname[$v], "\",\n"; } } print $c "};\n"; print $c "const sysvar_type_t sysvar_types[$cnt] = {\n"; foreach my $v (@varenum) { next unless (defined($vartype{$v})); print $c "\t[$v] = ", $vartype{$v}, ",\n"; } print $c "};\n"; print $c "const sysvar_t sysvar_defval[$cnt] = {\n"; print $c @vardef; print $c "};\n"; print $c "sysvar_t sysvar_val[$cnt];\n"; print $c "bool sysvar_isset[$cnt];\n"; close($c);