1package My::Utility;
2use strict;
3use warnings;
4use base qw(Exporter);
5
6our @EXPORT_OK = qw(check_config_script check_prebuilt_binaries check_prereqs_libs check_prereqs_tools find_SDL_dir find_file check_header
7                    sed_inplace get_dlext $inc_lib_candidates $source_packs check_perl_buildlibs);
8use Config;
9use ExtUtils::CBuilder;
10use File::Spec::Functions qw(splitdir catdir splitpath catpath rel2abs);
11use File::Find qw(find);
12use File::Which;
13use File::Copy qw(cp);
14use Cwd qw(realpath);
15
16our $cc                 = $Config{cc};
17our $inc_lib_candidates = {
18  '/usr/local/include'       => '/usr/local/lib',
19  '/usr/include'             => '/usr/lib',
20  '/usr/X11R6/include'       => '/usr/X11R6/lib',
21  '/usr/local/include/smpeg' => '/usr/local/lib',
22};
23$inc_lib_candidates->{'/usr/pkg/include/smpeg'} = '/usr/local/lib'            if -f '/usr/pkg/include/smpeg/smpeg.h';
24$inc_lib_candidates->{'/usr/include/smpeg'}     = '/usr/lib'                  if -f '/usr/include/smpeg/smpeg.h';
25$inc_lib_candidates->{'/usr/X11R6/include'}     = '/usr/X11R6/lib'            if -f '/usr/X11R6/include/GL/gl.h';
26$inc_lib_candidates->{'/usr/X11R7/include'}     = '/usr/X11R7/lib'            if -f '/usr/X11R7/include/GL/gl.h';
27$inc_lib_candidates->{'/usr/X11R7/include'}     = '/usr/X11R7/lib'            if -f '/usr/X11R7/include/freetype2/freetype/freetype.h';
28$inc_lib_candidates->{'/usr/X11R7/include'}     = '/usr/X11R7/lib'            if -f '/usr/X11R7/include/fontconfig/fontconfig.h';
29$inc_lib_candidates->{'/usr/include/ogg'}       = '/usr/lib/x86_64-linux-gnu' if -f '/usr/lib/x86_64-linux-gnu/libogg.so';
30$inc_lib_candidates->{'/usr/include/vorbis'}    = '/usr/lib/x86_64-linux-gnu' if -f '/usr/lib/x86_64-linux-gnu/libvorbis.so';
31$inc_lib_candidates->{'/usr/include'}           = '/usr/lib64'                if -e '/usr/lib64' && $Config{'myarchname'} =~ /64/;
32$inc_lib_candidates->{$ENV{SDL_INC}}            = $ENV{SDL_LIB}               if exists $ENV{SDL_LIB} && exists $ENV{SDL_INC};
33
34#### packs with prebuilt binaries
35# - all regexps has to match: arch_re ~ $Config{archname}, cc_re ~ $Config{cc}, os_re ~ $^O
36# - the order matters, we offer binaries to user in the same order (1st = preffered)
37my $prebuilt_binaries = [
38    {
39      title    => "Binaries Win/32bit SDL-1.2.14 (extended, 20100704) RECOMMENDED\n" .
40                  "\t(gfx, image, mixer, net, smpeg, ttf, sound, svg, rtf, Pango)",
41      url      => [
42        'http://strawberryperl.com/package/kmx/sdl/Win32_SDL-1.2.14-extended-bin_20100704.zip',
43        'http://froggs.de/libsdl/Win32_SDL-1.2.14-extended-bin_20100704.zip',
44      ],
45      sha1sum  => '98409ddeb649024a9cc1ab8ccb2ca7e8fe804fd8',
46      arch_re  => qr/^MSWin32-x86-multi-thread(-64int)?$/,
47      os_re    => qr/^MSWin32$/,
48      cc_re    => qr/gcc/,
49    },
50    {
51      title    => "Binaries Win/32bit SDL-1.2.14 (extended, 20111205)\n" .
52                  "\t(gfx, image, mixer, net, smpeg, ttf, sound, svg, rtf, Pango)",
53      url      => [
54        'http://strawberryperl.com/package/kmx/sdl/Win32_SDL-1.2.14-extended-bin_20111205.zip',
55        'http://froggs.de/libsdl/Win32_SDL-1.2.14-extended-bin_20111205.zip',
56      ],
57      sha1sum  => '553b7e21bb650d047ec9f2a5f650c67d76430e61',
58      arch_re  => qr/^MSWin32-x86-multi-thread(-64int)?$/,
59      os_re    => qr/^MSWin32$/,
60      cc_re    => qr/gcc/,
61    },
62    {
63      title    => "Binaries Win/64bit SDL-1.2.14 (extended, 20100824)\n" .
64                  "\t(gfx, image, mixer, net, smpeg, ttf, sound, svg, rtf, Pango)\n" .
65                  "\tBEWARE: binaries are using old ABI - will fail with the latest gcc\n" .
66                  "\tBEWARE: this is intended just for old strawberryperl 5.12.x/64bit",
67      url      => [
68        'http://strawberryperl.com/package/kmx/sdl/Win64_SDL-1.2.14-extended-bin_20100824.zip',
69        'http://froggs.de/libsdl/Win64_SDL-1.2.14-extended-bin_20100824.zip',
70      ],
71      sha1sum  => 'ccffb7218bcb17544ab00c8a1ae383422fe9586d',
72      arch_re  => qr/^MSWin32-x64-multi-thread$/,
73      os_re    => qr/^MSWin32$/,
74      cc_re    => qr/gcc/,
75      gccversion_re => qr/^4\.4\.3$/, #specific to the old gcc compiler used in 64bit strawberryperl 5.12.x
76    },
77    {
78      title    => "Binaries Win/64bit SDL-1.2.14 (extended, 20111205) RECOMMENDED\n" .
79                  "\t(gfx, image, mixer, net, smpeg, ttf, sound, svg, rtf, Pango)",
80      url      => [
81        'http://strawberryperl.com/package/kmx/sdl/Win64_SDL-1.2.14-extended-bin_20111205.zip',
82        'http://froggs.de/libsdl/Win64_SDL-1.2.14-extended-bin_20111205.zip',
83      ],
84      sha1sum  => '35f3b496ca443a9d14eff77e9e26acfa813afafd',
85      arch_re  => qr/^MSWin32-x64-multi-thread$/,
86      os_re    => qr/^MSWin32$/,
87      cc_re    => qr/gcc/,
88      gccversion_re => qr/^4\.(4\.[5-9]|[5-9]\.[0-9])$/,
89    },
90    {
91      title    => "Binaries Win/32bit SDL-1.2.15 (20120612)\n" .
92                  "\t(gfx, image, mixer, smpeg, ttf)",
93      url      => [
94        'http://froggs.de/libsdl/Win32_SDL-1.2.15-20120612.zip',
95      ],
96      sha1sum  => '22c531c1d0cc5a363c05045760870b2f45e9d0da',
97      arch_re  => qr/^MSWin32/,
98      os_re    => qr/^MSWin32$/,
99      cc_re    => qr/cl/,
100    },
101 ];
102
103#### tarballs with source codes
104our $source_packs = [
105  {
106    title   => "Source code build\n    ",
107    members => [
108      {
109        pack => 'z',
110        version => '1.2.5',
111        dirname => 'zlib-1.2.5',
112        url => [
113          'http://froggs.de/libz/zlib-1.2.5.tar.gz',
114        ],
115        sha1sum  => '8e8b93fa5eb80df1afe5422309dca42964562d7e',
116        patches => [
117          'zlib-1.2.5-bsd-ldconfig.patch',
118        ],
119        prereqs => {
120          libs => [ ]
121        }
122      },
123      {
124        pack => 'jpeg',
125        version => '8b',
126        dirname => 'jpeg-8b',
127        url => [
128          'http://www.ijg.org/files/jpegsrc.v8b.tar.gz',
129          'http://froggs.de/libjpeg/jpegsrc.v8b.tar.gz',
130        ],
131        sha1sum  => '15dc1939ea1a5b9d09baea11cceb13ca59e4f9df',
132        patches => [
133          'jpeg-8a_cygwin.patch',
134        ],
135        prereqs => {
136          libs => [ ]
137        }
138      },
139      {
140        pack => 'tiff',
141        version => '3.9.1',
142        dirname => 'tiff-3.9.1',
143        url => [
144          'http://froggs.de/libtiff/tiff-3.9.1.tar.gz',
145          'ftp://ftp.remotesensing.org/pub/libtiff/tiff-3.9.1.tar.gz',
146        ],
147        sha1sum  => '675ad1977023a89201b80cd5cd4abadea7ba0897',
148        patches => [ ],
149        prereqs => {
150          libs => [ ]
151        }
152      },
153      {
154        pack => 'png',
155        version => '1.4.1',
156        dirname => 'libpng-1.4.1',
157        url => [
158          'http://froggs.de/libpng/libpng-1.4.1.tar.gz',
159        ],
160        sha1sum  => '7a3488f5844068d67074f2507dd8a7ed9c69ff04',
161        prereqs => {
162          libs => [
163            'z',
164          ]
165        }
166      },
167      {
168        pack => 'freetype',
169        version => '2.3.12',
170        dirname => 'freetype-2.3.12',
171        url => [
172          'http://mirror.lihnidos.org/GNU/savannah/freetype/freetype-2.3.12.tar.gz',
173          'http://froggs.de/libfreetype/freetype-2.3.12.tar.gz',
174        ],
175        sha1sum  => '0082ec5e99fec5a1c6d89b321a7e2f201542e4b3',
176        prereqs => {
177          libs => [ ]
178        }
179      },
180      {
181        pack => 'SDL',
182        version => '1.2.15',
183        dirname => 'SDL-1.2',
184        url => [
185          'http://froggs.de/libsdl/SDL-1.2-2b923729fd01.tar.gz',
186        ],
187        sha1sum  => 'ec9841377403e8d1bcfd76626434be64d11f59f0',
188        patches => [
189          'test1.patch',
190          'SDL-1.2-openbsd-rldflags.patch',
191          'libsdl-1.2.15-const-xdata32.1.patch',
192          'libsdl-1.2.15-const-xdata32.2.patch',
193          'libsdl-1.2.15-const-xdata32.3.patch',
194          'libsdl-1.2.15-const-xdata32.4.patch',
195          'SDL-1.2.15-PIC-in-CFLAGS.patch',
196          'SDL-1.2.15-Makefile.in-OBJECTS.patch',
197          'SDL-1.2.15-mavericks-cgdirectpallete.patch',
198        ],
199        prereqs => {
200          libs => [
201            'pthread',
202          ]
203        },
204      },
205      {
206        pack => 'SDL_image',
207        version => '1.2.11',
208        dirname => 'SDL_image-1.2.11',
209        url => [
210          'http://www.libsdl.org/projects/SDL_image/release/SDL_image-1.2.11.tar.gz',
211          'http://froggs.de/libsdl/SDL_image-1.2.11.tar.gz',
212        ],
213        sha1sum  => 'dd384ff87848595fcc0691833431ec5029f973c7',
214        patches => [
215          'SDL_image-1.2.11-CGFloat.patch',
216          'SDL_image-1.2.11-libpng-flags.patch',
217        ],
218        prereqs => {
219          libs => [
220            'jpeg', 'tiff', 'png',
221          ]
222        }
223      },
224      {
225        pack => 'ogg',
226        version => '1.3.0',
227        dirname => 'libogg-1.3.0',
228        url => [
229          'http://downloads.xiph.org/releases/ogg/libogg-1.3.0.tar.gz',
230          'http://froggs.de/libsdl/libogg-1.3.0.tar.gz',
231        ],
232        sha1sum  => 'a900af21b6d7db1c7aa74eb0c39589ed9db991b8',
233        patches => [ ],
234      },
235      {
236        pack => 'vorbis',
237        version => '1.3.3',
238        dirname => 'libvorbis-1.3.3',
239        url => [
240          'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.3.tar.gz',
241          'http://froggs.de/libsdl/libvorbis-1.3.3.tar.gz',
242        ],
243        sha1sum  => '8dae60349292ed76db0e490dc5ee51088a84518b',
244        patches => [
245          'libvorbis-1.3.3-configure.patch',
246        ],
247        prereqs => {
248          libs => [ ]
249        }
250      },
251      {
252        pack => 'SDL_mixer',
253        version => '1.2.12',
254        dirname => 'SDL_mixer-1.2.12',
255        url => [
256          'http://www.libsdl.org/projects/SDL_mixer/release/SDL_mixer-1.2.12.tar.gz',
257          'http://froggs.de/libsdl/SDL_mixer-1.2.12.tar.gz',
258        ],
259        sha1sum  => 'a20fa96470ad9e1052f1957b77ffa68fb090b384',
260        patches => [
261          'SDL_mixer-1.2.12-native-midi-win32.patch',
262        ],
263        prereqs => {
264          libs => [
265            'ogg', 'vorbis',
266          ]
267        },
268      },
269      {
270        pack => 'SDL_ttf',
271        version => '2.0.11',
272        dirname => 'SDL_ttf-2.0.11',
273        url => [
274          'http://www.libsdl.org/projects/SDL_ttf/release/SDL_ttf-2.0.11.tar.gz',
275          'http://froggs.de/libsdl/SDL_ttf-2.0.11.tar.gz',
276        ],
277        sha1sum  => '0ccf7c70e26b7801d83f4847766e09f09db15cc6',
278        patches => [ ],
279        prereqs => {
280          libs => [
281            'freetype', # SDL_ttf
282          ]
283        },
284      },
285      {
286        pack => 'SDL_gfx',
287        version => '2.0.25',
288        dirname => 'SDL_gfx-2.0.25',
289        url => [
290          'http://froggs.de/libsdl/SDL_gfx-2.0.25.tar.gz',
291          'http://www.ferzkopp.net/Software/SDL_gfx-2.0/SDL_gfx-2.0.25.tar.gz',
292        ],
293        sha1sum  => '20a89d0b71b7b790b830c70f17ed2c44100bc0f4',
294        patches => [ ],
295        prereqs => {
296          libs => [ ]
297        }
298      },
299      {
300        pack => 'SDL_Pango',
301        version => '1.2',
302        dirname => 'SDL_Pango-0.1.2',
303        url => [
304          'http://downloads.sourceforge.net/sdlpango/SDL_Pango-0.1.2.tar.gz',
305          'http://froggs.de/libsdl/SDL_Pango-0.1.2.tar.gz',
306        ],
307        sha1sum  => 'c30f2941d476d9362850a150d29cb4a93730af68',
308        patches => [
309          'SDL_Pango-0.1.2-API-adds.1.patch',
310          'SDL_Pango-0.1.2-API-adds.2.patch',
311          'SDL_Pango-0.1.2-config-tools.1.patch',
312          'SDL_Pango-0.1.2-config-tools.2.patch',
313          'SDL_Pango-0.1.2-config-tools.3.patch',
314          'SDL_Pango-0.1.2-include-ft2build.h.patch',
315        ],
316        prereqs => {
317          libs => [
318            'pangoft2', 'pango', 'gobject', 'gmodule', 'glib', 'fontconfig', 'freetype', 'expat', # SDL_Pango
319          ]
320        }
321      },
322    ],
323  },
324];
325
326sub check_config_script {
327  my $script = shift || 'sdl-config';
328  print "checking for config script... ";
329  my $devnull = File::Spec->devnull();
330  my $version = `$script --version 2>$devnull`;
331  if($? >> 8) {
332    print "no\n";
333    return;
334  }
335  my $prefix = `$script --prefix 2>$devnull`;
336  if($? >> 8) {
337    print "no\n";
338    return;
339  }
340  $version =~ s/[\r\n]+$//;
341  $prefix  =~ s/[\r\n]+$//;
342  print "yes, $script\n";
343  #returning HASHREF
344  return {
345    title     => "Already installed SDL ver=$version path=$prefix",
346    buildtype => 'use_config_script',
347    script    => $script,
348    prefix    => $prefix,
349  };
350}
351
352sub check_prebuilt_binaries
353{
354  print "checking for prebuilt binaries... ";
355#  print "(os=$^O cc=$cc archname=$Config{archname})\n";
356  my @good = ();
357  foreach my $b (@{$prebuilt_binaries}) {
358    if ( ($^O =~ $b->{os_re}) &&
359         ($Config{archname} =~ $b->{arch_re}) &&
360         ($cc =~ $b->{cc_re}) &&
361         (!defined $b->{gccversion_re} || $Config{gccversion} =~ $b->{gccversion_re})
362        ) {
363      $b->{buildtype} = 'use_prebuilt_binaries';
364      push @good, $b;
365    }
366  }
367  scalar(@good)
368    ? print "yes, " . scalar(@good) . " option(s)\n"
369    : print "no\n";
370  #returning ARRAY of HASHREFs (sometimes more than one value)
371  return \@good;
372}
373
374sub check_prereqs_libs {
375  my @libs = @_;
376  my $ret  = 1;
377
378  foreach my $lib (@libs) {
379    print "checking for $lib... ";
380    my $found_dll          = '';
381    my $found_lib          = '';
382    my $found_inc          = '';
383    my $header_map         = {
384      'z'       => 'zlib',
385      'jpeg'    => 'jpeglib',
386      'vorbis'  => 'vorbisenc',
387      'SDL_gfx' => 'SDL_gfxPrimitives',
388      'SDL'     => 'SDL_version',
389    };
390    my $header             = (defined $header_map->{$lib}) ? $header_map->{$lib} : $lib;
391
392    my $dlext = get_dlext();
393    foreach (keys %$inc_lib_candidates) {
394      my $ld = $inc_lib_candidates->{$_};
395      next unless -d $_ && -d $ld;
396      ($found_dll) = find_file($ld, qr/[\/\\]lib\Q$lib\E[\-\d\.]*\.($dlext[\d\.]*|so|dll)$/);
397      $found_dll   = $1 if $found_dll && $found_dll =~/^(.+($dlext|so|dll))/ && -e $1;
398      ($found_lib) = find_file($ld, qr/[\/\\]lib\Q$lib\E[\-\d\.]*\.($dlext[\d\.]*|a|dll.a)$/);
399      ($found_inc) = find_file($_,  qr/[\/\\]\Q$header\E[\-\d\.]*\.h$/);
400      last if $found_lib && $found_inc;
401    }
402
403    if($found_lib && $found_inc) {
404      print "yes\n";
405      $ret &= 1;
406    }
407    else {
408      print "no\n";
409      $ret = 0;
410    }
411
412    if( scalar(@libs) == 1 ) {
413      return $ret
414        ? [(get_header_version($found_inc) || 'found'), $found_dll]
415        : [0, undef];
416    }
417  }
418
419  return $ret;
420}
421
422sub check_perl_buildlibs {
423  my @libs    = @_;
424  my $ret     = 1;
425  my $dlext   = get_dlext();
426  my $devnull = File::Spec->devnull();
427  for my $lib (@libs) {
428    print "checking if perl is linked against $lib... ";
429    if($Config{libs}        =~ /\Q-l$lib\E\b/
430    || $Config{perllibs}    =~ /\Q-l$lib\E\b/
431    || `ldd $^X 2>$devnull` =~ /[\/\\]lib\Q$lib\E[\-\d\.]*\.($dlext[\d\.]*|so|dll)$/) {
432      print "yes\n";
433      $ret &= 1;
434    }
435    else {
436      print "no\n";
437      $ret = 0;
438    }
439  }
440  return $ret;
441}
442
443sub check_prereqs {
444  my $bp  = shift;
445  my $ret = 1;
446  $ret   &= check_prereqs_libs(@{$bp->{prereqs}->{libs}}) if defined $bp->{prereqs}->{libs};
447
448  return $ret;
449}
450
451sub check_prereqs_tools {
452  my @tools = @_;
453  my $ret   = 1;
454
455  foreach my $tool (@tools) {
456
457    if((File::Which::which($tool) && -x File::Which::which($tool))
458    || ('pkg-config' eq $tool && defined $ENV{PKG_CONFIG} && $ENV{PKG_CONFIG}
459                              && File::Which::which($ENV{PKG_CONFIG})
460                              && -x File::Which::which($ENV{PKG_CONFIG}))) {
461      $ret &= 1;
462    }
463    else {
464      $ret = 0;
465    }
466  }
467
468  return $ret;
469}
470
471sub find_file {
472  my ($dir, $re) = @_;
473  my @files;
474  $re ||= qr/.*/;
475  {
476    #hide warning "Can't opendir(...): Permission denied - fix for http://rt.cpan.org/Public/Bug/Display.html?id=57232
477    no warnings;
478    find({ wanted => sub { push @files, rel2abs($_) if /$re/ }, follow => 1, no_chdir => 1 , follow_skip => 2}, $dir);
479  };
480  return @files;
481}
482
483sub find_SDL_dir {
484  my $root = shift;
485  my ($version, $prefix, $incdir, $libdir);
486  return unless $root;
487
488  # try to find SDL_version.h
489  my ($found) = find_file($root, qr/SDL_version\.h$/i ); # take just the first one
490  return unless $found;
491
492  # get version info
493  open(DAT, $found) || return;
494  my @raw=<DAT>;
495  close(DAT);
496  my ($v_maj) = grep(/^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+/, @raw);
497  $v_maj =~ s/^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)[.\r\n]*$/$1/;
498  my ($v_min) = grep(/^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+/, @raw);
499  $v_min =~ s/^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)[.\r\n]*$/$1/;
500  my ($v_pat) = grep(/^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+/, @raw);
501  $v_pat =~ s/^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)[.\r\n]*$/$1/;
502  return if (($v_maj eq '')||($v_min eq '')||($v_pat eq ''));
503  $version = "$v_maj.$v_min.$v_pat";
504
505  # get prefix dir
506  my ($v, $d, $f) = splitpath($found);
507  my @pp = reverse splitdir($d);
508  shift(@pp) if(defined($pp[0]) && $pp[0] eq '');
509  shift(@pp) if(defined($pp[0]) && $pp[0] eq 'SDL');
510  if(defined($pp[0]) && $pp[0] eq 'include') {
511    shift(@pp);
512    @pp = reverse @pp;
513    return (
514      $version,
515      catpath($v, catdir(@pp), ''),
516      catpath($v, catdir(@pp, 'include'), ''),
517      catpath($v, catdir(@pp, 'lib'), ''),
518    );
519  }
520}
521
522sub check_header {
523  my ($cflags, @header) = @_;
524  print STDERR "Testing header(s): " . join(', ', @header) . "\n";
525  my $cb = ExtUtils::CBuilder->new(quiet => 1);
526  my ($fs, $src) = File::Temp::tempfile('aaXXXX', SUFFIX => '.c', UNLINK => 1);
527  my $inc = '';
528  $inc .= "#include <$_>\n" for @header;
529  syswrite($fs, <<MARKER); # write test source code
530#if defined(_WIN32) && !defined(__CYGWIN__)
531#include <stdio.h>
532/* GL/gl.h on Win32 requires windows.h being included before */
533#include <windows.h>
534#endif
535$inc
536int demofunc(void) { return 0; }
537
538MARKER
539  close($fs);
540  my $obj = eval { $cb->compile( source => $src, extra_compiler_flags => $cflags); };
541  if($obj) {
542    unlink $obj;
543    return 1;
544  }
545  else {
546    print STDERR "###TEST FAILED### for: " . join(', ', @header) . "\n";
547    return 0;
548  }
549}
550
551sub sed_inplace {
552  # we expect to be called like this:
553  # sed_inplace("filename.txt", 's/0x([0-9]*)/n=$1/g');
554  my ($file, $re) = @_;
555  if (-e $file) {
556    cp($file, "$file.bak") or die "###ERROR### cp: $!";
557    open INPF, "<", "$file.bak" or die "###ERROR### open<: $!";
558    open OUTF, ">", $file or die "###ERROR### open>: $!";
559    binmode OUTF; # we do not want Windows newlines
560    while (<INPF>) {
561     eval( "$re" );
562     print OUTF $_;
563    }
564    close INPF;
565    close OUTF;
566  }
567}
568
569sub get_dlext {
570  if($^O =~ /darwin/) { # there can be .dylib's on a mac even if $Config{dlext} is 'bundle'
571    return 'so|dylib|bundle';
572  }
573  elsif( $^O =~ /cygwin/) {
574    return 'la';
575  }
576  else {
577    return $Config{so};
578  }
579}
580
581sub get_header_version {
582  my $file = shift;
583  # get version info
584  open(DAT, $file) || return;
585  my @raw = <DAT>;
586  close(DAT);
587
588  # generic magic how to get version major/minor/patchlevel
589  my ($v_maj) = grep(/^#define[ \t]+[A-Z_]+?MAJOR[A-Z_]*[ \t]+[0-9]+/, @raw);
590  $v_maj      = '' unless defined $v_maj;
591  $v_maj      =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
592  my ($v_min) = grep(/^#define[ \t]+[A-Z_]+MINOR[A-Z_]*[ \t]+[0-9]+/, @raw);
593  $v_min      = '' unless defined $v_min;
594  $v_min      =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
595  my ($v_pat) = grep(/^#define[ \t]+[A-Z_]+(PATCHLEVEL|MICRO|RELEASE)[A-Z_]*[ \t]+[0-9]+/, @raw);
596  $v_pat      = '' unless defined $v_pat;
597  $v_pat      =~ s/^#define[ \t]+[A-Z_]+[ \t]+([0-9]+)[.\r\n]*$/$1/;
598  if(($v_maj eq '')||($v_min eq '')||($v_pat eq '')) {
599    my ($rev) = grep(/\$Revision:\s*[0-9\.]+\s*\$/, @raw);
600    return unless defined $rev;
601    $rev      =~ s/.*\$Revision:\s*([0-9\.]+)\s*\$[.\r\n]*/$1/;
602    return $rev;
603  }
604  return "$v_maj.$v_min.$v_pat";
605}
606
6071;
608