From http://www.jwz.org/xscreensaver/xscreensaver-5.31.tar.gz
[xscreensaver] / hacks / munge-ad.pl
1 #!/usr/bin/perl -w
2 # Copyright © 2008-2014 Jamie Zawinski <jwz@jwz.org>
3 #
4 # Permission to use, copy, modify, distribute, and sell this software and its
5 # documentation for any purpose is hereby granted without fee, provided that
6 # the above copyright notice appear in all copies and that both that
7 # copyright notice and this permission notice appear in supporting
8 # documentation.  No representations are made about the suitability of this
9 # software for any purpose.  It is provided "as is" without express or 
10 # implied warranty.
11 #
12 # This updates driver/XScreenSaver.ad.in with the current list of savers.
13 #
14 # Created:  3-Aug-2008.
15
16 require 5;
17 use diagnostics;
18 use strict;
19
20 my $progname = $0; $progname =~ s@.*/@@g;
21 my ($version) = ('$Revision: 1.10 $' =~ m/\s(\d[.\d]+)\s/s);
22
23 my $verbose = 0;
24
25 # 1 means disabled: marked with "-" by default in the .ad file.
26 # 2 means retired: not mentioned in .ad at all (parsed from Makefile).
27 #
28 my %disable = ( 
29    'antinspect'         => 1,
30    'antmaze'            => 1,
31    'antspotlight'       => 1,
32    'braid'              => 1,
33    'crystal'            => 1,
34    'demon'              => 1,
35    'dnalogo'            => 1,
36    'fadeplot'           => 1,
37    'glblur'             => 1,
38    'glslideshow'        => 1,
39    'jigglypuff'         => 1,
40    'kaleidescope'       => 1,
41    'lcdscrub'           => 1,
42    'loop'               => 1,
43    'mismunch'           => 2,
44    'nerverot'           => 1,
45    'noseguy'            => 1,
46    'polyominoes'        => 1,
47    'providence'         => 1,
48    'pyro'               => 1,
49    'rdbomb'             => 2,  # alternate name
50    'rocks'              => 1,
51    'sballs'             => 1,
52    'sierpinski'         => 1,
53    'thornbird'          => 1,
54    'vidwhacker'         => 1,
55    'webcollage'         => 1,
56   );
57
58
59 # Parse the RETIRED_EXES variable from the Makefiles to populate %disable.
60 # Duplicated in ../OSX/build-fntable.pl.
61 #
62 sub parse_makefiles() {
63   foreach my $mf ( "Makefile.in", "glx/Makefile.in" ) {
64     open (my $in, '<', $mf) || error ("$mf: $!");
65     local $/ = undef;  # read entire file
66     my $body = <$in>;
67     close $in;
68
69     $body =~ s/\\\n//gs;
70     my ($var)  = ($body =~ m/^RETIRED_EXES\s*=\s*(.*)$/mi);
71     my ($var2) = ($body =~ m/^RETIRED_GL_EXES\s*=\s*(.*)$/mi);
72     error ("no RETIRED_EXES in $mf") unless $var;
73     $var .= " $var2" if $var2;
74     foreach my $hack (split (/\s+/, $var)) {
75       $disable{$hack} = 2;
76     }
77   }
78 }
79
80
81 sub munge_ad($) {
82   my ($file) = @_;
83
84   parse_makefiles();
85
86   open (my $in, '<', $file) || error ("$file: $!");
87   local $/ = undef;  # read entire file
88   my $body = <$in>;
89   close $in;
90   my $obody = $body;
91
92   my ($top, $mid, $bot) = ($body =~ m/^(.*?\n)(\*hacks\..*?\n)(\n.*)$/s);
93
94   my $mid2 = '';
95
96   my %hacks;
97
98   # Update the "*hacks.foo.name" section of the file based on the contents
99   # of config/*.xml.
100   #
101   my $dir = $file;
102   $dir =~ s@/[^/]*$@@s;
103   my @counts = (0,0,0,0,0,0,0,0,0,0);
104   foreach my $xml (sort (glob ("$dir/../hacks/config/*.xml"))) {
105     open (my $in, '<', $xml) || error ("$xml: $!");
106     local $/ = undef;  # read entire file
107     my $b = <$in>;
108     close $in;
109     my ($name) = ($b =~ m@<screensaver[^<>]*\b_label=\"([^<>\"]+)\"@s);
110     error ("$xml: no name") unless $name;
111
112     my $name2 = lc($name);
113     $name2 =~ s/^((x|gl)?[a-z])/\U$1/s;  # what prefs.c (make_hack_name) does
114
115     $xml =~ s@^.*/([^/]+)\.xml$@$1@s;
116     if ($name ne $name2) {
117       my $s = sprintf("*hacks.%s.name:", $xml);
118       $mid2 .= sprintf ("%-28s%s\n", $s, $name);
119       $counts[9]++;
120     }
121
122     # Grab the year.
123     my ($year) =
124       ($b =~ m/<_description>.*Written by.*?;\s+(19[6-9]\d|20\d\d)\b/si);
125     error ("no year in $xml.xml") unless $year;
126     $hacks{$xml} = $year;
127   }
128
129   # Splice in new names.
130   $body = $top . $mid2 . $bot;
131
132
133   # Replace the "programs" section.
134   # Sort hacks by creation date, but put the OpenGL ones at the end.
135   #
136   my $segregate_p = 0;  # whether to put the GL hacks at the end.
137   my $xhacks = '';
138   my $ghacks = '';
139   foreach my $hack (sort { $hacks{$a} == $hacks{$b}
140                            ? $a cmp $b 
141                            : $hacks{$a} <=> $hacks{$b}}
142                     (keys(%hacks))) {
143     my $cmd = "$hack -root";
144     my $ts = (length($cmd) / 8) * 8;
145     while ($ts < 40) { $cmd .= "\t"; $ts += 8; }
146
147     my $dis = $disable{$hack} || 0;
148
149     my $glp;
150     my $glep = ($hack eq 'extrusion');
151     if (-f "$hack.c" || -f "$hack") { $glp = 0; }
152     elsif (-f "glx/$hack.c") { $glp = 1; }
153     elsif ($hack eq 'companioncube') { $glp = 1; }  # kludge
154     elsif ($dis != 2) { error ("is $hack X or GL?"); }
155
156     $counts[($disable{$hack} || 0)]++;
157     if ($glp) {
158       $counts[6+($disable{$hack} || 0)]++;
159     } else {
160       $counts[3+($disable{$hack} || 0)]++;
161     }
162
163     next if ($dis == 2);
164
165     $dis = ($dis ? '-' : '');
166     my $vis = ($glp
167                ? (($dis ? '' : $glep ? '@GLE_KLUDGE@' : '@GL_KLUDGE@') .
168                   ' GL: ')
169                : '');
170     $cmd = "$dis$vis\t\t\t\t$cmd    \\n\\\n";
171
172     if ($glp) {
173       ($segregate_p ? $ghacks : $xhacks) .= $cmd;
174     } else {
175       $xhacks .= $cmd;
176     }
177   }
178
179   # Splice in new programs list.
180   #
181   $mid2 = ($xhacks .
182            ($segregate_p ? "\t\t\t\t\t\t\t\t\t      \\\n" : "") .
183            $ghacks);
184   $mid2 =~ s@\\$@@s;
185   ($top, $mid, $bot) = 
186     ($body =~ m/^(.*?\n\*programs:\s+\\\n)(.*?\n)(\n.*)$/s);
187   error ("unparsable") unless $mid;
188   $body = $top . $mid2 . $bot;
189
190   print STDERR "$progname: " .
191     "Total: $counts[0]+$counts[1]+$counts[2]; " .
192       "X11: $counts[3]+$counts[4]+$counts[5]; " .
193        "GL: $counts[6]+$counts[7]+$counts[8]; " .
194     "Names: $counts[9]\n"
195         if ($verbose);
196
197   # Write file if changed.
198   #
199   if ($body ne $obody) {
200     open (my $out, '>', $file) || error ("$file: $!");
201     print $out $body;
202     close $out;
203     print STDERR "$progname: wrote $file\n";
204   } elsif ($verbose) {
205     print STDERR "$progname: $file unchanged\n";
206   }
207 }
208
209
210 sub error($) {
211   my ($err) = @_;
212   print STDERR "$progname: $err\n";
213   exit 1;
214 }
215
216 sub usage() {
217   print STDERR "usage: $progname [--verbose] ad-file\n";
218   exit 1;
219 }
220
221 sub main() {
222   my $file;
223   while ($#ARGV >= 0) {
224     $_ = shift @ARGV;
225     if (m/^--?verbose$/) { $verbose++; }
226     elsif (m/^-v+$/) { $verbose += length($_)-1; }
227     elsif (m/^-./) { usage; }
228     elsif (!$file) { $file = $_; }
229     else { usage; }
230   }
231
232   usage unless ($file);
233   munge_ad ($file);
234 }
235
236 main();
237 exit 0;