| #!/usr/bin/env perl |
| ############################################################################ |
| # __________ __ ___. |
| # Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| # \/ \/ \/ \/ \/ |
| # $Id$ |
| # |
| # Copyright (C) 2019 by William Wilgus |
| # |
| # All files in this archive are subject to the GNU General Public License. |
| # See the file COPYING in the source tree root for full license agreement. |
| # |
| # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| # KIND, either express or implied. |
| # |
| ############################################################################ |
| |
| #rockbox to lua define generator, add names of constants to the array to include |
| |
| my @rockbox_defines = ( |
| '^HZ$', |
| '^LCD_(DEPTH|HEIGHT|WIDTH)$', |
| '^MODEL_NAME$', |
| '^SCREEN_MAIN$', |
| '^LCD_DEFAULT_(FG|BG)$', |
| '^LCD_REMOTE_(DEPTH|HEIGHT|WIDTH)$', |
| '^LCD_.+(BRIGHT|DARK)COLOR', |
| '^SCREEN_REMOTE$', |
| '^FONT_SYSFIXED$', |
| '^FONT_UI$', |
| '^PLAYLIST_(INSERT|PREPEND|REPLACE)', |
| '^TOUCHSCREEN_(POINT|BUTTON)$', |
| '^HOME_DIR$', |
| '^PLUGIN_DIR$', |
| '^PLUGIN(_APPS_|_GAMES_|_)DATA_DIR$', |
| '^ROCKBOX_DIR$', |
| '^VIEWERS_DATA_DIR$'); |
| |
| my @captured_defines; |
| my @names_seen; |
| my @all_defines; |
| |
| ############# precompile regex for speed ############# |
| my $def_regex = qr/#define\s+([^\s\r\n]+)\s+([^\r\n]+)/; |
| my $quot_regex = qr/.*([\"\']).*/; |
| my $num_regex = qr/.*([\+\-\*\\|&\d]).*/; |
| my $configh_regex = qr/^\s*#define\s*__CONFIG_H__\s*$/; |
| my $config_h = "?"; |
| my $exclude_regex = qr/^#define\s*_?POSIX.*/; |
| my $exclude_enum_regex = qr/^#define\s*(_SC_|_PC_|_CS_).*/; |
| print <<EOF |
| #include <stdio.h> |
| #include <stdbool.h> |
| |
| #define stringify(s) #s |
| |
| /* auto generated defines */ |
| |
| |
| EOF |
| ; |
| |
| while(my $line = <STDIN>) |
| { |
| if($config_h eq "?" && $line =~ $configh_regex) { $config_h = $line; } |
| next if($config_h eq "?"); #don't capture till we get to the config file |
| next if($line =~ $exclude_regex); |
| |
| if($line =~ $def_regex) #does it begin with #define? |
| { |
| push(@all_defines, $line); #save all defines for possible ambiguous macros |
| $name = $1; |
| next if $name =~ /^(ATTRIBUTE_|print|__).*/; #don't add reserved |
| $value = $2; |
| |
| if(grep($name =~ $_, @rockbox_defines)) |
| { |
| push(@names_seen, $name); |
| push(@captured_defines, {'name' => $name, 'value' => $value}); |
| print $line |
| } |
| else |
| { |
| $name =~ s{(\(.*\))}{}gx; #remove (...) on function type macros |
| #ifndef guard so we don't clash with the host |
| printf "#ifndef %s\n%s#endif\n\n", $name, $line; |
| } |
| } |
| elsif($line =~ /^(?!.*;)enum.*{/) #enum { |
| { |
| next if($line =~ /enum\s*__.*/); #don't add reserved |
| print $line; |
| next if($line =~ /.*};.*/); |
| do_enum($line) |
| } |
| elsif($line =~ /^(?!.*[;\(\)])enum.*/) #enum |
| { |
| next if($line =~ /enum\s*__.*/); #don't add reserved |
| #need to be careful might be a function returning enum |
| my $lastline = $line; |
| next if($line =~ /.*};.*/); |
| ($line = <STDIN>); |
| if($line =~ /.*{.*/) |
| { |
| print $lastline; |
| print $line; |
| } |
| else { next; } |
| do_enum($line) |
| } |
| |
| } |
| #warn "total defines: ".scalar @all_defines; |
| #warn "captured defines: ".scalar @captured_defines; |
| #Sort the functions |
| my @sorted_defines = sort { @$a{'name'} cmp @$b{'name'} } @captured_defines; |
| |
| printf "int main(void)\n{\n"; |
| printf "\tprintf(\"--[[Autogenerated rockbox constants]]\\n\\n\");"; |
| # Print the C array |
| foreach my $define (@sorted_defines) |
| { |
| if(@$define{'value'} =~ /^0[xX][0-9a-fA-F]+$/) #hex number |
| { |
| printf "\tprintf(\"rb[\\\"%%s\\\"] = 0x%%x\\n\", stringify(%s), %s);\n", @$define{'name'}, @$define{'name'}; |
| } |
| elsif(@$define{'value'} =~ /^[0-9]+$/) #number |
| { |
| printf "\tprintf(\"rb[\\\"%%s\\\"] = %%d\\n\", stringify(%s), %s);\n", @$define{'name'}, @$define{'name'}; |
| } |
| else #might be a string but we don't know since the macro isn't expanded far enough |
| { |
| my $max_depth = 10; |
| my $var = @$define{'value'}; |
| while($max_depth > 0) #follow the chain of #defines until we can see what type |
| { |
| $max_depth--; |
| $var = "\\\s*#define\\s+$var\\s+.*"; |
| #warn $var; |
| if(my ($x) = grep($_ =~ /($var)/, @all_defines)) #check all the defines |
| { |
| #warn $x; |
| if($x =~ $def_regex) |
| { |
| $var = $2; |
| #warn $var; |
| last if ($var =~ $quot_regex); |
| last if ($var =~ $num_regex); |
| next |
| } |
| #warn "end ".$var; |
| last |
| } |
| else |
| { |
| $var = @$define{'value'}; |
| last |
| } |
| } |
| if ($var =~$quot_regex) #has a quote it is a string |
| { |
| #guard with empty literals "" so gcc throws an error if it isn't a string |
| printf "\tprintf(\"rb[\\\"%%s\\\"] = \\\"%%s\\\"\\n\", stringify(%s), \"\" %s \"\");\n", @$define{'name'}, @$define{'name'}; |
| } |
| elsif ($var =~$num_regex) #it must be a number |
| { |
| printf "\tprintf(\"rb[\\\"%%s\\\"] = %%d\\n\", stringify(%s), %s);\n", @$define{'name'}, @$define{'name'}; |
| } |
| else { warn "Skipping ".@$define{'name'}." indeterminate macro type\n"; } |
| } |
| } |
| |
| print <<EOF |
| return 0; |
| } |
| |
| EOF |
| ; |
| |
| sub do_enum { |
| my ($line) = @_; |
| |
| while($line = <STDIN>) |
| { |
| next if($line =~ $exclude_enum_regex); |
| if($line =~ /.*};.*/) |
| { |
| print $line; |
| last |
| } |
| elsif($line =~ /([^\s,\t]+)\s*=?.*,?/) |
| { |
| $name = $1; |
| #printf "%s WHATTT?", $name; |
| $value = "0"; #enums are always integers |
| } |
| print $line; |
| if(grep($name =~ $_, @rockbox_defines)) |
| { |
| push(@names_seen, $name); |
| push(@captured_defines, {'name' => $name, 'value' => $value}); |
| } |
| |
| } |
| } |