X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=android%2Fgenerate_files.pl;fp=android%2Fgenerate_files.pl;h=cdc7b54bb1aad1f71cf0493b0965691f1a25a691;hp=84d400d5b12f88d4cd29f1cc5d420ae0fd122046;hb=88cfe534a698a0562e81345957a50714af1453bc;hpb=d1ae2829ff0fd2a96c16a0c8c5420efaa47d7b30 diff --git a/android/generate_files.pl b/android/generate_files.pl old mode 100644 new mode 100755 index 84d400d5..cdc7b54b --- a/android/generate_files.pl +++ b/android/generate_files.pl @@ -1,1722 +1,1723 @@ -#!/usr/bin/perl -w -# Copyright © 2008-2015 Jamie Zawinski -# Copyright © 2015 Dennis Sheil -# -# Permission to use, copy, modify, distribute, and sell this software and its -# documentation for any purpose is hereby granted without fee, provided that -# the above copyright notice appear in all copies and that both that -# copyright notice and this permission notice appear in supporting -# documentation. No representations are made about the suitability of this -# software for any purpose. It is provided "as is" without express or -# implied warranty. -# -# This parses the .c and .xml files and makes sure they are in sync: that -# options are spelled the same, and that all the numbers are in sync. -# Some of that functionality may be removed in the future. -# -# This also generates necessary Android files based on the information in -# those source and XML files. -# -# For the moment, the get_keys_and_values() subroutine is where support for -# previously unsupported Android live wallpapers is added. -# -# Created: 13-May-2015. - -require 5; -use diagnostics; -use strict; - -my $progname = $0; $progname =~ s@.*/@@g; -my ($version) = ('$Revision: 1.0 $' =~ m/\s(\d[.\d]+)\s/s); - -my $verbose = 0; - - -my $xlockmore_default_opts = ''; -foreach (qw(count cycles delay ncolors size font)) { - $xlockmore_default_opts .= "{\"-$_\", \".$_\", XrmoptionSepArg, 0},\n"; -} -$xlockmore_default_opts .= - "{\"-wireframe\", \".wireframe\", XrmoptionNoArg, \"true\"},\n" . - "{\"-3d\", \".use3d\", XrmoptionNoArg, \"true\"},\n" . - "{\"-no-3d\", \".use3d\", XrmoptionNoArg, \"false\"},\n"; - -my $thread_default_opts = - "{\"-threads\", \".useThreads\", XrmoptionNoArg, \"True\"},\n" . - "{\"-no-threads\", \".useThreads\", XrmoptionNoArg, \"False\"},\n"; - -my $analogtv_default_opts = ''; -foreach (qw(color tint brightness contrast)) { - $analogtv_default_opts .= "{\"-tv-$_\", \".TV$_\", XrmoptionSepArg, 0},\n"; -} - -$analogtv_default_opts .= $thread_default_opts; - - -sub parse_settings_xml($) { - - my ($saver) = @_; - - my $file = "project/xscreensaver/res/values/settings.xml"; - my $body = ''; - - local *IN; - - if (-e $file) { - open (IN, '<', $file) || error ("$file: $!"); - } - else { - my @short; - return @short; - } - - while () { $body .= $_; } - close IN; - $file =~ s@^.*/@@; - $body =~ s// /gsi; - $body =~ s/\s+/ /gs; - $body =~ s/([^\"]+)/); - $loop = $name; - - if ($name =~ /^$saver/) { - error ("$saver: $saver already in $file"); - } - - } elsif ($type eq 'item') { - - my ($item_value) = ($args =~ m/>(.+)/); - my $item = $loop . " = " . $item_value; - push @all, $item; - - } else { - error ("$file: unknown type \"$type\" for no arg"); - } - } - - return @all; - -} - - -sub parse_items_xml($) { - - my ($saver) = @_; - - my $file = "project/xscreensaver/res/values/items.xml"; - my $body = ''; - my (%pixkeys) ; - - local *IN; - - if (-e $file) { - open (IN, '<', $file) || error ("$file: $!"); - } - else { - my %short; - return %short; - } - - while () { $body .= $_; } - close IN; - $file =~ s@^.*/@@; - $body =~ s// /gsi; - - $body =~ s/\s+/ /gs; - $body =~ s/([^\"]+)/); - - if ($name =~ /^$saver/) { - error ("$saver: $saver already in $file"); - } - - $pixkeys{$name} = $value; - - } else { - error ("$file: unknown type \"$type\" for no arg"); - } - } - - return (%pixkeys); -} - - -sub parse_glue($) { - my ($saver) = @_; - my $file = "gen/glue.c"; - my $in; - - if (-e $file) { - open ($in, '<', $file) || error ("$file: $!"); - } - else { - my @short; - return @short; - } - - my $body = ''; - while (<$in>) { $body .= $_; } - close $in; - $file =~ s@^.*/@@; - $body =~ s@^#\s*(if|ifdef|ifndef|elif|else|endif).*$@@gm; - - my (@hacks); - if ($body =~ m/table\s*\*([a-z,\s\*_]+)xscreensaver_function_table;/s) { - foreach (split (/,\s*\n/, $1)) { - s/^\s*//s; - s/\*//s; - my @ftables = split (/_/, $_); - my $ftable = $ftables[0]; - if ($ftable eq $saver) { - error("$saver is already in glue"); - } - push @hacks, $ftable; - } - } - return @hacks; -} - -# Returns two tables: -# - A table of the default resource values. -# - A table of "-switch" => "resource: value", or "-switch" => "resource: %" -# -sub parse_src($) { - my ($saver) = @_; - my $ffile = lc($saver) . ".c"; - - # kludge... - $ffile = 'apple2-main.c' if ($ffile eq 'apple2.c'); - $ffile = 'sproingiewrap.c' if ($ffile eq 'sproingies.c'); - $ffile = 'b_lockglue.c' if ($ffile eq 'bubble3d.c'); - $ffile = 'polyhedra-gl.c' if ($ffile eq 'polyhedra.c'); - $ffile = 'companion.c' if ($ffile eq 'companioncube.c'); - - my $file = "../hacks/" . $ffile; - - $file = "../hacks/glx/$ffile" unless (-f $file); - my $body = ''; - open (my $in, '<', $file) || error ("$file: $!"); - while (<$in>) { $body .= $_; } - close $in; - $file =~ s@^.*/@@; - - my $xlockmore_p = 0; - my $thread_p = ($body =~ m/THREAD_DEFAULTS/); - my $analogtv_p = ($body =~ m/ANALOGTV_DEFAULTS/); - - $body =~ s@/\*.*?\*/@@gs; - $body =~ s@^#\s*(if|ifdef|ifndef|elif|else|endif).*$@@gm; - $body =~ s/(THREAD|ANALOGTV)_(DEFAULTS|OPTIONS)(_XLOCK)?//gs; - - print STDERR "$progname: $file: defaults:\n" if ($verbose > 2); - my %res_to_val; - if ($body =~ m/_defaults\s*\[\]\s*=\s*{(.*?)}\s*;/s) { - foreach (split (/,\s*\n/, $1)) { - s/^\s*//s; - s/\s*$//s; - next if m/^0?$/s; - my ($key, $val) = m@^\"([^:\s]+)\s*:\s*(.*?)\s*\"$@; - print STDERR "$progname: $file: unparsable: $_\n" unless $key; - $key =~ s/^[.*]//s; - $res_to_val{$key} = $val; - print STDERR "$progname: $file: $key = $val\n" if ($verbose > 2); - } - } elsif ($body =~ m/\#\s*define\s*DEFAULTS\s*\\?\s*(.*?)\n[\n#]/s) { - $xlockmore_p = 1; - my $str = $1; - $str =~ s/\"\s*\\\n\s*\"//gs; - $str =~ m/^\s*\"(.*?)\"\s*\\?\s*$/ || - error ("$file: unparsable defaults: $str"); - $str = $1; - $str =~ s/\s*\\n\s*/\n/gs; - foreach (split (/\n/, $str)) { - my ($key, $val) = m@^([^:\s]+)\s*:\s*(.*?)\s*$@; - print STDERR "$progname: $file: unparsable: $_\n" unless $key; - $key =~ s/^[.*]//s; - $res_to_val{$key} = $val; - print STDERR "$progname: $file: $key = $val\n" if ($verbose > 2); - } - - while ($body =~ s/^#\s*define\s+(DEF_([A-Z\d_]+))\s+\"([^\"]+)\"//m) { - my ($key1, $key2, $val) = ($1, lc($2), $3); - $key2 =~ s/_(.)/\U$1/gs; # "foo_bar" -> "fooBar" - $key2 =~ s/Rpm/RPM/; # kludge - $res_to_val{$key2} = $val; - print STDERR "$progname: $file: $key1 ($key2) = $val\n" - if ($verbose > 2); - } - - } else { - error ("$file: no defaults"); - } - - $body =~ m/XSCREENSAVER_MODULE(_2)?\s*\(\s*\"([^\"]+)\"/ || - error ("$file: no module name"); - $res_to_val{progclass} = $2; - $res_to_val{doFPS} = 'false'; - print STDERR "$progname: $file: progclass = $2\n" if ($verbose > 2); - - print STDERR "$progname: $file: switches to resources:\n" - if ($verbose > 2); - my %switch_to_res; - $switch_to_res{-fps} = 'doFPS: true'; - $switch_to_res{-fg} = 'foreground: %'; - $switch_to_res{-bg} = 'background: %'; - - my ($ign, $opts) = ($body =~ m/(_options|\bopts)\s*\[\]\s*=\s*{(.*?)}\s*;/s); - if ($xlockmore_p || $thread_p || $analogtv_p || $opts) { - $opts = '' unless $opts; - $opts .= ",\n$xlockmore_default_opts" if ($xlockmore_p); - $opts .= ",\n$thread_default_opts" if ($thread_p); - $opts .= ",\n$analogtv_default_opts" if ($analogtv_p); - - foreach (split (/,\s*\n/, $opts)) { - s/^\s*//s; - s/\s*$//s; - next if m/^$/s; - next if m/^{\s*0\s*,/s; - my ($switch, $res, $type, $v0, $v1, $v2) = - m@^ \s* { \s * \"([^\"]+)\" \s* , - \s * \"([^\"]+)\" \s* , - \s * ([^\s]+) \s* , - \s * (\"([^\"]*)\"|([a-zA-Z\d_]+)) \s* }@xi; - print STDERR "$progname: $file: unparsable: $_\n" unless $switch; - my $val = defined($v1) ? $v1 : $v2; - $val = '%' if ($type eq 'XrmoptionSepArg'); - $res =~ s/^[.*]//s; - $res =~ s/^[a-z\d]+\.//si; - $switch =~ s/^\+/-no-/s; - - $val = "$res: $val"; - if (defined ($switch_to_res{$switch})) { - print STDERR "$progname: $file: DUP! $switch = \"$val\"\n" - if ($verbose > 2); - } else { - $switch_to_res{$switch} = $val; - print STDERR "$progname: $file: $switch = \"$val\"\n" - if ($verbose > 2); - } - } - } else { - error ("$file: no options"); - } - - return (\%res_to_val, \%switch_to_res); -} - -# Returns a list of: -# "resource = default value" -# or "resource != non-default value" -# -sub parse_manifest_xml($$) { - my @result = (); - my ($saver, $switch_to_res) = @_; - my $file = "project/xscreensaver/AndroidManifest.xml"; - my $body = ''; - local *IN; - - if (-e $file) { - open (IN, "<$file") || error ("$file: $!"); - } - else { - return @result; - } - - while () { $body .= $_; } - close IN; - $file =~ s@^.*/@@; - - $body =~ s// /gsi; - - $body =~ s/\s+/ /gs; - $body =~ s/ 2); - - foreach (split (m/\001/, $body)) { - next if (m/^\s*$/s); - my ($type, $args) = m@^<([?/]?[-_a-z]+)\b\s*(.*)$@si; - error ("$progname: $file: unparsable: $_") unless $type; - next if ($type =~ m@^/@); - if ($type eq 'meta-data') { - my ($value) = ($args =~ m/\@xml\/([^\"]+)\"/); - push @result, $value; - } - } - return @result; -} - -# Returns a list of: -# "resource = default value" -# or "resource != non-default value" -# -sub parse_strings_xml($$) { - my @result = (); - my ($saver, $switch_to_res) = @_; - my $file = "project/xscreensaver/res/values/strings.xml"; - my $body = ''; - local *IN; - - if (-e $file) { - open (IN, "<$file") || error ("$file: $!"); - } - else { - return @result; - } - - while () { $body .= $_; } - close IN; - $file =~ s@^.*/@@; - - $body =~ s// /gsi; - - $body =~ s/\s+/ /gs; - $body =~ s/ 2); - - my $saver_name = $saver . "_name"; - - foreach (split (m/\001/, $body)) { - next if (m/^\s*$/s); - my ($type, $args) = m@^<([?/]?[-_a-z]+)\b\s*(.*)$@si; - error ("$progname: $file: unparsable: $_") unless $type; - next if ($type =~ m@^/@); - - if ($type =~ m/^([hv]group|\?xml|resources|xscreensaver-(image|text|updater))/s) { - - } elsif ($type eq 'string') { - my ($name) = ($args =~ m/\bname\s*=\s*\"([^\"]+)\"/); - my ($value) = ($args =~ m/>([^\"]+)/); - my ($val) = "$name = $value"; - if ($saver_name eq $name) { - error ("$saver: $saver already in $file"); - } - push @result, $val; - } elsif ($type eq 'item') { - # ignore - } else { - error ("$file: unknown type \"$type\" for no arg"); - } - } - - return @result; -} - - - -# Returns a list of: -# "resource = default value" -# or "resource != non-default value" -# -sub parse_xml($$) { - my ($saver, $switch_to_res) = @_; - my $file = "../hacks/config/" . lc($saver) . ".xml"; - my $body = ''; - local *IN; - open (IN, "<$file") || error ("$file: $!"); - while () { $body .= $_; } - close IN; - $file =~ s@^.*/@@; - - my @result = (); - - $body =~ s// /gsi; - - $body =~ s/\s+/ /gs; - $body =~ s/ 2); - foreach (split (m/\001/, $body)) { - next if (m/^\s*$/s); - my ($type, $args) = m@^<([?/]?[-_a-z]+)\b\s*(.*)$@si; - - my $type_val; - error ("$progname: $file: unparsable: $_") unless $type; - next if ($type =~ m@^/@); - - if ($type =~ m/^([hv]group|\?xml|command|string|file|_description|xscreensaver-(image|text|updater))/s) { - - } elsif ($type eq 'screensaver') { - my ($name) = ($args =~ m/\b_label\s*=\s*\"([^\"]+)\"/); - my $val = "progclass = $name"; - push @result, $val; - print STDERR "$progname: $file: name: $name\n" if ($verbose > 2); - - } elsif ($type eq 'video') { - error ("$file: multiple videos") if $video; - ($video) = ($args =~ m/\bhref="(.*?)"/); - error ("$file: unparsable video") unless $video; - error ("$file: unparsable video URL") - unless ($video =~ m@^https?://www\.youtube\.com/watch\?v=[^?&]+$@s); - - } elsif ($type eq 'number') { - my ($arg) = ($args =~ m/\barg\s*=\s*\"([^\"]+)\"/); - my ($val) = ($args =~ m/\bdefault\s*=\s*\"([^\"]+)\"/); - $val = '' unless defined($val); - - my ($low) = ($args =~ m/\blow\s*=\s*\"([^\"]+)\"/); - my ($high) = ($args =~ m/\bhigh\s*=\s*\"([^\"]+)\"/); - - my ($ll) = ($args =~ m/\b_low-label\s*=\s*\"([^\"]+)\"/); - my ($hl) = ($args =~ m/\b_high-label\s*=\s*\"([^\"]+)\"/); - - my $switch = $arg; - $switch =~ s/\s+.*$//; - my ($res) = $switch_to_res->{$switch}; - error ("$file: no resource for $type switch \"$arg\"") unless $res; - $res =~ s/: \%$//; - error ("$file: unparsable value: $res") if ($res =~ m/:/); - - $type_val = "$res" . "_type = $type"; - push @result, $type_val; - $val = "$res = $val"; - push @result, $val; - $val = "$res" . "_low = $low"; - push @result, $val; - $val = "$res" . "_high = $high"; - push @result, $val; - $val = "$res" . "_low-label = $ll"; - push @result, $val; - $val = "$res" . "_high-label = $hl"; - push @result, $val; - - print STDERR "$progname: $file: number: $val\n" if ($verbose > 2); - - } elsif ($type eq 'boolean') { - my ($set) = ($args =~ m/\barg-set\s*=\s*\"([^\"]+)\"/); - my ($unset) = ($args =~ m/\barg-unset\s*=\s*\"([^\"]+)\"/); - my ($arg) = $set || $unset || error ("$file: unparsable: $args"); - my ($res) = $switch_to_res->{$arg}; - error ("$file: no resource for boolean switch \"$arg\"") unless $res; - my ($res2, $val) = ($res =~ m/^(.*?): (.*)$/s); - error ("$file: unparsable boolean resource: $res") unless $res2; - $res = $res2; - $type_val = "$res" . "_type = $type"; - push @result, $type_val; -# $val = ($set ? "$res != $val" : "$res = $val"); - $val = "$res != $val"; - push @result, $val; - - print STDERR "$progname: $file: boolean: $val\n" if ($verbose > 2); - - } elsif ($type eq 'select') { - $args =~ s/{$set}; - error ("$file: no resource for select switch \"$set\"") unless $res; - - my ($res2, $val2) = ($res =~ m/^(.*?): (.*)$/s); - error ("$file: unparsable select resource: $res") unless $res2; - $res = $res2; - $type_val = "$res" . "_type = $type"; - push @result, $type_val; - $val = $val2 unless ($val2 eq '%'); - - error ("$file: mismatched resources: $res vs $this_res") - if (defined($this_res) && $this_res ne $res); - $this_res = $res; - - $val = "$res != $val"; - push @result, $val; - $val = "$res" . "_type = $type"; - push @result, $val; - - print STDERR "$progname: $file: select: $val\n" if ($verbose > 2); - - } else { - error ("$file: multiple default options: $set") if ($unset_p); - $unset_p++; - } - } - - } else { - error ("$file: unknown type \"$type\" for no arg"); - } - } - -# error ("$file: no video") unless $video; - print STDERR "\n$file: WARNING: no video\n\n" unless $video; - - return @result; -} - - -sub parse_then_make($) { - my ($saver) = @_; - - # kludge - return 0 if ($saver =~ m/(-helper)$/); - - my ($src_opts, $switchmap) = parse_src ($saver); - my (@xml_opts) = parse_xml ($saver, $switchmap); - - # tests if hack is supported yet - my (@test) = get_keys_and_values($saver, @xml_opts); - my (@strings_xml_opts) = parse_strings_xml ($saver, $switchmap); - my (%pixkeys) = parse_items_xml($saver); - my (@manifest_xml_opts) = parse_manifest_xml ($saver, $switchmap); - my (@glue_hacks) = parse_glue($saver); - my (@settings_xml_opts) = parse_settings_xml($saver); - - my (@all_settings) = get_settings($saver, $switchmap, \@xml_opts); - - make_settings($saver); - make_service($saver); - make_wallpaper($saver, @xml_opts); - - make_manifest($saver, @manifest_xml_opts); - - make_hack_xml($saver); - make_hack_settings_xml($saver, @xml_opts); - make_strings_xml($saver, \@xml_opts, \@strings_xml_opts); - make_items_xml($saver, \@xml_opts, \%pixkeys); - make_settings_xml($saver, \@all_settings, \@settings_xml_opts); - - make_glue($saver, @glue_hacks); - - return 0; -} - - -sub make_manifest($$) { - my ($saver, @manifest_opts) = @_; - push @manifest_opts, $saver unless grep{$_ eq $saver} @manifest_opts; - my $hack = ucfirst($saver); - my $file = "project/xscreensaver/AndroidManifest.xml"; - open (my $in, '>', $file) || error ("$file: $!"); - - my $body = ("\n" . - "\n" . - "\n" . - "\n\n"); - - foreach my $save (@manifest_opts) { - my $hac = ucfirst($save); - $body = $body . ("\n" . - " \n" . - " \n" . - " \n" . - " \n" . - "\n" . - "\n" . - "\n\n"); - - } - - $body = $body . ("\n\n" . - "\n" . - "\n" . - "\n"); - - print $in $body; - close $in; -} - - -sub make_hack_settings_xml($$) { - - my ($saver, @xml_opts) = @_; - my $hack = ucfirst($saver); - my $file = "project/xscreensaver/res/xml/" . $saver . "_settings.xml"; - my (%saver_keys) = get_keys_and_values($saver, @xml_opts); - - open (my $in, '>', $file) || error ("$file: $!"); - - my $body = ("\n" . - "\n" . - " \n"); - - my @keyarray = keys %saver_keys; - - - foreach my $sgkey (@keyarray) { - - my $type = get_type($sgkey, @xml_opts); - - - if ($type eq "number") { - $body = $body . " \n"; - } else { - $body = $body . " \n"; - } - } - - $body = $body . " \n" . - "\n"; - - print $in $body; - close $in; -} - - -sub make_items_xml($\@\%) { - my $saver = $_[0]; - my @xml_opts = @{$_[1]}; - my %pixkeys = %{$_[2]}; - - my $file = "project/xscreensaver/res/values/items.xml"; - - my $body = ("\n" . - "\n"); - - while(my($key, $value) = each %pixkeys) { - $body = $body . " ". $value . "\n"; - - } - - my (%saver_keys) = get_keys_and_values($saver, @xml_opts); - my @keyarray = keys %saver_keys; - - foreach my $item_key (@keyarray) { - - my $type = get_type($item_key, @xml_opts); - - if ($type eq "number") { - - my ($low, $high, $default) = get_low_high_def($item_key, @xml_opts); - my $float = ($default - $low) / ($high - $low); - - $body = ($body . - " $float\n"); - } - } - - $body = ($body . - "\n"); - open (my $in, '>', $file) || error ("$file: $!"); - print $in $body; - close $in; -} - - -sub get_type($@) { - - my($type_key, @xml_opts) = @_; - my $type=''; - - foreach my $claim (@xml_opts) { - - my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); - if ($res eq $type_key . "_type") { - $type = $xval; - } - - } - return $type; - -} - - -sub get_low_high_def($@) { - - my($sgkey, @xml_opts) = @_; - - my $low; - my $high; - my $default; - - foreach my $claim (@xml_opts) { - my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); - if ($res eq $sgkey . "_low") { - $low = $xval; - } - elsif ($res eq $sgkey . "_high") { - $high = $xval; - } - elsif ($res eq $sgkey) { - $default = $xval; - } - } - - return ($low, $high, $default); - -} - - -sub make_settings_xml($\@\@) { - - my $saver = $_[0]; - my @xml_opts = @{$_[1]}; - my @old_settings_xml = @{$_[2]}; - my $file = "project/xscreensaver/res/values/settings.xml"; - - my $body = ("\n" . - "\n"); - - my $arrays_from_old_settings = old_settings_string_arrays(@old_settings_xml); - - $body = $body . $arrays_from_old_settings; - - my (%saver_keys) = get_keys_and_values($saver, @xml_opts); - my @key_array = keys %saver_keys; - - my ($low, $high, $low_label, $high_label, $type); - my @selects; - - # for each setting of the hack which we chose to add - foreach my $selected_setting_key (@key_array) { - # see what values were in the relevant xml in hacks/config for this hack - foreach my $claim (@xml_opts) { - my ($xres, $xcompare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); - if ($xres =~ /^$selected_setting_key/) { - my $one, my $two; - if ($xres =~ /_/ ) { - ($one, $two) = ($xres =~ m/^(.*)_(.*)$/s); - if ($two eq "type") { - $type = $xval; - } elsif ($two eq "low-label") { - $low_label = $xval; - } elsif ($two eq "high-label") { - $high_label = $xval; - } elsif ($two eq "low") { - $low = $xval; - } elsif ($two eq "high") { - $high = $xval; - } - } else { - $one = $xres; - if ($type eq "select") { - push @selects, $xval; - } - } - } - } - - # add setting values based on the setting type (boolean, number, select) - if ($type eq "boolean") { - $body = $body . " \n" . - " \"True\"\n" . - " \"False\"\n" . - " \n" . - " \n" . - " \@string/t\n" . - " \@string/f\n" . - " \n"; - } elsif ($type eq "number") { - $body = $body . " \n" . - " \"" . $low_label . "\"\n" . - " \"" . $high_label . "\"\n" . - " \n" . - " \n" . - " \"" . $low . "\"\n" . - " \"" . $high . "\"\n" . - " \n"; - } elsif ($type eq "select") { - $body = $body . " \n"; - - foreach my $item (@selects) { - $body = $body . " \"" . $item . "\"\n" ; - } - - $body = $body . " \n" . - " \n"; - - foreach my $item (@selects) { - $body = $body . " \"" . $item . "\"\n" ; - } - - $body = $body . " \n"; - } - - @selects=(); - } - - $body = ($body . - "\n"); - - open (my $in, '>', $file) || error ("$file: $!"); - print $in $body; - close $in; - -} - - -sub old_settings_string_arrays(@) { - - my (@old_settings_file) = @_; - - my $body = ''; - my $current_string_array=''; - - - foreach my $claim (@old_settings_file) { - my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=) (.*)$/s); - error ("unparsable xml claim: $_") unless $compare; - - if ($current_string_array ne $res) { - if (length($current_string_array) > 0) { - $body = $body . " \n"; - } - - $current_string_array = $res; - $body = $body . " \n"; - } - - $body = $body . " " . $xval . "\n"; - } - - if ($#old_settings_file > -1) { - $body = $body . " \n"; - } - - - return $body; - -} - - -# TODO: This adds the proper parameters to settings such as hilbert's, but it -# does not remove the improper parameters from hacks such as Hilbert yet. -# -sub get_settings($$\@) { - my $saver = $_[0]; - my $switchmap = $_[1]; - my @xml_opts = @{$_[2]}; - - my @keys = keys % { $switchmap}; - - my $res_seen = 0; - my $val_seen = 0; - my @also; - foreach my $sgkey (@keys) { - my ($k, $v) = ($switchmap->{$sgkey} =~ m/^(.*): (.*)$/); - - if ($v ne '%') { - foreach my $claim (@xml_opts) { - my ($res, $compare, $val) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); - if ($res eq $k && $val eq $v) { - $val_seen = $val_seen + 1; - } - elsif ($res eq $k) { - $res_seen = $res_seen + 1; - } - } - - if ($val_seen eq 0 && $res_seen > 0) { - my $so = "$k != $v"; - push @also, $so; - } - - $val_seen = 0; - $res_seen = 0; - } - } - - my @all = (@xml_opts, @also); - return @all; - -} - - -sub make_strings_xml($\@\@) { - - my $saver = $_[0]; - my @xml_opts = @{$_[1]}; - my @strings_xml_opts = @{$_[2]}; - - my $saver_name = $saver . "_name"; - my $hack = ucfirst($saver); - my $file = "project/xscreensaver/res/values/strings.xml"; - my (%saver_keys) = get_keys_and_values($saver, @xml_opts); - - my $body = ("\n" . - "\n" . - " Hello World!\n" . - " Xscreensaver\n" . - " A live wallpaper\n\n" . - " Xscreensaver\n" . - " jwz and helpers\n" . - " True\n" . - " False\n"); - - foreach my $claim (@strings_xml_opts) { - my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); - error ("$saver: unparsable xml claim: $_") unless $compare; - if ($res eq 'hello' || - $res eq 'service_label' || - $res eq 'description' || - $res eq 'app_name' || - $res eq 'author' || - $res eq 't' || - $res eq 'f') { - } - elsif ($res eq $saver_name) { - error ("$saver: $saver already in $file"); - } - else { - $body = ($body . - " " . $xval . "\n"); - } - } - - $body = ($body . - " " . $hack . - "\n" . - " Settings\n" . - " " . $hack . - - "\n"); - - my @keyarray = keys %saver_keys; - - foreach my $sgkey (@keyarray) { - - my $type = get_type($sgkey, @xml_opts); - - if ($type eq "number") { - - my ($low, $high, $default) = get_low_high_def($sgkey, @xml_opts); - my $float = ($default - $low) / ($high - $low); - - $body = ($body . " " . "Set " . $sgkey . "\n" . - " " . "Choose " . $sgkey . "\n" . - " " . $low . "\n" . - " " . $high . "\n" . - " " . $saver_keys{$sgkey} . "\n"); - } - else { - - $body = ($body . " " . "Set " . $sgkey . "\n" . - " " . "Choose " . $sgkey . "\n" . - " " . $saver_keys{$sgkey} . "\n"); - } - } - - $body = ($body . - "\n"); - - open (my $in, '>', $file) || error ("$file: $!"); - print $in $body; - close $in; -} - - -sub make_hack_xml($) { - my ($saver) = @_; - my $hack = ucfirst($saver); - - my $dir = "project/xscreensaver/res/xml/"; - my $file = $dir . $saver . ".xml"; - my $in; - - if (-d $dir) { - open ($in, '>', $file) || error ("$file: $!"); - } - else { - mkdir $dir; - open ($in, '>', $file) || error ("$file: $!"); - } - - my $body = ("\n" . - "\n"); - - print $in $body; - close $in; -} - - -sub make_glue($$) { - my ($saver, @glue_hacks) = @_; - my (@hacks) = @glue_hacks; - - push @hacks, $saver; - - my $dir = "gen/"; - my $file = $dir . "glue.c"; - my $in; - - if (-d $dir) { - open ($in, '>', $file) || error ("$file: $!"); - } - else { - mkdir $dir; - open ($in, '>', $file) || error ("$file: $!"); - } - - - my $body = ("#include \n" . - "#include \n" . - "#include \n" . - "#include \n" . - "#include \n" . - "#include \n" . - "#include \n\n" . - "#include \"screenhackI.h\"\n" . - "#include \"jwzglesI.h\"\n" . - "#include \"version.h\"\n\n" . - "void drawXscreensaver();\n\n" . - "int sWindowWidth = 0;\n" . - "int sWindowHeight = 0;\n" . - "int initTried = 0;\n" . - "int renderTried = 0;\n" . - "int resetTried = 0;\n" . - "int currentFlip = 0;\n\n" . - "pthread_mutex_t mutg = PTHREAD_MUTEX_INITIALIZER;\n\n" . - "extern struct xscreensaver_function_table " . - "*xscreensaver_function_table;\n\n" . - "// if adding a table here, increase the magic number\n" . - "struct xscreensaver_function_table\n"); - - for my $i (0 .. $#hacks) { - $body = $body . " *" . $hacks[$i] ; - $body = $body . "_xscreensaver_function_table"; - if ($i eq $#hacks ) { - $body = $body . ";\n\n"; - } - else { - $body = $body . ",\n"; - } - } - - $body = $body . "struct running_hack {\n" . - " struct xscreensaver_function_table *xsft;\n" . - " Display *dpy;\n" . - " Window window;\n" . - " void *closure;\n" . - "};\n\n" . - "const char *progname;\n" . - "const char *progclass;\n\n" . - "struct running_hack rh["; - $body = $body . scalar(@hacks); - $body = $body . "];\n" . - "// ^ magic number of hacks - TODO: remove magic number\n\n\n" . - "int chosen;\n" . - "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_CallNative_nativeInit\n" . - " (JNIEnv * env);\n" . - "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_CallNative_nativeResize\n" . - " (JNIEnv * env, jobject thiz, jint w, jint h);\n" . - "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_CallNative_nativeRender\n" . - " (JNIEnv * env);\n" . - "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_CallNative_nativeDone\n" . - " (JNIEnv * env);\n"; - - foreach my $bighack (@hacks) { - my $bh = ucfirst($bighack); - $body = $body . "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_gen_" . $bh . - "Wallpaper_allnativeSettings\n" . - " (JNIEnv * env, jobject thiz, jstring jhack," . - " jstring hackPref,\n" . - " jint draw, jstring key);\n"; - - } - - $body = $body . "\n\n\nvoid doinit()\n{\n\n" ; - - for my $j (0 .. $#hacks) { - if ($j == 0) { - $body = $body . " if (chosen == " . $j . ") {\n" ; - } elsif ($j == $#hacks) { - $body = $body . " } else {\n" ; - } else { - $body = $body . " } else if (chosen == " . $j . ") {\n"; - } - $body = $body . " progname = \"" . $hacks[$j] . "\";\n" . - " rh[chosen].xsft = &" . $hacks[$j] . - "_xscreensaver_function_table;\n" ; - } - - $body = $body . " }\n\n" ; - $body = $body . " rh[chosen].dpy = jwxyz_make_display(0, 0);\n" . - " rh[chosen].window = XRootWindow(rh[chosen].dpy, 0);\n" . - "// TODO: Zero looks right, " . - "but double-check that is the right number\n\n" . - " progclass = rh[chosen].xsft->progclass;\n\n" . - " if (rh[chosen].xsft->setup_cb)\n" . - " rh[chosen].xsft->setup_cb(rh[chosen].xsft,\n" . - " rh[chosen].xsft->setup_arg);\n\n" . - " if (resetTried < 1) {\n" . - " resetTried++;\n" . - " jwzgles_reset();\n" . - " }\n\n" . - " void *(*init_cb) (Display *, Window, void *) =\n" . - " (void *(*)(Display *, Window, void *)) " . - "rh[chosen].xsft->init_cb;\n\n" . - " rh[chosen].closure =\n" . - " init_cb(rh[chosen].dpy, rh[chosen].window,\n" . - " rh[chosen].xsft->setup_arg);\n\n}\n\n\n" . - "void drawXscreensaver()\n{\n" . - " pthread_mutex_lock(&mutg);\n" . - " rh[chosen].xsft->draw_cb(rh[chosen].dpy, " . - "rh[chosen].window,\n" . - " rh[chosen].closure);\n" . - " pthread_mutex_unlock(&mutg);\n\n}\n\n\n" . - "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_CallNative_nativeInit\n" . - " (JNIEnv * env) {\n\n" . - " if (initTried < 1) {\n" . - " initTried++;\n" . - " } else {\n" . - " if (!rh[chosen].dpy) {\n" . - " doinit();\n" . - " } else {\n" . - " rh[chosen].xsft->free_cb(rh[chosen].dpy, " . - "rh[chosen].window,\n" . - " rh[chosen].closure);\n" . - " jwxyz_free_display(rh[chosen].dpy);\n" . - " rh[chosen].dpy = NULL;\n" . - " rh[chosen].window = NULL;\n" . - " if (!rh[chosen].dpy) {\n" . - " doinit();\n" . - " }\n\n }\n" . - " }\n\n}\n\n\n" . - "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_CallNative_nativeResize\n" . - " (JNIEnv * env, jobject thiz, jint w, jint h) {\n\n" . - " sWindowWidth = w;\n" . - " sWindowHeight = h;\n\n" . - " if (!rh[chosen].dpy) {\n" . - " doinit();\n" . - " }\n\n" . - " jwxyz_window_resized(rh[chosen].dpy, " . - "rh[chosen].window, 0, 0, w, h, 0);\n\n" . - " rh[chosen].xsft->reshape_cb(rh[chosen].dpy, " . - "rh[chosen].window,\n" . - " rh[chosen].closure, w, h);\n}\n\n" . - "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_CallNative_nativeRender\n" . - " (JNIEnv * env) {\n" . - " if (renderTried < 1) {\n" . - " renderTried++;\n" . - " } else {\n" . - " drawXscreensaver();\n" . - " }\n}\n\n" . - "// TODO: Check Java side is calling this properly\n" . - "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_CallNative_nativeDone\n" . - " (JNIEnv * env) {\n\n" . - " rh[chosen].xsft->free_cb(rh[chosen].dpy, " . - "rh[chosen].window,\n" . - " rh[chosen].closure);\n" . - " jwxyz_free_display(rh[chosen].dpy);\n" . - " rh[chosen].dpy = NULL;\n" . - " rh[chosen].window = NULL;\n\n}\n\n" ; - - for my $j (0 .. $#hacks) { - my $jhack = ucfirst($hacks[$j]); - - $body = $body . "JNIEXPORT void JNICALL\n" . - " Java_org_jwz_xscreensaver_gen_" . $jhack . - "Wallpaper_allnativeSettings\n" . - " (JNIEnv * env, jobject thiz, jstring jhack," . - " jstring hackPref,\n" . - " jint draw, jstring key) {\n\n" . - " const char *chack = " . - "(*env)->GetStringUTFChars(env, hackPref, NULL);\n" . - " char *hck = (char *) chack;\n" . - " const char *kchack = " . - "(*env)->GetStringUTFChars(env, key, NULL);\n" . - " char *khck = (char *) kchack;\n\n" . - " if (draw == 2) {\n" . - " set" . $jhack . "Settings(hck, khck);\n" . - " }\n\n" . - " chosen = " . $j . ";\n}\n\n"; - - } - - - print $in $body; - close $in; -} - -sub make_wallpaper($$) { - my ($saver, @xml_opts) = @_; - my $hack = ucfirst($saver); - my $file = "project/xscreensaver/src/org/jwz/xscreensaver/gen/"; - $file = $file . $hack . "Wallpaper.java"; - my (%saver_keys) = get_keys_and_values($saver, @xml_opts); - - open (my $in, '>', $file) || error ("$file: $!"); - - my $body = ("package org.jwz.xscreensaver.gen;\n" . - "import javax.microedition.khronos.egl.EGLConfig;\n" . - "import javax.microedition.khronos.opengles.GL10;\n" . - "import net.rbgrn.android.glwallpaperservice.*;\n" . - "import android.opengl.GLU;\n" . - "import android.content.Context;\n" . - "import android.content.SharedPreferences;\n" . - "import org.jwz.xscreensaver.*;\n" . - "public class " . $hack . - "Wallpaper extends ARenderer {\n" . - " private static native void allnativeSettings(" . - "String hack, String hackPref, int draw, String key);\n" . - " public static final String SHARED_PREFS_NAME=\"" . $saver . - "settings\";\n" . - " CallNative cn;\n" . - " public void onSurfaceCreated(" . - "GL10 gl, EGLConfig config) {\n" . - " super.onSurfaceCreated(gl, config);\n" . - " cn = new CallNative();\n" . - " NonSurfaceCreated();\n" . - " }\n" . - " public void onDrawFrame(GL10 gl) {\n" . - " super.onDrawFrame(gl);\n" . - " allnativeSettings(\"bogus\", \"bogus\", 1, \"bogus\");\n" . - " NonDrawFrame();\n" . - " }\n" . - " void NonDrawFrame() {\n" . - " cn.nativeRender();\n" . - " }\n" . - " void doSP(SharedPreferences sspp) {\n" . - - - " String hack = \"" . $saver . "\";\n"); - - my @keyarray = keys %saver_keys; - foreach my $sgkey (@keyarray) { - - my $type = get_type($sgkey, @xml_opts); - - if ($type eq "number") { - - my ($low, $high, $default) = get_low_high_def($sgkey, @xml_opts); - my $float = ($default - $low) / ($high - $low); - - $body = $body . - " String " . $sgkey . - "_low = sspp.getString(\"" . $saver . - "_" . $sgkey . "_low\", \"". $low . "\");\n" . - " String " . $sgkey . - "_high = sspp.getString(\"" . $saver . - "_" . $sgkey . "_high\", \"" . $high . "\");\n" . - " Float " . $sgkey . "PrefF = sspp.getFloat(\"" . $saver . - "_" . $sgkey . "\", " . $float . "f);\n" . - " String " . $sgkey . "Pref = getNumber(" . $sgkey . - "_low, " . $sgkey . "_high, " . $sgkey . "PrefF);\n" . - " allnativeSettings(hack, " . $sgkey . - "Pref, 2, \"" . $saver . "_" . $sgkey . "\");\n"; - } - elsif ($type eq "boolean") { - - $body = $body . " String " . $sgkey . - "Pref = sspp.getString(\"" . $saver . "_" . $sgkey . - "\", \"" . $saver_keys{$sgkey} . "\");\n" . - " allnativeSettings(hack, " . $sgkey . - "Pref, 2, \"" . $saver . "_" . $sgkey . "\");\n"; - - } - elsif ($type eq "select") { - - $body = $body . " String " . $sgkey . - "Pref = sspp.getString(\"" . $saver . "_" . $sgkey . - "\", \"" . $saver_keys{$sgkey} . "\");\n" . - " allnativeSettings(hack, " . $sgkey . - "Pref, 2, \"" . $saver . "_" . $sgkey . "\");\n"; - - } - else { - print STDERR "$progname: type $type not yet implemented \n"; - } - - } - - $body = $body . " }\n" . - " String getNumber(String low, String high, Float pref) {\n" . - " Float lowF = Float.parseFloat(low);\n" . - " Float lowH = Float.parseFloat(high);\n" . - " Float diff = lowH - lowF;\n" . - " Float mult = pref * diff;\n" . - " Float add = mult + lowF;\n" . - " int i;\n" . - " String s;\n" . - " if (diff > 2.0) {\n" . - " i = (Integer) Math.round(add);\n" . - " s = Integer.toString(i);\n}\n" . - " else {\n" . - " s = Float.toString(add);\n}\n" . - " return s;\n" . - " }\n\n" . - " static\n" . - " {\n" . - " System.loadLibrary (\"xscreensaver\");\n" . - " }\n" . - "}\n"; - - print $in $body; - close $in; - -} - -sub get_keys_and_values($$) { - - my ($saver, @xml_opts) = @_; - my (%saver_keys) ; - - foreach my $claim (@xml_opts) { - my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); - error ("$saver: unparsable xml claim: $_") unless $compare; - - if ($saver eq "sproingies") { - if ($res eq "count") { - $saver_keys{$res} = $xval; - } - elsif ($res eq "wireframe") { - #$saver_keys{$res} = $xval; - $saver_keys{$res} = "False"; - } - - } - elsif ($saver eq "hilbert") { - if ($res eq "mode") { - $saver_keys{$res} = $xval; - } - } - elsif ($saver eq "stonerview") { - if ($res eq "transparent") { - #$saver_keys{$res} = $xval; - $saver_keys{$res} = "False"; - } - } - elsif ($saver eq "superquadrics") { - # spinspeed/speed. float/int - if ($res eq "spinspeed") { - $saver_keys{$res} = $xval; - } - } - elsif ($saver eq "bouncingcow") { - if ($res eq "count") { - $saver_keys{$res} = "3"; - } - elsif ($res eq "speed") { - $saver_keys{$res} = "0.1"; - } - } - elsif ($saver eq "unknownpleasures") { - if ($res eq "wireframe") { - $saver_keys{$res} = "True"; - } - elsif ($res eq "speed") { - $saver_keys{$res} = "3.0"; - } - #elsif ($res eq "count") { - # $saver_keys{$res} = $xval; - #} - #elsif ($res eq "resolution") { - # $saver_keys{$res} = $xval; - #} - #elsif ($res eq "ortho") { - # $saver_keys{$res} = $xval; - #} - - } - elsif ($saver eq "hypertorus") { - if ($res =~ /^(displayMode|appearance|colors|projection3d|projection4d|speedwx|speedwy|speedwz|speedxy|speedxz|speedyz)$/) { - $saver_keys{$res} = $xval; - } - } - elsif ($saver eq "glhanoi") { - if ($res =~ /^(light|fog|trails|poles|speed)$/) { - # TODO: check in xval for true/false should be higher up in logic - if ($xval =~ /^(true|false)$/) { - $saver_keys{$res} = ucfirst($xval); - } - else { - $saver_keys{$res} = $xval; - } - } - } - else { - error ("$saver: not yet supported for Android"); - } - - } - - return (%saver_keys); -} - - -sub make_service($) { - my ($saver) = @_; - my $hack = ucfirst($saver); - my $file = "project/xscreensaver/src/org/jwz/xscreensaver/gen/"; - $file = $file . $hack . "Service.java"; - open (my $in, '>', $file) || error ("$file: $!"); - - my $body = ("package org.jwz.xscreensaver.gen;\n\n" . - "import net.rbgrn.android.glwallpaperservice.*;\n" . - "import android.content.SharedPreferences;\n" . - "import org.jwz.xscreensaver.*;\n\n" . - "// Original code provided by Robert Green\n" . - "// http://www.rbgrn.net/content/354-glsurfaceview-adapted-3d-live-wallpapers\n" . - "public class " . $hack . - "Service extends GLWallpaperService {\n\n" . - " SharedPreferences sp;\n\n" . - " public " . $hack . - "Service() {\n" . - " super();\n" . - " }\n\n" . - " \@Override\n" . - " public void onCreate() {\n" . - " sp = ((XscreensaverApp)getApplication())." . - "getThePrefs($hack" . "Wallpaper.SHARED_PREFS_NAME);\n" . - " }\n\n" . - " public Engine onCreateEngine() {\n" . - " MyEngine engine = new MyEngine();\n" . - " return engine;\n" . - " }\n\n" . - " class MyEngine extends GLEngine {\n" . - " " . $hack . - "Wallpaper renderer;\n" . - " public MyEngine() {\n" . - " super();\n" . - " // handle prefs, other initialization\n" . - " renderer = new " . $hack . - "Wallpaper();\n" . - " setRenderer(renderer);\n" . - " setRenderMode(RENDERMODE_CONTINUOUSLY);\n" . - " }\n\n" . - " public void onDestroy() {\n" . - " super.onDestroy();\n" . - " if (renderer != null) {\n" . - " renderer.release(); " . - "// assuming yours has this method - it should!\n" . - " }\n" . - " renderer = null;\n" . - " }\n\n" . - " \@Override\n" . - " public void onVisibilityChanged(boolean visible) {\n" . - " super.onVisibilityChanged(visible);\n" . - " if (visible) {\n" . - " renderer.doSP(sp);\n" . - " }\n" . - " }\n\n" . - " }\n" . - " static\n" . - " {\n" . - " System.loadLibrary (\"xscreensaver\");\n" . - " }\n\n\n" . - "}\n"); - - print $in $body; - close $in; - -} - -sub make_settings($) { - my ($saver) = @_; - my $hack = ucfirst($saver); - my $dir = "project/xscreensaver/src/org/jwz/xscreensaver/gen/"; - my $file = $dir . $hack . "Settings.java"; - my $in; - - if (-d $dir) { - open ($in, '>', $file) || error ("$file: $!"); - } - else { - mkdir $dir; - open ($in, '>', $file) || error ("$file: $!"); - } - - my $body = ("/*\n" . - " * Copyright (C) 2009 Google Inc.\n" . - " *\n" . - " * Licensed under the Apache License, Version 2.0 " . - "(the \"License\"); you may not\n" . - " * use this file except in compliance with the License. " . - "You may obtain a copy of\n" . - " * the License at\n" . - " *\n" . - " * http://www.apache.org/licenses/LICENSE-2.0\n" . - " *\n" . - " * Unless required by applicable law or agreed to in writing," . - " software\n" . - " * distributed under the License is distributed" . - " on an \"AS IS\" BASIS, WITHOUT\n" . - " * WARRANTIES OR CONDITIONS OF ANY KIND," . - " either express or implied. See the\n" . - " * License for the specific language governing" . - "permissions and limitations under\n" . - " * the License.\n" . - " */\n\n" . - "package org.jwz.xscreensaver.gen;\n\n" . - "import org.jwz.xscreensaver.R;\n\n" . - "import android.content.SharedPreferences;\n" . - "import android.os.Bundle;\n" . - "import android.preference.PreferenceActivity;\n\n" . - "public class " . $hack . - "Settings extends PreferenceActivity\n" . - " implements " . - "SharedPreferences.OnSharedPreferenceChangeListener {\n\n" . - " \@Override\n" . - " protected void onCreate(Bundle icicle) {\n" . - " super.onCreate(icicle);\n" . - " getPreferenceManager().setSharedPreferencesName(\n" . - " " . $hack . - "Wallpaper.SHARED_PREFS_NAME);\n" . - " addPreferencesFromResource(R.xml." . $saver . - "_settings);\n" . - " getPreferenceManager().getSharedPreferences()." . - "registerOnSharedPreferenceChangeListener(\n" . - " this);\n" . - " }\n\n" . - " \@Override\n" . - " protected void onResume() {\n" . - " super.onResume();\n" . - " }\n\n" . - " \@Override\n" . - " protected void onDestroy() {\n" . - " getPreferenceManager().getSharedPreferences()." . - "unregisterOnSharedPreferenceChangeListener(\n" . - " this);\n" . - " super.onDestroy();\n" . - " }\n\n" . - " public void onSharedPreferenceChanged(" . - "SharedPreferences sharedPreferences,\n" . - " String key) {\n" . - " }\n" . - "}\n"); - - print $in $body; - close $in; -} - - -sub error($) { - my ($err) = @_; - print STDERR "$progname: $err\n"; - exit 1; -} - -sub usage() { - print STDERR "usage: $progname [--verbose] files ...\n"; - exit 1; -} - -sub main() { - my @files = (); - while ($#ARGV >= 0) { - $_ = shift @ARGV; - if (m/^--?verbose$/) { $verbose++; } - elsif (m/^-v+$/) { $verbose += length($_)-1; } - elsif (m/^-./) { usage; } - else { push @files, $_; } -# else { usage; } - } - - usage unless ($#files >= 0); - my $failures = 0; - foreach (@files) { $failures += parse_then_make($_); } - exit ($failures); -} - -main(); +#!/usr/bin/perl -w +# Copyright © 2008-2015 Jamie Zawinski +# Copyright © 2015 Dennis Sheil +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation. No representations are made about the suitability of this +# software for any purpose. It is provided "as is" without express or +# implied warranty. +# +# This parses the .c and .xml files and makes sure they are in sync: that +# options are spelled the same, and that all the numbers are in sync. +# Some of that functionality may be removed in the future. +# +# This also generates necessary Android files based on the information in +# those source and XML files. +# +# For the moment, the get_keys_and_values() subroutine is where support for +# previously unsupported Android live wallpapers is added. +# +# Created: 13-May-2015. + +require 5; +use diagnostics; +use strict; + +my $progname = $0; $progname =~ s@.*/@@g; +my ($version) = ('$Revision: 1.1 $' =~ m/\s(\d[.\d]+)\s/s); + +my $verbose = 0; + + +my $xlockmore_default_opts = ''; +foreach (qw(count cycles delay ncolors size font)) { + $xlockmore_default_opts .= "{\"-$_\", \".$_\", XrmoptionSepArg, 0},\n"; +} +$xlockmore_default_opts .= + "{\"-wireframe\", \".wireframe\", XrmoptionNoArg, \"true\"},\n" . + "{\"-3d\", \".use3d\", XrmoptionNoArg, \"true\"},\n" . + "{\"-no-3d\", \".use3d\", XrmoptionNoArg, \"false\"},\n"; + +my $thread_default_opts = + "{\"-threads\", \".useThreads\", XrmoptionNoArg, \"True\"},\n" . + "{\"-no-threads\", \".useThreads\", XrmoptionNoArg, \"False\"},\n"; + +my $analogtv_default_opts = ''; +foreach (qw(color tint brightness contrast)) { + $analogtv_default_opts .= "{\"-tv-$_\", \".TV$_\", XrmoptionSepArg, 0},\n"; +} + +$analogtv_default_opts .= $thread_default_opts; + + +sub parse_settings_xml($) { + + my ($saver) = @_; + + my $file = "project/xscreensaver/res/values/settings.xml"; + my $body = ''; + + local *IN; + + if (-e $file) { + open (IN, '<', $file) || error ("$file: $!"); + } + else { + my @short; + return @short; + } + + while () { $body .= $_; } + close IN; + $file =~ s@^.*/@@; + $body =~ s// /gsi; + $body =~ s/\s+/ /gs; + $body =~ s/([^\"]+)/); + $loop = $name; + + if ($name =~ /^$saver/) { + error ("$saver: $saver already in $file"); + } + + } elsif ($type eq 'item') { + + my ($item_value) = ($args =~ m/>(.+)/); + my $item = $loop . " = " . $item_value; + push @all, $item; + + } else { + error ("$file: unknown type \"$type\" for no arg"); + } + } + + return @all; + +} + + +sub parse_items_xml($) { + + my ($saver) = @_; + + my $file = "project/xscreensaver/res/values/items.xml"; + my $body = ''; + my (%pixkeys) ; + + local *IN; + + if (-e $file) { + open (IN, '<', $file) || error ("$file: $!"); + } + else { + my %short; + return %short; + } + + while () { $body .= $_; } + close IN; + $file =~ s@^.*/@@; + $body =~ s// /gsi; + + $body =~ s/\s+/ /gs; + $body =~ s/([^\"]+)/); + + if ($name =~ /^$saver/) { + error ("$saver: $saver already in $file"); + } + + $pixkeys{$name} = $value; + + } else { + error ("$file: unknown type \"$type\" for no arg"); + } + } + + return (%pixkeys); +} + + +sub parse_glue($) { + my ($saver) = @_; + my $file = "gen/glue.c"; + my $in; + + if (-e $file) { + open ($in, '<', $file) || error ("$file: $!"); + } + else { + my @short; + return @short; + } + + my $body = ''; + while (<$in>) { $body .= $_; } + close $in; + $file =~ s@^.*/@@; + $body =~ s@^#\s*(if|ifdef|ifndef|elif|else|endif).*$@@gm; + + my (@hacks); + if ($body =~ m/table\s*\*([a-z,\s\*_]+)xscreensaver_function_table;/s) { + foreach (split (/,\s*\n/, $1)) { + s/^\s*//s; + s/\*//s; + my @ftables = split (/_/, $_); + my $ftable = $ftables[0]; + if ($ftable eq $saver) { + error("$saver is already in glue"); + } + push @hacks, $ftable; + } + } + return @hacks; +} + +# Returns two tables: +# - A table of the default resource values. +# - A table of "-switch" => "resource: value", or "-switch" => "resource: %" +# +sub parse_src($) { + my ($saver) = @_; + my $ffile = lc($saver) . ".c"; + + # kludge... + $ffile = 'apple2-main.c' if ($ffile eq 'apple2.c'); + $ffile = 'sproingiewrap.c' if ($ffile eq 'sproingies.c'); + $ffile = 'b_lockglue.c' if ($ffile eq 'bubble3d.c'); + $ffile = 'polyhedra-gl.c' if ($ffile eq 'polyhedra.c'); + $ffile = 'companion.c' if ($ffile eq 'companioncube.c'); + + my $file = "../hacks/" . $ffile; + + $file = "../hacks/glx/$ffile" unless (-f $file); + my $body = ''; + open (my $in, '<', $file) || error ("$file: $!"); + while (<$in>) { $body .= $_; } + close $in; + $file =~ s@^.*/@@; + + my $xlockmore_p = 0; + my $thread_p = ($body =~ m/THREAD_DEFAULTS/); + my $analogtv_p = ($body =~ m/ANALOGTV_DEFAULTS/); + + $body =~ s@/\*.*?\*/@@gs; + $body =~ s@^#\s*(if|ifdef|ifndef|elif|else|endif).*$@@gm; + $body =~ s/(THREAD|ANALOGTV)_(DEFAULTS|OPTIONS)(_XLOCK)?//gs; + + print STDERR "$progname: $file: defaults:\n" if ($verbose > 2); + my %res_to_val; + if ($body =~ m/_defaults\s*\[\]\s*=\s*{(.*?)}\s*;/s) { + foreach (split (/,\s*\n/, $1)) { + s/^\s*//s; + s/\s*$//s; + next if m/^0?$/s; + my ($key, $val) = m@^\"([^:\s]+)\s*:\s*(.*?)\s*\"$@; + print STDERR "$progname: $file: unparsable: $_\n" unless $key; + $key =~ s/^[.*]//s; + $res_to_val{$key} = $val; + print STDERR "$progname: $file: $key = $val\n" if ($verbose > 2); + } + } elsif ($body =~ m/\#\s*define\s*DEFAULTS\s*\\?\s*(.*?)\n[\n#]/s) { + $xlockmore_p = 1; + my $str = $1; + $str =~ s/\"\s*\\\n\s*\"//gs; + $str =~ m/^\s*\"(.*?)\"\s*\\?\s*$/ || + error ("$file: unparsable defaults: $str"); + $str = $1; + $str =~ s/\s*\\n\s*/\n/gs; + foreach (split (/\n/, $str)) { + my ($key, $val) = m@^([^:\s]+)\s*:\s*(.*?)\s*$@; + print STDERR "$progname: $file: unparsable: $_\n" unless $key; + $key =~ s/^[.*]//s; + $res_to_val{$key} = $val; + print STDERR "$progname: $file: $key = $val\n" if ($verbose > 2); + } + + while ($body =~ s/^#\s*define\s+(DEF_([A-Z\d_]+))\s+\"([^\"]+)\"//m) { + my ($key1, $key2, $val) = ($1, lc($2), $3); + $key2 =~ s/_(.)/\U$1/gs; # "foo_bar" -> "fooBar" + $key2 =~ s/Rpm/RPM/; # kludge + $res_to_val{$key2} = $val; + print STDERR "$progname: $file: $key1 ($key2) = $val\n" + if ($verbose > 2); + } + + } else { + error ("$file: no defaults"); + } + + $body =~ m/XSCREENSAVER_MODULE(_2)?\s*\(\s*\"([^\"]+)\"/ || + error ("$file: no module name"); + $res_to_val{progclass} = $2; + $res_to_val{doFPS} = 'false'; + print STDERR "$progname: $file: progclass = $2\n" if ($verbose > 2); + + print STDERR "$progname: $file: switches to resources:\n" + if ($verbose > 2); + my %switch_to_res; + $switch_to_res{-fps} = 'doFPS: true'; + $switch_to_res{-fg} = 'foreground: %'; + $switch_to_res{-bg} = 'background: %'; + + my ($ign, $opts) = ($body =~ m/(_options|\bopts)\s*\[\]\s*=\s*{(.*?)}\s*;/s); + if ($xlockmore_p || $thread_p || $analogtv_p || $opts) { + $opts = '' unless $opts; + $opts .= ",\n$xlockmore_default_opts" if ($xlockmore_p); + $opts .= ",\n$thread_default_opts" if ($thread_p); + $opts .= ",\n$analogtv_default_opts" if ($analogtv_p); + + foreach (split (/,\s*\n/, $opts)) { + s/^\s*//s; + s/\s*$//s; + next if m/^$/s; + next if m/^{\s*0\s*,/s; + my ($switch, $res, $type, $v0, $v1, $v2) = + m@^ \s* { \s * \"([^\"]+)\" \s* , + \s * \"([^\"]+)\" \s* , + \s * ([^\s]+) \s* , + \s * (\"([^\"]*)\"|([a-zA-Z\d_]+)) \s* }@xi; + print STDERR "$progname: $file: unparsable: $_\n" unless $switch; + my $val = defined($v1) ? $v1 : $v2; + $val = '%' if ($type eq 'XrmoptionSepArg'); + $res =~ s/^[.*]//s; + $res =~ s/^[a-z\d]+\.//si; + $switch =~ s/^\+/-no-/s; + + $val = "$res: $val"; + if (defined ($switch_to_res{$switch})) { + print STDERR "$progname: $file: DUP! $switch = \"$val\"\n" + if ($verbose > 2); + } else { + $switch_to_res{$switch} = $val; + print STDERR "$progname: $file: $switch = \"$val\"\n" + if ($verbose > 2); + } + } + } else { + error ("$file: no options"); + } + + return (\%res_to_val, \%switch_to_res); +} + +# Returns a list of: +# "resource = default value" +# or "resource != non-default value" +# +sub parse_manifest_xml($$) { + my @result = (); + my ($saver, $switch_to_res) = @_; + my $file = "project/xscreensaver/AndroidManifest.xml"; + my $body = ''; + local *IN; + + if (-e $file) { + open (IN, "<$file") || error ("$file: $!"); + } + else { + return @result; + } + + while () { $body .= $_; } + close IN; + $file =~ s@^.*/@@; + + $body =~ s// /gsi; + + $body =~ s/\s+/ /gs; + $body =~ s/ 2); + + foreach (split (m/\001/, $body)) { + next if (m/^\s*$/s); + my ($type, $args) = m@^<([?/]?[-_a-z]+)\b\s*(.*)$@si; + error ("$progname: $file: unparsable: $_") unless $type; + next if ($type =~ m@^/@); + if ($type eq 'meta-data') { + my ($value) = ($args =~ m/\@xml\/([^\"]+)\"/); + push @result, $value; + } + } + return @result; +} + +# Returns a list of: +# "resource = default value" +# or "resource != non-default value" +# +sub parse_strings_xml($$) { + my @result = (); + my ($saver, $switch_to_res) = @_; + my $file = "project/xscreensaver/res/values/strings.xml"; + my $body = ''; + local *IN; + + if (-e $file) { + open (IN, "<$file") || error ("$file: $!"); + } + else { + return @result; + } + + while () { $body .= $_; } + close IN; + $file =~ s@^.*/@@; + + $body =~ s// /gsi; + + $body =~ s/\s+/ /gs; + $body =~ s/ 2); + + my $saver_name = $saver . "_name"; + + foreach (split (m/\001/, $body)) { + next if (m/^\s*$/s); + my ($type, $args) = m@^<([?/]?[-_a-z]+)\b\s*(.*)$@si; + error ("$progname: $file: unparsable: $_") unless $type; + next if ($type =~ m@^/@); + + if ($type =~ m/^([hv]group|\?xml|resources|xscreensaver-(image|text|updater))/s) { + + } elsif ($type eq 'string') { + my ($name) = ($args =~ m/\bname\s*=\s*\"([^\"]+)\"/); + my ($value) = ($args =~ m/>([^\"]+)/); + my ($val) = "$name = $value"; + if ($saver_name eq $name) { + error ("$saver: $saver already in $file"); + } + push @result, $val; + } elsif ($type eq 'item') { + # ignore + } else { + error ("$file: unknown type \"$type\" for no arg"); + } + } + + return @result; +} + + + +# Returns a list of: +# "resource = default value" +# or "resource != non-default value" +# +sub parse_xml($$) { + my ($saver, $switch_to_res) = @_; + my $file = "../hacks/config/" . lc($saver) . ".xml"; + my $body = ''; + local *IN; + open (IN, "<$file") || error ("$file: $!"); + while () { $body .= $_; } + close IN; + $file =~ s@^.*/@@; + + my @result = (); + + $body =~ s// /gsi; + + $body =~ s/\s+/ /gs; + $body =~ s/ 2); + foreach (split (m/\001/, $body)) { + next if (m/^\s*$/s); + my ($type, $args) = m@^<([?/]?[-_a-z]+)\b\s*(.*)$@si; + + my $type_val; + error ("$progname: $file: unparsable: $_") unless $type; + next if ($type =~ m@^/@); + + if ($type =~ m/^([hv]group|\?xml|command|string|file|_description|xscreensaver-(image|text|updater))/s) { + + } elsif ($type eq 'screensaver') { + my ($name) = ($args =~ m/\b_label\s*=\s*\"([^\"]+)\"/); + my $val = "progclass = $name"; + push @result, $val; + print STDERR "$progname: $file: name: $name\n" if ($verbose > 2); + + } elsif ($type eq 'video') { + error ("$file: multiple videos") if $video; + ($video) = ($args =~ m/\bhref="(.*?)"/); + error ("$file: unparsable video") unless $video; + error ("$file: unparsable video URL") + unless ($video =~ m@^https?://www\.youtube\.com/watch\?v=[^?&]+$@s); + + } elsif ($type eq 'number') { + my ($arg) = ($args =~ m/\barg\s*=\s*\"([^\"]+)\"/); + my ($val) = ($args =~ m/\bdefault\s*=\s*\"([^\"]+)\"/); + $val = '' unless defined($val); + + my ($low) = ($args =~ m/\blow\s*=\s*\"([^\"]+)\"/); + my ($high) = ($args =~ m/\bhigh\s*=\s*\"([^\"]+)\"/); + + my ($ll) = ($args =~ m/\b_low-label\s*=\s*\"([^\"]+)\"/); + my ($hl) = ($args =~ m/\b_high-label\s*=\s*\"([^\"]+)\"/); + + my $switch = $arg; + $switch =~ s/\s+.*$//; + my ($res) = $switch_to_res->{$switch}; + error ("$file: no resource for $type switch \"$arg\"") unless $res; + $res =~ s/: \%$//; + error ("$file: unparsable value: $res") if ($res =~ m/:/); + + $type_val = "$res" . "_type = $type"; + push @result, $type_val; + $val = "$res = $val"; + push @result, $val; + $val = "$res" . "_low = $low"; + push @result, $val; + $val = "$res" . "_high = $high"; + push @result, $val; + $val = "$res" . "_low-label = $ll"; + push @result, $val; + $val = "$res" . "_high-label = $hl"; + push @result, $val; + + print STDERR "$progname: $file: number: $val\n" if ($verbose > 2); + + } elsif ($type eq 'boolean') { + my ($set) = ($args =~ m/\barg-set\s*=\s*\"([^\"]+)\"/); + my ($unset) = ($args =~ m/\barg-unset\s*=\s*\"([^\"]+)\"/); + my ($arg) = $set || $unset || error ("$file: unparsable: $args"); + my ($res) = $switch_to_res->{$arg}; + error ("$file: no resource for boolean switch \"$arg\"") unless $res; + my ($res2, $val) = ($res =~ m/^(.*?): (.*)$/s); + error ("$file: unparsable boolean resource: $res") unless $res2; + $res = $res2; + $type_val = "$res" . "_type = $type"; + push @result, $type_val; +# $val = ($set ? "$res != $val" : "$res = $val"); + $val = "$res != $val"; + push @result, $val; + + print STDERR "$progname: $file: boolean: $val\n" if ($verbose > 2); + + } elsif ($type eq 'select') { + $args =~ s/{$set}; + error ("$file: no resource for select switch \"$set\"") unless $res; + + my ($res2, $val2) = ($res =~ m/^(.*?): (.*)$/s); + error ("$file: unparsable select resource: $res") unless $res2; + $res = $res2; + $type_val = "$res" . "_type = $type"; + push @result, $type_val; + $val = $val2 unless ($val2 eq '%'); + + error ("$file: mismatched resources: $res vs $this_res") + if (defined($this_res) && $this_res ne $res); + $this_res = $res; + + $val = "$res != $val"; + push @result, $val; + $val = "$res" . "_type = $type"; + push @result, $val; + + print STDERR "$progname: $file: select: $val\n" if ($verbose > 2); + + } else { + error ("$file: multiple default options: $set") if ($unset_p); + $unset_p++; + } + } + + } else { + error ("$file: unknown type \"$type\" for no arg"); + } + } + +# error ("$file: no video") unless $video; + print STDERR "\n$file: WARNING: no video\n\n" unless $video; + + return @result; +} + + +sub parse_then_make($) { + my ($saver) = @_; + + # kludge + return 0 if ($saver =~ m/(-helper)$/); + + my ($src_opts, $switchmap) = parse_src ($saver); + my (@xml_opts) = parse_xml ($saver, $switchmap); + + # tests if hack is supported yet + my (@test) = get_keys_and_values($saver, @xml_opts); + my (@strings_xml_opts) = parse_strings_xml ($saver, $switchmap); + my (%pixkeys) = parse_items_xml($saver); + my (@manifest_xml_opts) = parse_manifest_xml ($saver, $switchmap); + my (@glue_hacks) = parse_glue($saver); + my (@settings_xml_opts) = parse_settings_xml($saver); + + my (@all_settings) = get_settings($saver, $switchmap, \@xml_opts); + + make_settings($saver); + make_service($saver); + make_wallpaper($saver, @xml_opts); + + make_manifest($saver, @manifest_xml_opts); + + make_hack_xml($saver); + make_hack_settings_xml($saver, @xml_opts); + make_strings_xml($saver, \@xml_opts, \@strings_xml_opts); + make_items_xml($saver, \@xml_opts, \%pixkeys); + make_settings_xml($saver, \@all_settings, \@settings_xml_opts); + + make_glue($saver, @glue_hacks); + + return 0; +} + + +sub make_manifest($$) { + my ($saver, @manifest_opts) = @_; + push @manifest_opts, $saver unless grep{$_ eq $saver} @manifest_opts; + my $hack = ucfirst($saver); + my $file = "project/xscreensaver/AndroidManifest.xml"; + open (my $in, '>', $file) || error ("$file: $!"); + + my $body = ("\n" . + "\n" . + "\n" . + "\n\n"); + + foreach my $save (@manifest_opts) { + my $hac = ucfirst($save); + $body = $body . ("\n" . + " \n" . + " \n" . + " \n" . + " \n" . + "\n" . + "\n" . + "\n\n"); + + } + + $body = $body . ("\n\n" . + "\n" . + "\n" . + "\n"); + + print $in $body; + close $in; +} + + +sub make_hack_settings_xml($$) { + + my ($saver, @xml_opts) = @_; + my $hack = ucfirst($saver); + my $file = "project/xscreensaver/res/xml/" . $saver . "_settings.xml"; + my (%saver_keys) = get_keys_and_values($saver, @xml_opts); + + open (my $in, '>', $file) || error ("$file: $!"); + + my $body = ("\n" . + "\n" . + " \n"); + + my @keyarray = keys %saver_keys; + + + foreach my $sgkey (@keyarray) { + + my $type = get_type($sgkey, @xml_opts); + + + if ($type eq "number") { + $body = $body . " \n"; + } else { + $body = $body . " \n"; + } + } + + $body = $body . " \n" . + "\n"; + + print $in $body; + close $in; +} + + +sub make_items_xml($\@\%) { + my $saver = $_[0]; + my @xml_opts = @{$_[1]}; + my %pixkeys = %{$_[2]}; + + my $file = "project/xscreensaver/res/values/items.xml"; + + my $body = ("\n" . + "\n"); + + while(my($key, $value) = each %pixkeys) { + $body = $body . " ". $value . "\n"; + + } + + my (%saver_keys) = get_keys_and_values($saver, @xml_opts); + my @keyarray = keys %saver_keys; + + foreach my $item_key (@keyarray) { + + my $type = get_type($item_key, @xml_opts); + + if ($type eq "number") { + + my ($low, $high, $default) = get_low_high_def($item_key, @xml_opts); + my $float = ($default - $low) / ($high - $low); + + $body = ($body . + " $float\n"); + } + } + + $body = ($body . + "\n"); + open (my $in, '>', $file) || error ("$file: $!"); + print $in $body; + close $in; +} + + +sub get_type($@) { + + my($type_key, @xml_opts) = @_; + my $type=''; + + foreach my $claim (@xml_opts) { + + my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); + if ($res eq $type_key . "_type") { + $type = $xval; + } + + } + return $type; + +} + + +sub get_low_high_def($@) { + + my($sgkey, @xml_opts) = @_; + + my $low; + my $high; + my $default; + + foreach my $claim (@xml_opts) { + my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); + if ($res eq $sgkey . "_low") { + $low = $xval; + } + elsif ($res eq $sgkey . "_high") { + $high = $xval; + } + elsif ($res eq $sgkey) { + $default = $xval; + } + } + + return ($low, $high, $default); + +} + + +sub make_settings_xml($\@\@) { + + my $saver = $_[0]; + my @xml_opts = @{$_[1]}; + my @old_settings_xml = @{$_[2]}; + my $file = "project/xscreensaver/res/values/settings.xml"; + + my $body = ("\n" . + "\n"); + + my $arrays_from_old_settings = old_settings_string_arrays(@old_settings_xml); + + $body = $body . $arrays_from_old_settings; + + my (%saver_keys) = get_keys_and_values($saver, @xml_opts); + my @key_array = keys %saver_keys; + + my ($low, $high, $low_label, $high_label, $type); + my @selects; + + # for each setting of the hack which we chose to add + foreach my $selected_setting_key (@key_array) { + # see what values were in the relevant xml in hacks/config for this hack + foreach my $claim (@xml_opts) { + my ($xres, $xcompare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); + if ($xres =~ /^$selected_setting_key/) { + my $one, my $two; + if ($xres =~ /_/ ) { + ($one, $two) = ($xres =~ m/^(.*)_(.*)$/s); + if ($two eq "type") { + $type = $xval; + } elsif ($two eq "low-label") { + $low_label = $xval; + } elsif ($two eq "high-label") { + $high_label = $xval; + } elsif ($two eq "low") { + $low = $xval; + } elsif ($two eq "high") { + $high = $xval; + } + } else { + $one = $xres; + if ($type eq "select") { + push @selects, $xval; + } + } + } + } + + # add setting values based on the setting type (boolean, number, select) + if ($type eq "boolean") { + $body = $body . " \n" . + " \"True\"\n" . + " \"False\"\n" . + " \n" . + " \n" . + " \@string/t\n" . + " \@string/f\n" . + " \n"; + } elsif ($type eq "number") { + $body = $body . " \n" . + " \"" . $low_label . "\"\n" . + " \"" . $high_label . "\"\n" . + " \n" . + " \n" . + " \"" . $low . "\"\n" . + " \"" . $high . "\"\n" . + " \n"; + } elsif ($type eq "select") { + $body = $body . " \n"; + + foreach my $item (@selects) { + $body = $body . " \"" . $item . "\"\n" ; + } + + $body = $body . " \n" . + " \n"; + + foreach my $item (@selects) { + $body = $body . " \"" . $item . "\"\n" ; + } + + $body = $body . " \n"; + } + + @selects=(); + } + + $body = ($body . + "\n"); + + open (my $in, '>', $file) || error ("$file: $!"); + print $in $body; + close $in; + +} + + +sub old_settings_string_arrays(@) { + + my (@old_settings_file) = @_; + + my $body = ''; + my $current_string_array=''; + + + foreach my $claim (@old_settings_file) { + my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=) (.*)$/s); + error ("unparsable xml claim: $_") unless $compare; + + if ($current_string_array ne $res) { + if (length($current_string_array) > 0) { + $body = $body . " \n"; + } + + $current_string_array = $res; + $body = $body . " \n"; + } + + $body = $body . " " . $xval . "\n"; + } + + if ($#old_settings_file > -1) { + $body = $body . " \n"; + } + + + return $body; + +} + + +# TODO: This adds the proper parameters to settings such as hilbert's, but it +# does not remove the improper parameters from hacks such as Hilbert yet. +# +sub get_settings($$\@) { + my $saver = $_[0]; + my $switchmap = $_[1]; + my @xml_opts = @{$_[2]}; + + my @keys = keys % { $switchmap}; + + my $res_seen = 0; + my $val_seen = 0; + my @also; + foreach my $sgkey (@keys) { + my ($k, $v) = ($switchmap->{$sgkey} =~ m/^(.*): (.*)$/); + + if ($v ne '%') { + foreach my $claim (@xml_opts) { + my ($res, $compare, $val) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); + if ($res eq $k && $val eq $v) { + $val_seen = $val_seen + 1; + } + elsif ($res eq $k) { + $res_seen = $res_seen + 1; + } + } + + if ($val_seen eq 0 && $res_seen > 0) { + my $so = "$k != $v"; + push @also, $so; + } + + $val_seen = 0; + $res_seen = 0; + } + } + + my @all = (@xml_opts, @also); + return @all; + +} + + +sub make_strings_xml($\@\@) { + + my $saver = $_[0]; + my @xml_opts = @{$_[1]}; + my @strings_xml_opts = @{$_[2]}; + + my $saver_name = $saver . "_name"; + my $hack = ucfirst($saver); + my $file = "project/xscreensaver/res/values/strings.xml"; + my (%saver_keys) = get_keys_and_values($saver, @xml_opts); + + my $body = ("\n" . + "\n" . + " Hello World!\n" . + " Xscreensaver\n" . + " A live wallpaper\n\n" . + " Xscreensaver\n" . + " jwz and helpers\n" . + " True\n" . + " False\n"); + + foreach my $claim (@strings_xml_opts) { + my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); + error ("$saver: unparsable xml claim: $_") unless $compare; + if ($res eq 'hello' || + $res eq 'service_label' || + $res eq 'description' || + $res eq 'app_name' || + $res eq 'author' || + $res eq 't' || + $res eq 'f') { + } + elsif ($res eq $saver_name) { + error ("$saver: $saver already in $file"); + } + else { + $body = ($body . + " " . $xval . "\n"); + } + } + + $body = ($body . + " " . $hack . + "\n" . + " Settings\n" . + " " . $hack . + + "\n"); + + my @keyarray = keys %saver_keys; + + foreach my $sgkey (@keyarray) { + + my $type = get_type($sgkey, @xml_opts); + + if ($type eq "number") { + + my ($low, $high, $default) = get_low_high_def($sgkey, @xml_opts); + my $float = ($default - $low) / ($high - $low); + + $body = ($body . " " . "Set " . $sgkey . "\n" . + " " . "Choose " . $sgkey . "\n" . + " " . $low . "\n" . + " " . $high . "\n" . + " " . $saver_keys{$sgkey} . "\n"); + } + else { + + $body = ($body . " " . "Set " . $sgkey . "\n" . + " " . "Choose " . $sgkey . "\n" . + " " . $saver_keys{$sgkey} . "\n"); + } + } + + $body = ($body . + "\n"); + + open (my $in, '>', $file) || error ("$file: $!"); + print $in $body; + close $in; +} + + +sub make_hack_xml($) { + my ($saver) = @_; + my $hack = ucfirst($saver); + + my $dir = "project/xscreensaver/res/xml/"; + my $file = $dir . $saver . ".xml"; + my $in; + + if (-d $dir) { + open ($in, '>', $file) || error ("$file: $!"); + } + else { + mkdir $dir; + open ($in, '>', $file) || error ("$file: $!"); + } + + my $body = ("\n" . + "\n"); + + print $in $body; + close $in; +} + + +sub make_glue($$) { + my ($saver, @glue_hacks) = @_; + my (@hacks) = @glue_hacks; + + push @hacks, $saver; + + my $dir = "gen/"; + my $file = $dir . "glue.c"; + my $in; + + if (-d $dir) { + open ($in, '>', $file) || error ("$file: $!"); + } + else { + mkdir $dir; + open ($in, '>', $file) || error ("$file: $!"); + } + + + my $body = ("#include \n" . + "#include \n" . + "#include \n" . + "#include \n" . + "#include \n" . + "#include \n" . + "#include \n\n" . + "#include \"screenhackI.h\"\n" . + "#include \"jwzglesI.h\"\n" . + "#include \"version.h\"\n\n" . + "void drawXscreensaver();\n\n" . + "int sWindowWidth = 0;\n" . + "int sWindowHeight = 0;\n" . + "int initTried = 0;\n" . + "int renderTried = 0;\n" . + "int resetTried = 0;\n" . + "int currentFlip = 0;\n\n" . + "pthread_mutex_t mutg = PTHREAD_MUTEX_INITIALIZER;\n\n" . + "extern struct xscreensaver_function_table " . + "*xscreensaver_function_table;\n\n" . + "// if adding a table here, increase the magic number\n" . + "struct xscreensaver_function_table\n"); + + for my $i (0 .. $#hacks) { + $body = $body . " *" . $hacks[$i] ; + $body = $body . "_xscreensaver_function_table"; + if ($i eq $#hacks ) { + $body = $body . ";\n\n"; + } + else { + $body = $body . ",\n"; + } + } + + $body = $body . "struct running_hack {\n" . + " struct xscreensaver_function_table *xsft;\n" . + " Display *dpy;\n" . + " Window window;\n" . + " void *closure;\n" . + "};\n\n" . + "const char *progname;\n" . + "const char *progclass;\n\n" . + "struct running_hack rh["; + $body = $body . scalar(@hacks); + $body = $body . "];\n" . + "// ^ magic number of hacks - TODO: remove magic number\n\n\n" . + "int chosen;\n" . + "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_CallNative_nativeInit\n" . + " (JNIEnv * env);\n" . + "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_CallNative_nativeResize\n" . + " (JNIEnv * env, jobject thiz, jint w, jint h);\n" . + "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_CallNative_nativeRender\n" . + " (JNIEnv * env);\n" . + "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_CallNative_nativeDone\n" . + " (JNIEnv * env);\n"; + + foreach my $bighack (@hacks) { + my $bh = ucfirst($bighack); + $body = $body . "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_gen_" . $bh . + "Wallpaper_allnativeSettings\n" . + " (JNIEnv * env, jobject thiz, jstring jhack," . + " jstring hackPref,\n" . + " jint draw, jstring key);\n"; + + } + + $body = $body . "\n\n\nvoid doinit()\n{\n\n" ; + + for my $j (0 .. $#hacks) { + if ($j == 0) { + $body = $body . " if (chosen == " . $j . ") {\n" ; + } elsif ($j == $#hacks) { + $body = $body . " } else {\n" ; + } else { + $body = $body . " } else if (chosen == " . $j . ") {\n"; + } + $body = $body . " progname = \"" . $hacks[$j] . "\";\n" . + " rh[chosen].xsft = &" . $hacks[$j] . + "_xscreensaver_function_table;\n" ; + } + + $body = $body . " }\n\n" ; + $body = $body . " rh[chosen].dpy = jwxyz_make_display(0, 0);\n" . + " rh[chosen].window = XRootWindow(rh[chosen].dpy, 0);\n" . + "// TODO: Zero looks right, " . + "but double-check that is the right number\n\n" . + " progclass = rh[chosen].xsft->progclass;\n\n" . + " if (rh[chosen].xsft->setup_cb)\n" . + " rh[chosen].xsft->setup_cb(rh[chosen].xsft,\n" . + " rh[chosen].xsft->setup_arg);\n\n" . + " if (resetTried < 1) {\n" . + " resetTried++;\n" . + " jwzgles_reset();\n" . + " }\n\n" . + " void *(*init_cb) (Display *, Window, void *) =\n" . + " (void *(*)(Display *, Window, void *)) " . + "rh[chosen].xsft->init_cb;\n\n" . + " rh[chosen].closure =\n" . + " init_cb(rh[chosen].dpy, rh[chosen].window,\n" . + " rh[chosen].xsft->setup_arg);\n\n}\n\n\n" . + "void drawXscreensaver()\n{\n" . + " pthread_mutex_lock(&mutg);\n" . + " rh[chosen].xsft->draw_cb(rh[chosen].dpy, " . + "rh[chosen].window,\n" . + " rh[chosen].closure);\n" . + " pthread_mutex_unlock(&mutg);\n\n}\n\n\n" . + "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_CallNative_nativeInit\n" . + " (JNIEnv * env) {\n\n" . + " if (initTried < 1) {\n" . + " initTried++;\n" . + " } else {\n" . + " if (!rh[chosen].dpy) {\n" . + " doinit();\n" . + " } else {\n" . + " rh[chosen].xsft->free_cb(rh[chosen].dpy, " . + "rh[chosen].window,\n" . + " rh[chosen].closure);\n" . + " jwxyz_free_display(rh[chosen].dpy);\n" . + " rh[chosen].dpy = NULL;\n" . + " rh[chosen].window = NULL;\n" . + " if (!rh[chosen].dpy) {\n" . + " doinit();\n" . + " }\n\n }\n" . + " }\n\n}\n\n\n" . + "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_CallNative_nativeResize\n" . + " (JNIEnv * env, jobject thiz, jint w, jint h) {\n\n" . + " sWindowWidth = w;\n" . + " sWindowHeight = h;\n\n" . + " if (!rh[chosen].dpy) {\n" . + " doinit();\n" . + " }\n\n" . + " jwxyz_window_resized(rh[chosen].dpy, " . + "rh[chosen].window, 0, 0, w, h, 0);\n\n" . + " rh[chosen].xsft->reshape_cb(rh[chosen].dpy, " . + "rh[chosen].window,\n" . + " rh[chosen].closure, w, h);\n}\n\n" . + "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_CallNative_nativeRender\n" . + " (JNIEnv * env) {\n" . + " if (renderTried < 1) {\n" . + " renderTried++;\n" . + " } else {\n" . + " drawXscreensaver();\n" . + " }\n}\n\n" . + "// TODO: Check Java side is calling this properly\n" . + "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_CallNative_nativeDone\n" . + " (JNIEnv * env) {\n\n" . + " rh[chosen].xsft->free_cb(rh[chosen].dpy, " . + "rh[chosen].window,\n" . + " rh[chosen].closure);\n" . + " jwxyz_free_display(rh[chosen].dpy);\n" . + " rh[chosen].dpy = NULL;\n" . + " rh[chosen].window = NULL;\n\n}\n\n" ; + + for my $j (0 .. $#hacks) { + my $jhack = ucfirst($hacks[$j]); + + $body = $body . "JNIEXPORT void JNICALL\n" . + " Java_org_jwz_xscreensaver_gen_" . $jhack . + "Wallpaper_allnativeSettings\n" . + " (JNIEnv * env, jobject thiz, jstring jhack," . + " jstring hackPref,\n" . + " jint draw, jstring key) {\n\n" . + " const char *chack = " . + "(*env)->GetStringUTFChars(env, hackPref, NULL);\n" . + " char *hck = (char *) chack;\n" . + " const char *kchack = " . + "(*env)->GetStringUTFChars(env, key, NULL);\n" . + " char *khck = (char *) kchack;\n\n" . + " if (draw == 2) {\n" . + " set" . $jhack . "Settings(hck, khck);\n" . + " }\n\n" . + " chosen = " . $j . ";\n}\n\n"; + + } + + + print $in $body; + close $in; +} + +sub make_wallpaper($$) { + my ($saver, @xml_opts) = @_; + my $hack = ucfirst($saver); + my $file = "project/xscreensaver/src/org/jwz/xscreensaver/gen/"; + $file = $file . $hack . "Wallpaper.java"; + my (%saver_keys) = get_keys_and_values($saver, @xml_opts); + + open (my $in, '>', $file) || error ("$file: $!"); + + my $body = ("package org.jwz.xscreensaver.gen;\n" . + "import javax.microedition.khronos.egl.EGLConfig;\n" . + "import javax.microedition.khronos.opengles.GL10;\n" . + "import net.rbgrn.android.glwallpaperservice.*;\n" . + "import android.opengl.GLU;\n" . + "import android.content.Context;\n" . + "import android.content.SharedPreferences;\n" . + "import org.jwz.xscreensaver.*;\n" . + "public class " . $hack . + "Wallpaper extends ARenderer {\n" . + " private static native void allnativeSettings(" . + "String hack, String hackPref, int draw, String key);\n" . + " public static final String SHARED_PREFS_NAME=\"" . $saver . + "settings\";\n" . + " CallNative cn;\n" . + " public void onSurfaceCreated(" . + "GL10 gl, EGLConfig config) {\n" . + " super.onSurfaceCreated(gl, config);\n" . + " cn = new CallNative();\n" . + " NonSurfaceCreated();\n" . + " }\n" . + " public void onDrawFrame(GL10 gl) {\n" . + " super.onDrawFrame(gl);\n" . + " allnativeSettings(\"bogus\", \"bogus\", 1, \"bogus\");\n" . + " NonDrawFrame();\n" . + " }\n" . + " void NonDrawFrame() {\n" . + " cn.nativeRender();\n" . + " }\n" . + " void doSP(SharedPreferences sspp) {\n" . + + + " String hack = \"" . $saver . "\";\n"); + + my @keyarray = keys %saver_keys; + foreach my $sgkey (@keyarray) { + + my $type = get_type($sgkey, @xml_opts); + + if ($type eq "number") { + + my ($low, $high, $default) = get_low_high_def($sgkey, @xml_opts); + my $float = ($default - $low) / ($high - $low); + + $body = $body . + " String " . $sgkey . + "_low = sspp.getString(\"" . $saver . + "_" . $sgkey . "_low\", \"". $low . "\");\n" . + " String " . $sgkey . + "_high = sspp.getString(\"" . $saver . + "_" . $sgkey . "_high\", \"" . $high . "\");\n" . + " Float " . $sgkey . "PrefF = sspp.getFloat(\"" . $saver . + "_" . $sgkey . "\", " . $float . "f);\n" . + " String " . $sgkey . "Pref = getNumber(" . $sgkey . + "_low, " . $sgkey . "_high, " . $sgkey . "PrefF);\n" . + " allnativeSettings(hack, " . $sgkey . + "Pref, 2, \"" . $saver . "_" . $sgkey . "\");\n"; + } + elsif ($type eq "boolean") { + + $body = $body . " String " . $sgkey . + "Pref = sspp.getString(\"" . $saver . "_" . $sgkey . + "\", \"" . $saver_keys{$sgkey} . "\");\n" . + " allnativeSettings(hack, " . $sgkey . + "Pref, 2, \"" . $saver . "_" . $sgkey . "\");\n"; + + } + elsif ($type eq "select") { + + $body = $body . " String " . $sgkey . + "Pref = sspp.getString(\"" . $saver . "_" . $sgkey . + "\", \"" . $saver_keys{$sgkey} . "\");\n" . + " allnativeSettings(hack, " . $sgkey . + "Pref, 2, \"" . $saver . "_" . $sgkey . "\");\n"; + + } + else { + print STDERR "$progname: type $type not yet implemented \n"; + } + + } + + $body = $body . " }\n" . + " String getNumber(String low, String high, Float pref) {\n" . + " Float lowF = Float.parseFloat(low);\n" . + " Float lowH = Float.parseFloat(high);\n" . + " Float diff = lowH - lowF;\n" . + " Float mult = pref * diff;\n" . + " Float add = mult + lowF;\n" . + " int i;\n" . + " String s;\n" . + " if (diff > 2.0) {\n" . + " i = (Integer) Math.round(add);\n" . + " s = Integer.toString(i);\n}\n" . + " else {\n" . + " s = Float.toString(add);\n}\n" . + " return s;\n" . + " }\n\n" . + " static\n" . + " {\n" . + " System.loadLibrary (\"xscreensaver\");\n" . + " }\n" . + "}\n"; + + print $in $body; + close $in; + +} + +sub get_keys_and_values($$) { + + my ($saver, @xml_opts) = @_; + my (%saver_keys) ; + + foreach my $claim (@xml_opts) { + my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); + error ("$saver: unparsable xml claim: $_") unless $compare; + + if ($saver eq "sproingies") { + if ($res eq "count") { + $saver_keys{$res} = $xval; + } + elsif ($res eq "wireframe") { + #$saver_keys{$res} = $xval; + $saver_keys{$res} = "False"; + } + + } + elsif ($saver eq "hilbert") { + if ($res eq "mode") { + $saver_keys{$res} = $xval; + } + } + elsif ($saver eq "stonerview") { + if ($res eq "transparent") { + #$saver_keys{$res} = $xval; + $saver_keys{$res} = "False"; + } + } + elsif ($saver eq "superquadrics") { + # spinspeed/speed. float/int + if ($res eq "spinspeed") { + $saver_keys{$res} = $xval; + } + } + elsif ($saver eq "bouncingcow") { + if ($res eq "count") { + $saver_keys{$res} = "3"; + } + elsif ($res eq "speed") { + $saver_keys{$res} = "0.1"; + } + } + elsif ($saver eq "unknownpleasures") { + if ($res eq "wireframe") { + $saver_keys{$res} = "True"; + } + elsif ($res eq "speed") { + $saver_keys{$res} = "3.0"; + } + #elsif ($res eq "count") { + # $saver_keys{$res} = $xval; + #} + #elsif ($res eq "resolution") { + # $saver_keys{$res} = $xval; + #} + #elsif ($res eq "ortho") { + # $saver_keys{$res} = $xval; + #} + + } + elsif ($saver eq "hypertorus") { + if ($res =~ /^(displayMode|appearance|colors|projection3d|projection4d|speedwx|speedwy|speedwz|speedxy|speedxz|speedyz)$/) { + $saver_keys{$res} = $xval; + } + } + elsif ($saver eq "glhanoi") { + if ($res =~ /^(light|fog|trails|poles|speed)$/) { + # TODO: check in xval for true/false should be higher up in logic + if ($xval =~ /^(true|false)$/) { + $saver_keys{$res} = ucfirst($xval); + } + else { + $saver_keys{$res} = $xval; + } + } + } + else { + error ("$saver: not yet supported for Android"); + } + + } + + return (%saver_keys); +} + + +sub make_service($) { + my ($saver) = @_; + my $hack = ucfirst($saver); + my $file = "project/xscreensaver/src/org/jwz/xscreensaver/gen/"; + $file = $file . $hack . "Service.java"; + open (my $in, '>', $file) || error ("$file: $!"); + + my $body = ("package org.jwz.xscreensaver.gen;\n\n" . + "import net.rbgrn.android.glwallpaperservice.*;\n" . + "import android.content.SharedPreferences;\n" . + "import org.jwz.xscreensaver.*;\n\n" . + "// Original code provided by Robert Green\n" . + "// http://www.rbgrn.net/content/354-glsurfaceview-adapted-3d-live-wallpapers\n" . + "public class " . $hack . + "Service extends GLWallpaperService {\n\n" . + " SharedPreferences sp;\n\n" . + " public " . $hack . + "Service() {\n" . + " super();\n" . + " }\n\n" . + " \@Override\n" . + " public void onCreate() {\n" . + " sp = ((XscreensaverApp)getApplication())." . + "getThePrefs($hack" . "Wallpaper.SHARED_PREFS_NAME);\n" . + " }\n\n" . + " public Engine onCreateEngine() {\n" . + " MyEngine engine = new MyEngine();\n" . + " return engine;\n" . + " }\n\n" . + " class MyEngine extends GLEngine {\n" . + " " . $hack . + "Wallpaper renderer;\n" . + " public MyEngine() {\n" . + " super();\n" . + " // handle prefs, other initialization\n" . + " renderer = new " . $hack . + "Wallpaper();\n" . + " setEGLConfigChooser(8, 8, 8, 8, 16, 0);\n" . + " setRenderer(renderer);\n" . + " setRenderMode(RENDERMODE_CONTINUOUSLY);\n" . + " }\n\n" . + " public void onDestroy() {\n" . + " super.onDestroy();\n" . + " if (renderer != null) {\n" . + " renderer.release(); " . + "// assuming yours has this method - it should!\n" . + " }\n" . + " renderer = null;\n" . + " }\n\n" . + " \@Override\n" . + " public void onVisibilityChanged(boolean visible) {\n" . + " super.onVisibilityChanged(visible);\n" . + " if (visible) {\n" . + " renderer.doSP(sp);\n" . + " }\n" . + " }\n\n" . + " }\n" . + " static\n" . + " {\n" . + " System.loadLibrary (\"xscreensaver\");\n" . + " }\n\n\n" . + "}\n"); + + print $in $body; + close $in; + +} + +sub make_settings($) { + my ($saver) = @_; + my $hack = ucfirst($saver); + my $dir = "project/xscreensaver/src/org/jwz/xscreensaver/gen/"; + my $file = $dir . $hack . "Settings.java"; + my $in; + + if (-d $dir) { + open ($in, '>', $file) || error ("$file: $!"); + } + else { + mkdir $dir; + open ($in, '>', $file) || error ("$file: $!"); + } + + my $body = ("/*\n" . + " * Copyright (C) 2009 Google Inc.\n" . + " *\n" . + " * Licensed under the Apache License, Version 2.0 " . + "(the \"License\"); you may not\n" . + " * use this file except in compliance with the License. " . + "You may obtain a copy of\n" . + " * the License at\n" . + " *\n" . + " * http://www.apache.org/licenses/LICENSE-2.0\n" . + " *\n" . + " * Unless required by applicable law or agreed to in writing," . + " software\n" . + " * distributed under the License is distributed" . + " on an \"AS IS\" BASIS, WITHOUT\n" . + " * WARRANTIES OR CONDITIONS OF ANY KIND," . + " either express or implied. See the\n" . + " * License for the specific language governing" . + "permissions and limitations under\n" . + " * the License.\n" . + " */\n\n" . + "package org.jwz.xscreensaver.gen;\n\n" . + "import org.jwz.xscreensaver.R;\n\n" . + "import android.content.SharedPreferences;\n" . + "import android.os.Bundle;\n" . + "import android.preference.PreferenceActivity;\n\n" . + "public class " . $hack . + "Settings extends PreferenceActivity\n" . + " implements " . + "SharedPreferences.OnSharedPreferenceChangeListener {\n\n" . + " \@Override\n" . + " protected void onCreate(Bundle icicle) {\n" . + " super.onCreate(icicle);\n" . + " getPreferenceManager().setSharedPreferencesName(\n" . + " " . $hack . + "Wallpaper.SHARED_PREFS_NAME);\n" . + " addPreferencesFromResource(R.xml." . $saver . + "_settings);\n" . + " getPreferenceManager().getSharedPreferences()." . + "registerOnSharedPreferenceChangeListener(\n" . + " this);\n" . + " }\n\n" . + " \@Override\n" . + " protected void onResume() {\n" . + " super.onResume();\n" . + " }\n\n" . + " \@Override\n" . + " protected void onDestroy() {\n" . + " getPreferenceManager().getSharedPreferences()." . + "unregisterOnSharedPreferenceChangeListener(\n" . + " this);\n" . + " super.onDestroy();\n" . + " }\n\n" . + " public void onSharedPreferenceChanged(" . + "SharedPreferences sharedPreferences,\n" . + " String key) {\n" . + " }\n" . + "}\n"); + + print $in $body; + close $in; +} + + +sub error($) { + my ($err) = @_; + print STDERR "$progname: $err\n"; + exit 1; +} + +sub usage() { + print STDERR "usage: $progname [--verbose] files ...\n"; + exit 1; +} + +sub main() { + my @files = (); + while ($#ARGV >= 0) { + $_ = shift @ARGV; + if (m/^--?verbose$/) { $verbose++; } + elsif (m/^-v+$/) { $verbose += length($_)-1; } + elsif (m/^-./) { usage; } + else { push @files, $_; } +# else { usage; } + } + + usage unless ($#files >= 0); + my $failures = 0; + foreach (@files) { $failures += parse_then_make($_); } + exit ($failures); +} + +main();