#!/usr/bin/perl -P # Copyright (c) 2012 Stevan Andjelkovic # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use constant SETTINGS => "settings.c"; use constant CONFIG => "xombrero.conf"; use constant MAIN => "xombrero.c"; # This is a script that checks if the default setting values of xombrero # (found in SETTINGS) are reflected by the CONFIG. It is meant to help # the developers; the end user need not bother with it. # The rule of the game: if a setting has a boolean value (i.e. on or # off), then the config value should be the negation of the default # value, otherwise (i.e. the value is non-boolean) the config value # should be the default value. sub follows_the_rule { my ($default_value, $config_value) = @_; # Boolean setting. if ($default_value =~ /^(0|1)$/) { if ($default_value != $config_value) { return (1); } # Non-boolean setting. } else { if ($default_value eq $config_value) { return (1); } } return (0); } # There are plenty of limitations, for example: struct settings are # ignored, some string settings are initialized in special ways (we only # account for strings initialized in main() using g_strdup.), etc. # The following are settings which will not be checked by the script, # because either they are exceptions to the rule or it is hard to check # them in a systematic way. Check them manually. my @unsupported = qw( url_regex http_proxy browser_mode default_script search_string cmd_font cmd_font_name oops_font oops_font_name tabbar_font tabbar_font_name statusbar_font statusbar_font_name runtime_settings cookie_wl js_wl keybinding mime_type alias ); # The -P flag invokes the C pre-processor. #define DEBUG (0) use strict; #if (DEBUG) use warnings; #endif my %settings = (); my %config = (); # ---------------------------------------------------------------------- # Main # Walk through SETTINGS and collect all settings and their default # values. Note that the default string values cannot be initialized in # SETTINGS. with_file(SETTINGS, \&process_settings, \%settings); # We need to go through MAIN to get the default string values. with_file(MAIN, \&process_main, \%settings); # Then walk through CONFIG and collect all settings and their config # values. with_file(CONFIG, \&process_config, \%config); # Finally check if the collected settings follow the rule. summary(); # ---------------------------------------------------------------------- # Helper subroutines # Higher-order subroutine that takes a file, a subroutine and a hash. It # opens the file and applies the subroutine to each line of the file. The # hash is used for debugging output. sub with_file { my ($file, $sub, $hash) = @_; open(my $fh, "<", $file) or die "Cannot open $file: $!"; while (<$fh>) { &$sub($_); } close($fh) or warn "Cannot close $file: $!"; if (DEBUG) { print("$file:\n" . "=" x length($file) . "\n"); while (my ($key, $value) = each(%{$hash})) { print "$key => $value\n"; } } } sub process_settings { # Save integer settings. if (/^[g]?int\s+(\w+)\s+=\s(\d+);/) { $settings{$1} = $2; } # Save float settings. if (/^[g]?float\s+(\w+)\s+=\s(\d+\.\d+);/) { $settings{$1} = $2; } # Save boolean settings. if (/^gboolean\s+(\w+)\s+=\s(\w+);/) { if ($2 eq "TRUE") { $settings{$1} = 1; } elsif ($2 eq "FALSE") { $settings{$1} = 0; } else { die "$1 got non-boolean value $2 in " . SETTINGS; } } # Save string setting. Note that the default string cannot be # initialized in SETTINGS, that is why we also process MAIN. if (/^[g]?char\s+\*(\w+)\s+=\s+NULL;/ or /^[g]?char\s+(\w+)\[\w+\];/) { $settings{$1} = "NULL"; } } my $found_main = 0; sub process_main { # Find main(), as that is where the strings are initialized. unless ($found_main) { if (/^main\(int argc, char \*argv\[\]\)$/) { $found_main = 1; } return; } # Once we found main(), get the string settings. for my $setting (keys %settings) { $setting = quotemeta $setting; if (/^\s+$setting\s+=\s+g_strdup\("(.*)"\);/) { $settings{$setting} = $1; } } } sub process_config { # Save integer and boolean settings. if (/^#\s+(\w+)\s+=\s+(\d+)$/) { $config{$1} = $2; return; } # Save float settings. if (/^#\s+(\w+)\s+=\s+(\d+\.\d+)$/) { $config{$1} = $2; return; } # Save string settings. if (/^#\s+(\w+)\s+=\s+(.*)$/) { $config{$1} = $2; } } my @breaks_the_rule = (); my @missing_in_config = (); my @missing_in_settings = (); sub summary { print_with_sep("Summary", "="); # Collect settings that are in SETTINGS, but missing in CONFIG # as well as settings that break the rule. while (my ($setting, $default_value) = each(%settings)) { my $config_value = $config{$setting}; if (!defined $config_value) { push(@missing_in_config, $setting); next; } if (!follows_the_rule($default_value, $config_value)) { push(@breaks_the_rule, $setting); } } # Collect settings that are in CONFIG, but not in SETTINGS. for my $setting (keys %config) { if (!defined $settings{$setting}) { push(@missing_in_settings, $setting); } } # Report the settings that break the rule. print_with_sep("Settings that break the rule", "-"); for my $setting (@breaks_the_rule) { print SETTINGS . ":\t$setting = $settings{$setting}\n" . CONFIG . ":\t$setting = $config{$setting}\n\n" unless $setting ~~ @unsupported; } # Report the settings that are in SETTINGS, but not in CONFIG. print_with_sep("Settings in " . SETTINGS . " that are not in " . CONFIG, "-"); map { print "$_ = $settings{$_}\n" unless $_ ~~ @unsupported } @missing_in_config; # And vice versa. print_with_sep("Settings in " . CONFIG . " that are not in " . SETTINGS, "-"); map { print "$_ = $config{$_}\n" unless $_ ~~ @unsupported } @missing_in_settings; print_with_sep("Manually check the following", "-"); map { print "$_\n" } @unsupported; } sub print_with_sep { my ($line, $sep) = @_; print "\n$line\n" . $sep x length($line) . "\n"; }