#!/usr/bin/perl -P
# Copyright (c) 2012 Stevan Andjelkovic <stevan.andjelkovic@strath.ac.uk>
#
# 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";
}