| #! /usr/bin/perl -w |
| # |
| # Static Hashtable Generator |
| # |
| # (c) 2000-2002 by Harri Porten <porten@kde.org> and |
| # David Faure <faure@kde.org> |
| # Modified (c) 2004 by Nikolas Zimmermann <wildfox@kde.org> |
| |
| $file = $ARGV[0]; |
| shift; |
| my $findSize = 0; |
| my $includelookup = 0; |
| # Use -s as second argument to make it try many hash sizes |
| $findSize = 1 if (defined($ARGV[0]) && $ARGV[0] eq "-s"); |
| # Use -i as second argument to make it include "lookup.h" |
| $includelookup = 1 if (defined($ARGV[0]) && $ARGV[0] eq "-i"); |
| # Use -n as second argument to make it use the third |
| # argument as namespace parameter ie. -n KDOM |
| $useNameSpace = $ARGV[1] if (defined($ARGV[0]) && $ARGV[0] eq "-n"); |
| |
| print STDERR "Creating hashtable for $file\n"; |
| open(IN, $file) or die "No such file $file"; |
| |
| @keys = (); |
| @values = (); |
| @attrs = (); |
| @params = (); |
| |
| my $inside = 0; |
| my $name; |
| my $size; |
| my $hashsize; |
| my $banner = 0; |
| sub calcTable(); |
| sub output(); |
| sub hashValue($); |
| |
| while (<IN>) { |
| chop; |
| s/^\s*//g; |
| if (/^\#|^$/) { |
| # comment. do nothing |
| } elsif (/^\@begin/ && !$inside) { |
| if (/^\@begin\s*([:_\w]+)\s*(\d+)\s*$/) { |
| $inside = 1; |
| $name = $1; |
| $hashsize = $2; |
| } else { |
| printf STDERR "WARNING: \@begin without table name and hashsize, skipping $_\n"; |
| } |
| } elsif (/^\@end\s*$/ && $inside) { |
| |
| if($findSize) { |
| my $entriesnum=@keys; |
| print STDERR "Table: $name $entriesnum entries\n"; |
| for( $i=3 ; $i<79 ; ++$i) { $hashsize=$i ; calcTable(); } |
| } else { |
| calcTable(); |
| } |
| |
| output(); |
| @keys = (); |
| @values = (); |
| @attrs = (); |
| @params = (); |
| $inside = 0; |
| } elsif (/^([-:\@\w\[\=\]]+)\s*([\w\:-]+)\s*([\w\|]*)\s*(\w*)\s*$/ && $inside) { |
| my $key = $1; |
| my $val = $2; |
| my $att = $3; |
| my $param = $4; |
| push(@keys, $key); |
| push(@values, $val); |
| printf STDERR "WARNING: Number of arguments missing for $key/$val\n" |
| if ( $att =~ m/Function/ && length($param) == 0); |
| push(@attrs, length($att) > 0 ? $att : "0"); |
| push(@params, length($param) > 0 ? $param : "0"); |
| } elsif ($inside) { |
| die "invalid data"; |
| } |
| } |
| |
| die "missing closing \@end" if ($inside); |
| |
| sub calcTable() { |
| @table = (); |
| @links = (); |
| $size = $hashsize; |
| my $collisions = 0; |
| my $maxdepth = 0; |
| my $i = 0; |
| foreach $key (@keys) { |
| my $depth = 0; |
| my $h = hashValue($key) % $hashsize; |
| while (defined($table[$h])) { |
| if (defined($links[$h])) { |
| $h = $links[$h]; |
| $depth++; |
| } else { |
| $collisions++; |
| $links[$h] = $size; |
| $h = $size; |
| $size++; |
| } |
| } |
| #print STDERR "table[$h] = $i\n"; |
| $table[$h] = $i; |
| $i++; |
| $maxdepth = $depth if ( $depth > $maxdepth); |
| } |
| |
| # Ensure table is big enough (in case of undef entries at the end) |
| if ( $#table+1 < $size ) { |
| $#table = $size-1; |
| } |
| #print STDERR "After loop: size=$size table=".($#table+1)."\n"; |
| |
| if ($findSize) { |
| my $emptycount = 0; |
| foreach $entry (@table) { |
| $emptycount++ if (!defined($entry)); |
| } |
| print STDERR "Hashsize: $hashsize Total Size: $size Empty: $emptycount MaxDepth: $maxdepth Collisions: $collisions\n"; |
| } |
| # my $debugtable = 0; |
| # foreach $entry (@table) { |
| # print STDERR "$debugtable " . (defined $entry ? $entry : '<undefined>'); |
| # print STDERR " -> " . $links[$debugtable] if (defined($links[$debugtable])); |
| # print STDERR "\n"; |
| # $debugtable++; |
| # } |
| } |
| |
| sub hashValue($) { |
| @chars = split(/ */, $_[0]); |
| my $val = 0; |
| foreach $c (@chars) { |
| $val += ord($c); |
| } |
| return $val; |
| } |
| |
| sub output() { |
| if (!$banner) { |
| $banner = 1; |
| print "/* Automatically generated from $file using $0. DO NOT EDIT ! */\n"; |
| } |
| |
| my $nameEntries = "${name}Entries"; |
| $nameEntries =~ s/:/_/g; |
| |
| print "\n#include \"lookup.h\"\n" if ($includelookup); |
| if ($useNameSpace) { |
| print "\nnamespace ${useNameSpace}\n{\n"; |
| print "\nusing namespace KJS;"; |
| } else { |
| print "\nnamespace KJS {\n"; |
| } |
| print "\nstatic const struct HashEntry ".$nameEntries."[] = {\n"; |
| my $i = 0; |
| #print STDERR "writing out table with ".($#table+1)." entries\n"; |
| foreach $entry (@table) { |
| if (defined($entry)) { |
| my $key = $keys[$entry]; |
| print " \{ \"" . $key . "\""; |
| print ", " . $values[$entry]; |
| print ", " . $attrs[$entry]; |
| print ", " . $params[$entry]; |
| print ", "; |
| if (defined($links[$i])) { |
| print "&${nameEntries}[$links[$i]]" . " \}"; |
| } else { |
| print "0 \}" |
| } |
| } else { |
| print " \{ 0, 0, 0, 0, 0 \}"; |
| } |
| print "," unless ($i == $size - 1); |
| print "\n"; |
| $i++; |
| } |
| print "};\n\n"; |
| print "const struct HashTable $name = "; |
| print "\{ 2, $size, ".$nameEntries.", $hashsize \};\n\n"; |
| print "} // namespace\n"; |
| } |