f5e3b1f3dc69fc07c4d49854707b38783ef833d9
[xscreensaver] / OSX / build-fntable.pl
1 #!/usr/bin/perl -w
2 # Copyright © 2012 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 # Generates a .h file that lists all the function tables we use, because
13 # CFBundleGetDataPointerForName doesn't work in "Archive" builds.
14 # What a crock of shit.
15 #
16 # There's no real way to integrate this into the Xcode build system, so
17 # run this manually each time a new saver is added to the iOS app.
18 #
19 # Created: 14-Jul-2012.
20
21 require 5;
22 #use diagnostics;       # Fails on some MacOS 10.5 systems
23 use strict;
24
25 my $progname = $0; $progname =~ s@.*/@@g;
26 my $version = q{ $Revision: 1.1 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
27
28 my $verbose = 1;
29
30 sub build_h($$) {
31   my ($app_dir, $outfile) = @_;
32
33   opendir (my $dh, $app_dir) || error ("$app_dir: $!");
34   print STDERR "$progname: scanning $app_dir...\n" if ($verbose > 1);
35
36   my @names = ();
37   foreach (sort (readdir ($dh))) {
38     next unless (m/^(.*)\.xml$/);
39     push @names, $1;
40   }
41   closedir $dh;
42
43   my $suf = 'xscreensaver_function_table';
44
45   my $body = "extern struct $suf";
46   foreach my $s (@names) {
47     $body .= "\n *${s}_${suf},";
48   }
49   $body =~ s/,\s*$/;/s;
50
51   $body .= ("\n\n" .
52             "static NSDictionary *make_function_tables_dict(void)\n{\n" .
53             "  return\n    [NSDictionary dictionaryWithObjectsAndKeys:\n");
54   foreach my $s (@names) {
55     $body .= "\t[NSValue valueWithPointer:&${s}_${suf}], @\"${s}\",\n";
56   }
57   $body .= ("\tnil];\n" .
58             "}\n");
59
60   my $obody = '';
61   if (open (my $in, '<', $outfile)) {
62     local $/ = undef;  # read entire file
63     $obody = <$in>;
64     close $in;
65   }
66
67   if ($obody eq $body) {
68     print STDERR "$progname: $outfile: unchanged\n" if ($verbose > 1);
69   } else {
70     my $file_tmp = "$outfile.tmp";
71     open (my $out, '>', $file_tmp) || error ("$file_tmp: $!");
72     print $out $body || error ("$file_tmp: $!");
73     close $out || error ("$file_tmp: $!");
74
75     if (!rename ("$file_tmp", "$outfile")) {
76       unlink "$file_tmp";
77       error ("mv \"$file_tmp\" \"$outfile\": $!");
78     }
79     print STDERR "$progname: wrote $outfile\n" if ($verbose);
80   }
81 }
82
83
84 sub error($) {
85   my ($err) = @_;
86   print STDERR "$progname: $err\n";
87   exit 1;
88 }
89
90 sub usage() {
91   print STDERR "usage: $progname [--verbose] program.app output.h\n";
92   exit 1;
93 }
94
95 sub main() {
96
97   my ($app, $out);
98   while ($_ = $ARGV[0]) {
99     shift @ARGV;
100     if    (m/^--?verbose$/s)  { $verbose++; }
101     elsif (m/^-v+$/)          { $verbose += length($_)-1; }
102     elsif (m/^--?q(uiet)?$/s) { $verbose = 0; }
103     elsif (m/^-/s)            { usage(); }
104     elsif (! $app)            { $app = $_; }
105     elsif (! $out)            { $out = $_; }
106     else                      { usage(); }
107   }
108   usage() unless ($out && $app);
109   build_h ($app, $out);
110 }
111
112 main();
113 exit 0;