From http://www.jwz.org/xscreensaver/xscreensaver-5.22.tar.gz
[xscreensaver] / OSX / build-fntable.pl
1 #!/usr/bin/perl -w
2 # Copyright © 2012-2013 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 .c 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.2 $ }; $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 = ("/* Generated file, do not edit.\n" .
46               "   Created: " . localtime() . " by $progname $version.\n" .
47               " */\n" .
48               "\n" .
49               "#import <Foundation/Foundation.h>\n" .
50               "#import <UIKit/UIKit.h>\n" .
51               "\n" .
52               "extern NSDictionary *make_function_table_dict(void);\n" .
53               "\n");
54
55   $body .= "extern struct $suf";
56   foreach my $s (@names) {
57     $body .= "\n *${s}_${suf},";
58   }
59   $body =~ s/,\s*$/;/s;
60
61   sub line($$) {
62     my ($s, $suf) = @_;
63     return "\t[NSValue valueWithPointer:&${s}_${suf}], @\"${s}\",\n";
64   }
65
66   $body .= ("\n\n" .
67             "NSDictionary *make_function_table_dict(void)\n{\n" .
68             "  return\n    [NSDictionary dictionaryWithObjectsAndKeys:\n" .
69             "\n" .
70             "#if defined(APPLE2_ONLY)\n" .
71             " " . line('apple2', $suf) .
72             "#elif defined(PHOSPHOR_ONLY)\n" .
73             " " . line('phosphor', $suf) .
74             "#else\n");
75   foreach my $s (@names) { $body .= line($s, $suf); }
76   $body .= ("#endif\n" .
77             "\tnil];\n" .
78             "}\n\n");
79
80   my $obody = '';
81   if (open (my $in, '<', $outfile)) {
82     local $/ = undef;  # read entire file
83     $obody = <$in>;
84     close $in;
85   }
86
87   # strip comments/date for diff.
88   my ($body2, $obody2) = ($body, $obody);
89   foreach ($body2, $obody2) { s@/\*.*?\*/@@gs; }
90
91   if ($body2 eq $obody2) {
92     print STDERR "$progname: $outfile: unchanged\n" if ($verbose > 1);
93   } else {
94     my $file_tmp = "$outfile.tmp";
95     open (my $out, '>', $file_tmp) || error ("$file_tmp: $!");
96     print $out $body || error ("$file_tmp: $!");
97     close $out || error ("$file_tmp: $!");
98
99     if (!rename ("$file_tmp", "$outfile")) {
100       unlink "$file_tmp";
101       error ("mv \"$file_tmp\" \"$outfile\": $!");
102     }
103     print STDERR "$progname: wrote $outfile\n" if ($verbose);
104   }
105 }
106
107
108 sub error($) {
109   my ($err) = @_;
110   print STDERR "$progname: $err\n";
111   exit 1;
112 }
113
114 sub usage() {
115   print STDERR "usage: $progname [--verbose] program.app output.c\n";
116   exit 1;
117 }
118
119 sub main() {
120
121   my ($app, $out);
122   while ($_ = $ARGV[0]) {
123     shift @ARGV;
124     if    (m/^--?verbose$/s)  { $verbose++; }
125     elsif (m/^-v+$/)          { $verbose += length($_)-1; }
126     elsif (m/^--?q(uiet)?$/s) { $verbose = 0; }
127     elsif (m/^-/s)            { usage(); }
128     elsif (! $app)            { $app = $_; }
129     elsif (! $out)            { $out = $_; }
130     else                      { usage(); }
131   }
132   usage() unless ($out && $app);
133   build_h ($app, $out);
134 }
135
136 main();
137 exit 0;