File Coverage

blib/lib/Test/Smoke/Util.pm
Criterion Covered Total %
statement 422 548 77.0
branch 243 376 64.6
condition 59 108 54.6
subroutine 29 33 87.8
pod 24 24 100.0
total 777 1089 71.3


line stmt bran cond sub pod time code
1             package Test::Smoke::Util;
2 39     39   995248 use strict;
  39         262  
  39         1500  
3              
4             our $VERSION = '0.58';
5              
6 39     39   232 use Exporter 'import';
  39         63  
  39         2521  
7             our @EXPORT = qw(
8             &Configure_win32
9             &get_cfg_filename &get_config
10             &get_patch
11             &skip_config &skip_filter
12             );
13              
14             our @EXPORT_OK = qw(
15             &grepccmsg &grepnonfatal &get_local_patches &set_local_patch
16             &get_ncpu &get_smoked_Config &parse_report_Config
17             &get_regen_headers &run_regen_headers
18             &whereis &clean_filename &read_logfile
19             &calc_timeout &time_in_hhmm
20             &do_pod2usage
21             &set_vms_rooted_logical
22             );
23              
24 39     39   15201 use Text::ParseWords;
  39         44070  
  39         2120  
25 39     39   8841 use File::Spec::Functions;
  39         17309  
  39         2601  
26 39     39   15807 use Encode qw ( decode );
  39         464215  
  39         2660  
27 39     39   267 use File::Find;
  39         64  
  39         2040  
28 39     39   229 use Cwd;
  39         78  
  39         2055  
29 39     39   11881 use Test::Smoke::LogMixin;
  39         106  
  39         313152  
30              
31             our $NOCASE = $^O eq 'VMS';
32              
33             =head1 NAME
34              
35             Test::Smoke::Util - Take out some of the functions of the smoke suite.
36              
37             =head1 FUNCTIONS
38              
39             I've taken out some of the general stuff and put it here.
40             Now I can write some tests!
41              
42             =head2 Configure_win32( $command[, $win32_maker[, @args]] )
43              
44             C alters the settings of the makefile for MSWin32.
45              
46             C<$command> is in the form of './Configure -des -Dusedevel ...'
47              
48             C<$win32_maker> should either be C or C, the default
49             is C.
50              
51             C<@args> is a list of C<< option=value >> pairs that will (eventually)
52             be passed to L.
53              
54             PLEASE read README.win32 and study the comments in the makefile.
55              
56             It supports these options:
57              
58             =over 4
59              
60             =item * B<-Duseperlio>
61              
62             set USE_PERLIO = define (default) [should be depricated]
63              
64             =item * B<-Dusethreads>
65              
66             set USE_ITHREADS = define (also sets USE_MULTI and USE_IMP_SYS)
67              
68             =item * B<-Duseithreads>
69              
70             set USE_ITHREADS = define (also sets USE_MULTI and USE_IMP_SYS)
71              
72             =item * B<-Dusemultiplicity>
73              
74             sets USE_MULTI = define (also sets USE_ITHREADS and USE_IMP_SYS)
75              
76             =item * B<-Duseimpsys>
77              
78             sets USE_IMP_SYS = define (also sets USE_ITHREADS and USE_MULTI)
79              
80             =item * B<-Uusethreads> or B<-Uuseithreads>
81              
82             unset C, C and C
83              
84             =item * B<-Dusemymalloc>
85              
86             set C
87              
88             =item * B<-Duselargefiles>
89              
90             set C
91              
92             =item * B<-Duse64bint>
93              
94             set C (always for win64, needed for -UWIN64)
95              
96             =item * B<-Duselongdouble>
97              
98             set C (GCC only)
99              
100             =item * B<-Dusequadmath>
101              
102             set both C and C (GCC only)
103              
104             =item * B<-Dusesitecustomize>
105              
106             set C
107              
108             =item * B<-Udefault_inc_excludes_dot>
109              
110             unsets C<# DEFAULT_INC_EXCLUDES_DOT := define> (comments out the line)
111              
112             =item * B<-Dbccold>
113              
114             set BCCOLD = define (this is for bcc32 <= 5.4)
115              
116             =item * B<-Dgcc_v3_2>
117              
118             set USE_GCC_V3_2 = define (this is for gcc >= 3.2)
119              
120             =item * B<-DDEBUGGING>
121              
122             sets CFG = Debug
123              
124             =item * B<-DINST_DRV=...>
125              
126             sets INST_DRV to a new value (default is "c:")
127              
128             =item * B<-DINST_TOP=...> or B<-Dprefix=...>
129              
130             sets INST_TOp to a new value (default is "$(INST_DRV)\perl"), this is
131             where perl will be installed when C<< [ng]make install >> is run.
132              
133             =item * B<-DINST_VER=...>
134              
135             sets INST_VER to a new value (default is forced not set), this is also used
136             as part of the installation path to get a more unixy installation.
137             Without C and C you get an ActiveState like
138             installation.
139              
140             =item * B<-DINST_ARCH=...>
141              
142             sets INST_ARCH to a new value (default is forced not set), this is also used
143             as part of the installation path to get a more unixy installation.
144             Without C and C you get an ActiveState like
145             installation.
146              
147             =item * B<-DCCHOME=...>
148              
149             Set the base directory for the C compiler.
150             B<$(CCHOME)\bin> still needs to be in the path!
151              
152             =item * B<-DIS_WIN95>
153              
154             sets IS_WIN95 to 'define' to indicate this is Win9[58]
155              
156             =item * B<-DCRYPT_SRC=...>
157              
158             The file to use as source for des_fcrypt()
159              
160             =item * B<-DCRYPT_LIB=...>
161              
162             The library to use for des_fcrypt()
163              
164             =item * B<-Dcf_email=...>
165              
166             Set the cf_email option (Config.pm)
167              
168             =item * B<-Accflags=...>
169              
170             Sets C
171              
172             =item * B<-Aldflags=...>
173              
174             Adds and sets C
175              
176             =back
177              
178             =cut
179              
180             my %win32_makefile_map = (
181             nmake => "Makefile",
182             gmake => "GNUmakefile",
183             );
184              
185             sub Configure_win32 {
186 28     28 1 77566 my($command, $win32_maker, @args ) = @_;
187 28   50     70 $win32_maker ||= 'nmake'; $win32_maker = lc $win32_maker;
  28         52  
188 28         52 my $is_nmake = $win32_maker eq 'nmake';
189 28         36 my $is_gmake = $win32_maker eq 'gmake';
190              
191 28         39 local $_;
192 28         432 my %opt_map = (
193             "-Dusethreads" => "USE_ITHREADS",
194             "-Duseithreads" => "USE_ITHREADS",
195             "-Duseperlio" => "USE_PERLIO",
196             "-Dusemultiplicity" => "USE_MULTI",
197             "-Duseimpsys" => "USE_IMP_SYS",
198             "-Uuseimpsys" => "USE_IMP_SYS",
199             "-Dusemymalloc" => "PERL_MALLOC",
200             "-Duselargefiles" => "USE_LARGE_FILES",
201             "-Duse64bitint" => "USE_64_BIT_INT",
202             "-Duselongdouble" => "USE_LONG_DOUBLE",
203             "-Dusequadmath" => "USE_QUADMATH",
204             "-Dusesitecustomize" => "USE_SITECUST",
205             "-Uuseshrplib" => "BUILD_STATIC",
206             "-Udefault_inc_excludes_dot" => "DEFAULT_INC_EXCLUDES_DOT",
207             "-UWIN64" => "WIN64",
208             "-Uusethreads" => "USE_ITHREADS",
209             "-Uuseithreads" => "USE_ITHREADS",
210             "-UUSE_MINGW_ANSI_STDIO" => "USE_MINGW_ANSI_STDIO",
211             "-DDEBUGGING" => "USE_DEBUGGING",
212             "-DINST_DRV" => "INST_DRV",
213             "-DINST_TOP" => "INST_TOP",
214             "-Dprefix" => "INST_TOP",
215             "-DINST_VER" => "INST_VER",
216             "-DINST_ARCH" => "INST_ARCH",
217             "-Dcf_email" => "EMAIL",
218             "-DCCTYPE" => "CCTYPE",
219             "-Dgcc_v3_2" => "USE_GCC_V3_2",
220             "-DGCC_4XX" => "GCC_4XX",
221             "-DGCCWRAPV" => "GCCWRAPV",
222             "-DGCCHELPERDLL" => "GCCHELPERDLL",
223             "-Dbccold" => "BCCOLD",
224             "-DCCHOME" => "CCHOME",
225             "-DGCCBIN" => "GCCBIN",
226             "-DIS_WIN95" => "IS_WIN95",
227             "-DCRYPT_SRC" => "CRYPT_SRC",
228             "-DCRYPT_LIB" => "CRYPT_LIB",
229             "-DEXTRALIBDIRS" => "EXTRALIBDIRS",
230             );
231             # %opts hash-values:
232             # undef => leave option as-is when no override (makefile default)
233             # 0 => disable option when no override (forced default)
234             # (true) => enable option when no override (change value, unless
235             # $key =~ /^(?:PERL|USE)_/) (forced default)
236 28         344 my %opts = (
237             USE_MULTI => 1,
238             USE_ITHREADS => 1,
239             USE_IMP_SYS => 1,
240             USE_PERLIO => 1,
241             USE_LARGE_FILES => 0, # default define
242             PERL_MALLOC => 0,
243             BUILD_STATIC => 0,
244             USE_64_BIT_INT => 0,
245             USE_LONG_DOUBLE => 0,
246             USE_QUADMATH => 0,
247             I_QUADMATH => 0,
248             WIN64 => 1,
249             USE_SITECUST => 0,
250             DEFAULT_INC_EXCLUDES_DOT => 1,
251             USE_MINGW_ANSI_STDIO => 1,
252             USE_DEBUGGING => 0,
253             INST_DRV => undef,
254             INST_TOP => undef,
255             INST_VER => '',
256             INST_ARCH => '',
257             EMAIL => undef, # used to be $smoker,
258             CCTYPE => undef, # used to be $win32_cctype,
259             USE_GCC_V3_2 => 0,
260             GCC_4XX => 0,
261             GCCWRAPV => 0,
262             GCCHELPERDLL => undef,
263             BCCOLD => 0,
264             CCHOME => undef,
265             GCCBIN => 'GCC',
266             IS_WIN95 => 0,
267             CRYPT_SRC => undef,
268             CRYPT_LIB => undef,
269             EXTRALIBDIRS => undef,
270             );
271              
272             # $undef_re: regex for options that should be UNcommented for -Uxxx
273 28         103 my $undef_re = qr/WIN64/;
274              
275             # $def_re: regex for options that should be UNcommented for -Dxxx
276 28         62 my $def_re = qr/((?:(?:DEFAULT|PERL|USE|IS|GCC|I)_\w+)|BCCOLD|GCCWRAPV)/;
277              
278 28         1164 my @w32_opts = grep ! /^$def_re/, keys %opts;
279 28         166 my $config_args = join " ",
280             grep /^-[DU][a-z_]+/, quotewords( '\s+', 1, $command );
281 28         3211 push @args, "config_args=$config_args";
282              
283             my @adjust_opts = grep {
284 28         68 /^-A(?:ccflags|ldflags)=/
  100         2576  
285             } quotewords('\s+', 1, $command);
286             my $adjust_ccflags = join(
287             " ",
288             map {
289 6 50       38 s/^-Accflags=(["']?)(.+?)\1// ? $2 : ()
290 28         62 } grep { /^-Accflags=/ } @adjust_opts
  6         15  
291             );
292             my $adjust_ldflags = join(
293             " ",
294             map {
295 0 0       0 s/^-Aldflags=(["']?)(.+?)\1// ? $2 : ()
296 28         54 } grep { /^-Aldflags=/ } @adjust_opts
  6         12  
297             );
298              
299 28 50       118 $command =~ m{^\s*\./Configure\s+(.*)} or die "unable to parse command";
300 28         58 my $cmdln = $1;
301 28         60 foreach ( quotewords( '\s+', 1, $cmdln ) ) {
302 72 100       2072 m/^-[des]{1,3}$/ and next;
303 64 100       115 m/^-Dusedevel$/ and next;
304 56 100       92 m/^-A(ccflags|ldflags)/ and next;
305 50 50       188 if (my( $option, $value ) = /^(-[DU]\w+)(?:=(.+))?$/) {
306 50 50       102 die "invalid option '$_'" unless exists $opt_map{$option};
307 50 100       115 $opts{$opt_map{$option}} = $value ? $value : 1;
308 50 100       118 $option =~ /^-U/ and $opts{$opt_map{$option}} = 0;
309             }
310             }
311              
312             # Handle some switches that impact more make-vars
313 28 100       77 if ( $cmdln =~ /-Uusei?threads\b/ ) {
314 2         6 $opts{USE_MULTI} = $opts{USE_ITHREADS} = $opts{USE_IMP_SYS} = 0;
315              
316             }
317 28 50       59 if ( $cmdln =~ /-Dusequadmath\b/ ) {
318 0         0 $opts{USE_QUADMATH} = $opts{I_QUADMATH} = 1;
319             }
320             # If you set one, we do all, so you can have fork()
321             # unless you set -Uuseimpsys
322 28 100       59 if ( $cmdln !~ /-Uuseimpsys\b/ ) {
323 26 50 66     69 if ( $opts{USE_MULTI} || $opts{USE_ITHREADS} || $opts{USE_IMP_SYS} ) {
      33        
324 24         43 $opts{USE_MULTI} = $opts{USE_ITHREADS} = $opts{USE_IMP_SYS} = 1;
325             }
326             }
327             else {
328 2 50 33     11 if ( $opts{USE_MULTI} || $opts{USE_ITHREADS} ) {
329 2         5 $opts{USE_MULTI} = $opts{USE_ITHREADS} = 1;
330             }
331             }
332              
333             # If you -Dgcc_v3_2 you 'll *want* CCTYPE = GCC
334 28 50       51 $opts{CCTYPE} = "GCC" if $opts{USE_GCC_V3_2};
335              
336             # If you -DGCC_4XX you 'll *want* CCTYPE = GCC
337 28 50       50 $opts{CCTYPE} = "GCC" if $opts{GCC_4XX};
338              
339             # If you -Dbccold you 'll *want* CCTYPE = BORLAND
340 28 50       44 $opts{CCTYPE} = "BORLAND" if $opts{BCCOLD};
341              
342 28         20821 printf "* %-25s = %s\n", $_, $opts{$_} for grep $opts{$_}, sort keys %opts;
343              
344 28         176 local (*ORG, *NEW);
345 28 50       88 my $maker = $win32_makefile_map{ $win32_maker }
346             or die "no make file for $win32_maker";
347 28         62 my $in = "win32/$maker";
348 28         34 my $out = "win32/smoke.mk";
349 28 50       907 open(ORG, "<:raw", $in) or die "Cannot line-end-check '$in': $!";
350 28         327 my $dummy = ;
351 28         325 close(ORG); undef(*ORG);
  28         88  
352 28 50       94 my $layer = $dummy =~ /\015\012\Z/ ? ':crlf' : '';
353              
354 28 50       623 open ORG, "<$layer", $in or die "unable to open '$in': $!";
355 28 50       1433 open NEW, ">:crlf", $out or die "unable to open '$out': $!";
356 28         79 my $donot_change = 0;
357 28 50       51 my $check_linkflags = $adjust_ldflags ? 1 : 0;
358 28         346 while () {
359 2450 100       3338 if ( $donot_change ) {
360             # need to help the Win95 build
361 532 100       809 if (m/^\s*CFG_VARS\s*=/) {
362 28 50 66     107 my( $extra_char, $quote ) = ($is_nmake || $is_gmake)
363             ? ( "\t", '"' ) : ("~", "" );
364 28         202 $_ .= join "", map "\t\t$quote$_$quote\t${extra_char}\t\\\n",
365             grep /\w+=/, @args;
366             }
367 532         639 print NEW $_;
368 532         1062 next;
369             } else {
370 1918         2648 $donot_change = /^#+ CHANGE THESE ONLY IF YOU MUST #+/;
371             }
372              
373             # Only change config stuff _above_ that line!
374 1918 100       8966 if ( m/^\s*#?\s*$def_re(\s*[\*:]?=\s*define)$/ ) {
    100          
    100          
    100          
    100          
375 266 100       812 $_ = ($opts{$1} ? "" : "#") . $1 . $2 . "\n";
376             }
377             elsif (m/\s*#?\s*($undef_re)(\s*[*:]?=\s*undef)$/) {
378 28 100       116 $_ = ($opts{$1} ? "#" : "") . "$1$2\n";
379             }
380             elsif (m/^\s*#?\s*(CFG\s*[*:]?=\s*Debug)$/) {
381 28 50       87 $_ = ($opts{USE_DEBUGGING} ? "" : "#") . $1 . "\n";
382             }
383             elsif (m/^\s*#?\s*(BUILD_STATIC)\s*([*:]?=)\s*(.*)$/) {
384 28         97 my( $macro, $op, $mval ) = ( $1, $2, $3);
385 28 100       72 if ( $config_args =~ /-([UD])useshrplib\b/ ) {
386 2 50       14 $_ = ( $1 eq 'D' ? "#" : "" ) . "$macro $op $mval\n";
387             }
388             }
389             elsif (m/^\s*#?\s*(BUILDOPT)\s*([*:]?)=\s*\$\(BUILDOPTEXTRA\)/) {
390 28 100       109 my $prf = $2 ? $2 : '';
391 28 100       51 if ($adjust_ccflags) {
392             # Set BUILDOPTEXTRA to $adjust_ccflags
393 4         17 s/^\s*#\s*//;
394 4         13 $_ = "BUILDOPTEXTRA\t${prf}= $adjust_ccflags\n$_";
395             }
396 28 50       50 if ($adjust_ldflags) {
397 0         0 $_ .= "\n# Additional linker flags\n"
398             . "PRIV_LINK_FLAGS\t${prf}= $adjust_ldflags\n";
399             }
400             }
401             else {
402 1540         4987 foreach my $cfg_var ( grep defined $opts{ $_ }, @w32_opts ) {
403 8018 100       136239 if ( m/^\s*#?\s*($cfg_var\s*(\*|:)?=)\s*(.*)$/ ) {
404 72         232 my ($name, $val) = ($1, $2);
405 72 100 100     277 next if $_ =~ /^#/ and !$opts{ $cfg_var };
406 46 100       123 $_ = $opts{ $cfg_var } ?
407             "$name $opts{ $cfg_var }\n":
408             "#$name $val\n";
409 46         91 last;
410             }
411             }
412             }
413 1918         6411 print NEW $_;
414             }
415 28         254 close ORG;
416 28         1378 close NEW;
417 28         505 return $out;
418             } # Configure_win32
419              
420             =head2 set_vms_rooted_logical( $logical, $dir )
421              
422             This will set a VMS rooted logical like:
423              
424             define/translation=concealed $logical $dir
425              
426             =cut
427              
428             sub set_vms_rooted_logical {
429 0     0 1 0 my( $logical, $dir ) = @_;
430 0 0       0 return unless $^O eq 'VMS';
431              
432 0         0 my $cwd = cwd();
433 0   0     0 $dir ||= $cwd;
434              
435 0 0       0 -d $dir or do {
436 0         0 require File::Path;
437 0         0 File::Path::mkpath( $dir );
438             };
439 0 0       0 chdir $dir or die "Cannot chdir($dir): $!";
440              
441             # On older systems we might exceed the 8-level directory depth limit
442             # imposed by RMS. We get around this with a rooted logical, but we
443             # can't create logical names with attributes in Perl, so we do it
444             # in a DCL subprocess and put it in the job table so the parent sees it.
445              
446 0 0       0 open TSBRL, '> tsbuildrl.com' or die "Error creating DCL-file; $!";
447              
448 0         0 print TSBRL <
449             \$ $logical = F\$PARSE("SYS\$DISK:[]",,,,"NO_CONCEAL")-".][000000"-"]["-"].;"+".]"
450             \$ DEFINE/JOB/NOLOG/TRANSLATION=CONCEALED $logical '$logical'
451             COMMAND
452 0         0 close TSBRL;
453              
454 0         0 my $result = system '@tsbuildrl.com';
455 0         0 1 while unlink 'tsbuildrl.com';
456 0         0 chdir $cwd;
457 0         0 return $result == 0;
458             }
459              
460             =head2 get_cfg_filename( )
461              
462             C tries to find a B and returns it.
463              
464             =cut
465              
466             sub get_cfg_filename {
467 5     5 1 1336 my( $cfg_name ) = @_;
468 5 100 100     85 return $cfg_name if defined $cfg_name && -f $cfg_name;
469              
470 2   33     13 my( $base_dir ) = ( $0 =~ m|^(.*)/| ) || File::Spec->curdir;
471 2         23 $cfg_name = File::Spec->catfile( $base_dir, 'smoke.cfg' );
472 2 50 33     40 return $cfg_name if -f $cfg_name && -s _;
473              
474 2         10 $base_dir = File::Spec->curdir;
475 2         12 $cfg_name = File::Spec->catfile( $base_dir, 'smoke.cfg' );
476 2 50 33     23 return $cfg_name if -f $cfg_name && -s _;
477              
478 2         10 return undef;
479             }
480              
481             =head2 read_logfile( )
482              
483             Read the logfile. If an argument is passed, force to (re)read the log
484             If no argument is passed, return the stored log if available otherwise
485             read the logfile
486              
487             =cut
488              
489             sub read_logfile {
490 16     16 1 78 my ($logfile, $verbose) = @_;
491 16 50       79 return if ! defined $logfile;
492              
493 16 50       616 open my $fh, "<", $logfile or return undef;
494 16         75 my $log = do { local $/; <$fh> };
  16         141  
  16         519  
495 16         151 close $fh;
496              
497 16         41 my $es = eval { decode("utf-8", $log, Encode::FB_CROAK ) };
  16         347  
498 16 50       2228 $@ and eval { $es = decode("cp1252", $log, Encode::FB_CROAK ) };
  0         0  
499 16 50       50 $@ and eval { $es = decode("iso-8859-1", $log, Encode::FB_CROAK ) };
  0         0  
500              
501 16 50       59 warn("Couldn't decode logfile($logfile): $@") if $@;
502 16 50       121 return $@ ? $log : $es;
503             }
504              
505             =head2 grepccmsg( $cc, $logfile, $verbose )
506              
507             This is a port of Jarkko Hietaniemi's grepccerr script.
508              
509             =cut
510              
511             sub grepccmsg {
512 70     70 1 24703 my( $cc, $smokelog, $verbose ) = @_;
513 70 50       230 defined $smokelog or return;
514 70 50 33     634 $cc = 'gcc' if !$cc || $cc eq 'g++' || $cc eq 'clang';
      33        
515 70         1407 my %OS2PAT = (
516             'aix' =>
517             # "foo.c", line n.c: pppp-qqq (W) ...error description...
518             # "foo.c", line n.c: pppp-qqq (S) ...error description...
519             '(^".+?", line \d+\.\d+: \d+-\d+ \([WS]\) .+?$)',
520              
521             'dec_osf' =>
522             # DEC OSF/1, Digital UNIX, Tru64 (notice also VMS)
523             # cc: Warning: foo.c, line nnn: ...error description...(error_tag)
524             # ...error line...
525             # ------^
526             # cc: Error: foo.c, line nnn: ...error description... (error_tag)
527             # ...error line...
528             # ------^
529             '(^cc: (?:Warning|Error): .+?^-*\^$)',
530              
531             'hpux' =>
532             # cc: "foo.c"" line nnn: warning ppp: ...error description...
533             # cc: "foo.c"" line nnn: error ppp: ...error description...
534             '(^cc: ".+?", line \d+: (?:warning|error) \d+: .+?$)',
535              
536             'irix' =>
537             # cc-pppp cc: WARNING File = foo.c, Line = nnnn
538             # ...error description...
539             #
540             # ...error line...
541             # ^
542             # cc-pppp cc: ERROR File = foo.c, Line = nnnn
543             # ...error description...
544             #
545             # ...error line...
546             # ^
547             '^(cc-\d+ cc: (?:WARNING|ERROR) File = .+?, ' .
548             'Line = \d+.+?^\s*\^$)',
549              
550             'solaris' =>
551             # "foo.c", line nnn: warning: ...error description...
552             # "foo.c", line nnn: warning: ...:
553             # ...error description...
554             # "foo.c", line nnn: syntax error ...
555             '(^".+?", line \d+: ' .
556             '(?:warning: (?:(?:.+?:$)?.+?$)|syntax error.+?$))',
557              
558             'vms' => # same compiler as Tru64, different message syntax
559             # ...error line...
560             # ......^
561             # %CC-W-MESSAGEID, ...error description...
562             # at line number nnn in file foo.c
563             '(^\n.+?\n^\.+?\^\n^\%CC-(?:I|W|E|F)-\w+, ' .
564             '.+?\nat line number \d+ in file \S+?$)',
565              
566             'gcc' =>
567             # foo.c: In function `foo':
568             # foo.c:nnn: warning: ...
569             # foo.c: In function `foo':
570             # foo.c:nnn:ppp: warning: ...
571             # Sometimes also the column is mentioned.
572             # foo.c: In function `foo':
573             # foo.c:nnn: error: ...
574             # foo.c(:nn)?: undefined reference to ...
575             '(^(?-s:.+?):(?: In function .+?:$|' .
576             '(?: undefined reference to .+?$)|' .
577             '\d+(?:\:\d+)?: ' . '(?:warning:|error:|note:|invalid) .+?$))',
578              
579             'mswin32' => # MSVC(?:60)*
580             # foo.c : error LNKnnn: error description
581             # full\path\to\fooc.c : fatal error LNKnnn: error description
582             # foo.c(nnn) : warning Cnnn: warning description
583             '(^(?!NMAKE)(?-s:.+?) : (?-s:.+?)\d+: .+?$)',
584              
585             'bcc32' => # BORLAND 5.5 on MSWin32
586             # Warning Wnnn filename line: warning description
587             # Error Ennn:: error description
588             '(^(?:(?:Warning W)|(?:Error E))\d+ .+? \d+: .+?$)',
589              
590             'icc' => # Intel C on Linux
591             # pp_sys.c(4412): warning #num: text
592             # SETi( getpriority(which, who) );
593             # ^
594             '(^.*?\([0-9]+\): (?:warning #[0-9]+|error): .+$)',
595             'icpc' => # Intel C++
596             '(^.*?\([0-9]+\): (?:warning #[0-9]+|error): .+$)',
597             );
598 70 50       275 exists $OS2PAT{ lc $cc } or $cc = 'gcc';
599 70         166 my $pat = $OS2PAT{ lc $cc };
600              
601 70         141 my( $indx, %error ) = ( 1 );
602 70 50       195 if ($smokelog) {
603 70 50       198 $verbose and print "Pattern($cc): /$pat/\n";
604             } else {
605 0         0 $error{ "Couldn't examine logfile for compiler warnings." } = 1;
606             }
607              
608 70         85067 while ($smokelog =~ m/$pat/mg) {
609 1260         2471 (my $msg = $1) =~ s/^\s+//;
610 1260         5505 $msg =~ s/[\s\r\n]+\Z//;
611              
612             # Skip known junk from Configure
613 1260 50       2068 $msg =~ m{^try\.c:[ :0-9]+\bwarning:} and next;
614              
615             # We need to think about this IRIX/$Config{cc} thing
616             # $cc eq "irix" && $Config{cc} =~ m/-n32|-64/ &&
617             # $msg =~ m/cc-(?:1009|1110|1047) / and next;
618              
619 1260   66     8925 $error{ $msg } ||= $indx++;
620             }
621              
622 70         304 my @errors = sort { $error{ $a } <=> $error{ $b } } keys %error;
  264         378  
623              
624 70 100       747 return wantarray ? @errors : \@errors;
625             }
626              
627             =head2 grepnonfatal( $cc, $logfile, $verbose )
628              
629             This is a way to find known failures that do not cause the tests to
630             fail but are important enough to report, like being unable to install
631             manual pages.
632              
633             =cut
634              
635             sub grepnonfatal {
636 68     68 1 15868 my( $cc, $smokelog, $verbose ) = @_;
637 68 50       171 $smokelog or return;
638              
639 68         148 my( $indx, %error ) = ( 1 );
640              
641 68         313 my $kf = qr{
642             # Pod::Man is not available: Can't load module Encode, dynamic loading not available in this perl.
643             (\b (\S+) (?-x: is not available: Can't load module )
644             (\S+?) , (?-x: dynamic loading not available) )
645             }xi;
646              
647 68     1   32719 while ($smokelog =~ m{$kf}g) {
  1         794  
  1         22  
  1         19  
648 24         58 my $fail = $1; # $2 = "Pod::Man", $3 = "Encode"
649              
650 24   66     28292 $error{ $fail } ||= $indx++;
651             }
652              
653 68         22072 my @errors = sort { $error{ $a } <=> $error{ $b } } keys %error;
  0         0  
654              
655 68 100       836 return wantarray ? @errors : \@errors;
656             }
657              
658             =head2 get_local_patches( $ddir )
659              
660             C reads F to scan for the locally
661             applied patches array.
662              
663             =cut
664              
665             sub get_local_patches {
666 82     82 1 7343 my( $ddir, $verbose ) = @_;
667 82   33     245 $ddir = shift || cwd();
668 82         483 my $plevel = catfile( $ddir, 'patchlevel.h' );
669              
670 82         1888 my $logger = Test::Smoke::Logger->new(v => $verbose);
671              
672 82         224 my @lpatches = ( );
673 82         276 local *PLEVEL;
674 82         909 $logger->log_info("Locally applied patches from '%s'", $plevel);
675 82 100       1943 unless ( open PLEVEL, "< $plevel" ) {
676 59         640 $logger->log_warn("open(%s) error: %s", $plevel, $!);
677 59         853 return @lpatches;
678             }
679 23         74 my( $seen, $patchnum );
680 23         415 while ( ) {
681 3945 100       5551 $patchnum = $1 if /#define PERL_PATCHNUM\s+(\d+)/;
682 3945 100 100     5854 $seen && /^\s*,"(.+)"/ and push @lpatches, $1;
683 3945 100       7664 /^\s*static.+?local_patches\[\]/ and $seen++;
684             }
685 23         200 close PLEVEL;
686 23 100       63 if ( defined $patchnum ) {
687             @lpatches = map {
688 2         5 s/^(MAINT|DEVEL)$/$1$patchnum/;
  4         18  
689 4         10 $_;
690             } @lpatches;
691             }
692 23         126 $logger->log_info("Patches: '%s'", join(';', @lpatches));
693 23         136 return @lpatches;
694             }
695              
696             =head2 set_local_patch( $ddir, @descr )
697              
698             Copy the code from F. Older (pre 5.8.1) perls do not
699             have it and it doesn't work on MSWin32.
700              
701             =cut
702              
703             sub set_local_patch {
704 17     17 1 9591 my( $ddir, @descr ) = @_;
705              
706 17         179 my $plh = catfile( $ddir, 'patchlevel.h' );
707 17         94 my $pln = catfile( $ddir, 'patchlevel.new' );
708 17         92 my $plb = catfile( $ddir, 'patchlevel.bak' );
709 17         109 local( *PLIN, *PLOUT );
710 17 50       650 open PLIN, "< $plh" or return 0;
711 17 50       1010 open PLOUT, "> $pln" or return 0;
712 17         76 my $seen=0;
713 17         30 my $done=0;
714 17         484 while ( ) {
715 2588 100 100     4307 if ( /^(\s+),NULL/ and $seen ) {
716 17         31 $done++;
717 17         73 while ( my $c = shift @descr ) {
718 19         264 print PLOUT qq{$1,"$c"\n};
719             }
720             }
721 2588 100       3486 $seen++ if /local_patches\[\]/;
722 2588         4471 print PLOUT;
723             }
724 17         154 close PLIN;
725 17 50       642 close PLOUT or return 0;
726              
727 17 50       65 if ( not $done ) {
728 0         0 require Carp;
729 0         0 Carp::carp("Failed to update patchlevel.h. Content not as expected?");
730 0         0 return 0;
731             }
732              
733 17   33     744 -e $plb and 1 while unlink $plb;
734 17         221 my $errno = "$!";
735 17 50       164 if ( -e $plb ) {
736 0         0 require Carp;
737 0         0 Carp::carp( "Could not unlink $plb : $errno" );
738 0         0 return 0;
739             }
740              
741 17 50       582 unless ( rename $plh, $plb ) {
742 0         0 require Carp;
743 0         0 Carp::carp( "Could not rename $plh to $plb : $!" );
744 0         0 return 0;
745             }
746 17 50       400 unless ( rename $pln, $plh ) {
747 0         0 require Carp;
748 0         0 Carp::carp( "Could not rename '$pln' to '$plh' : $!" );
749 0         0 return 0;
750             }
751              
752 17         125 return 1;
753             }
754              
755             =head2 get_config( $filename )
756              
757             Read and parse the configuration from file, or return the default
758             config.
759              
760             =cut
761              
762             sub get_config {
763 3     3 1 630 my( $config_file ) = @_;
764              
765             return (
766 3 100       19 [ "",
767             "-Dusethreads -Duseithreads"
768             ],
769             [ "",
770             "-Duse64bitint",
771             "-Duse64bitall",
772             "-Duselongdouble",
773             "-Dusemorebits",
774             "-Duse64bitall -Duselongdouble"
775             ],
776             { policy_target => "-DDEBUGGING",
777             args => [ "", "-DDEBUGGING" ]
778             },
779             ) unless defined $config_file;
780              
781 1 50       28 open CONF, "< $config_file" or do {
782 0         0 warn "Can't open '$config_file': $!\nUsing standard configuration";
783 0         0 return get_config( undef );
784             };
785 1         3 my( @conf, @cnf_stack, @target );
786              
787             # Cheat. Force a break marker as a line after the last line.
788 1         33 foreach (, "=") {
789 14 100       30 m/^#/ and next;
790 12 100       32 s/\s+$// if m/\s/; # Blanks, new-lines and carriage returns. M$
791 12 100       21 if (m:^/:) {
792 1         3 m:^/(.*)/$:;
793 1 50       3 defined $1 or die "Policy target line didn't end with '/': '$_'";
794 1         3 push @target, $1;
795 1         1 next;
796             }
797              
798 11 100       18 if (!m/^=/) {
799             # Not a break marker
800 7         11 push @conf, $_;
801 7         8 next;
802             }
803              
804             # Break marker, so process the lines we have.
805 4 50       9 if (@target > 1) {
806             warn "Multiple policy target lines " .
807 0         0 join (", ", map {"'$_'"} @target) . " - will use first";
  0         0  
808             }
809 4         9 my %conf = map { $_ => 1 } @conf;
  7         15  
810 4 50 66     23 if (keys %conf == 1 and exists $conf{""} and !@target) {
      33        
811             # There are only blank lines - treat it as if there were no lines
812             # (Lets people have blank sections in configuration files without
813             # warnings.)
814             # Unless there is a policy target. (substituting '' in place of
815             # target is a valid thing to do.)
816 1         3 @conf = ();
817             }
818              
819 4 100       7 unless (@conf) {
820             # They have no target lines
821 1 50       9 @target and
822             warn "Policy target '$target[0]' has no configuration lines, ".
823             "so it will not be used";
824 1         3 @target = ();
825 1         3 next;
826             }
827              
828 3         9 while (my ($key, $val) = each %conf) {
829 6 50       17 $val > 1 and
830             warn "Configuration line '$key' duplicated $val times";
831             }
832 3         5 my $args = [@conf];
833 3         6 @conf = ();
834 3 100       5 if (@target) {
835 1         3 push @cnf_stack, { policy_target => $target[0], args => $args };
836 1         2 @target = ();
837 1         2 next;
838             }
839              
840 2         17 push @cnf_stack, $args;
841             }
842 1         13 close CONF;
843 1         6 return @cnf_stack;
844             }
845              
846             =head2 get_patch( [$ddir] )
847              
848             Try to find the patchlevel, look for B<.patch> or try to get it from
849             B as a fallback.
850              
851             =cut
852              
853             sub get_patch {
854 12     12 1 6976 my( $ddir ) = @_;
855 12   66     91 $ddir ||= File::Spec->curdir;
856              
857 12         167 my $dot_patch = File::Spec->catfile( $ddir, '.patch' );
858 12         60 local *DOTPATCH;
859 12         32 my $patch_level = '?????';
860 12 100       290 if ( open DOTPATCH, "< $dot_patch" ) {
861 3   50     75 chomp( $patch_level = || '' );
862 3         34 close DOTPATCH;
863              
864 3 50       18 if ( $patch_level ) {
865 3 100       25 if ($patch_level =~ /\s/) {
866 1         6 my ($branch, $sha, $describe) = (split ' ', $patch_level)[0, -2, -1];
867 1         5 (my $short_describe = $describe) =~ s/^GitLive-//;
868 1         7 return [$sha, $short_describe, $branch];
869             }
870 2         17 return [$patch_level];
871             }
872 0         0 return [ '' ];
873             }
874              
875             # There does not seem to be a '.patch', try 'git_version.h'
876             # We are looking for the line: #define PERL_PATCHNUM "v5.21.6-224-g6324db4"
877 9         88 my $git_version_h = File::Spec->catfile($ddir, 'git_version.h');
878 9 100       178 if (open my $gvh, '<', $git_version_h) {
879 2         28 while (my $line = <$gvh>) {
880 14 100       44 if ($line =~ /^#define PERL_PATCHNUM "(.+)"$/) {
881 1         20 return [$1];
882             }
883             }
884 1         10 close $gvh;
885             }
886             # This only applies to
887             # There does not seem to be a '.patch', and we couldn't find git_version.h
888             # Now try 'patchlevel.h'
889             # We are looking for the line: ,"DEVEL19999" (within local_patches[] = {}
890 8         27 local *PATCHLEVEL_H;
891 8         66 my $patchlevel_h = File::Spec->catfile( $ddir, 'patchlevel.h' );
892 8 100       173 if ( open PATCHLEVEL_H, "< $patchlevel_h" ) {
893 5         16 my( $declaration_seen, $patchnum ) = ( 0, 0 );
894 5         94 while ( ) {
895 299 100       444 $patchnum = $1 if /#define PERL_PATCHNUM\s+(\d+)/;
896 299   100     681 $declaration_seen ||= /local_patches\[\]/;
897 299 100 100     763 $declaration_seen &&
898             /^\s+,"(?:(?:DEVEL|MAINT)(\d+)?)|(RC\d+)"/ or next;
899 5   50     26 $patch_level = $patchnum || $1 || $2 || '?????';
900 5 100       13 if ( $patch_level =~ /^RC/ ) {
901 1         4 $patch_level = version_from_patchlevel_h( $ddir ) .
902             "-$patch_level";
903             } else {
904 4 100       13 $patch_level .= $patchnum ? "" : '(+)';
905             }
906             }
907             }
908 8         106 return [ $patch_level ];
909             }
910              
911             =head2 version_from_patchlevel_h( $ddir )
912              
913             C returns a "dotted" version as derived
914             from the F file in the distribution.
915              
916             =cut
917              
918             sub version_from_patchlevel_h {
919 20     20 1 67 my( $ddir ) = @_;
920 20   33     53 $ddir ||= File::Spec->curdir;
921 20         378 my $file = File::Spec->catfile( $ddir, 'patchlevel.h' );
922              
923 20         162 my( $revision, $version, $subversion ) = qw( 5 ? ? );
924 20         77 local *PATCHLEVEL;
925 20 100       411 if ( open PATCHLEVEL, "< $file" ) {
926 5         12 my $patchlevel = do { local $/; };
  5         21  
  5         133  
927 5         50 close PATCHLEVEL;
928              
929 5 100       50 if ( $patchlevel =~ /^#define PATCHLEVEL\s+(\d+)/m ) {
930             # Also support perl < 5.6
931 1         6 $version = sprintf "%03u", $1;
932 1 50       8 $subversion = $patchlevel =~ /^#define SUBVERSION\s+(\d+)/m
933             ? sprintf "%02u", $1 : '??';
934 1         6 return "$revision.$version$subversion";
935             }
936              
937 4 50       38 $revision = $patchlevel =~ /^#define PERL_REVISION\s+(\d+)/m
938             ? $1 : '?';
939 4 50       30 $version = $patchlevel =~ /^#define PERL_VERSION\s+(\d+)/m
940             ? $1 : '?';
941 4 50       31 $subversion = $patchlevel =~ /^#define PERL_SUBVERSION\s+(\d+)/m
942             ? $1 : '?';
943             }
944 19         138 return "$revision.$version.$subversion";
945             }
946              
947             =head2 get_ncpu( $osname )
948              
949             C returns the number of available (online/active/enabled) CPUs.
950              
951             It does this by using some operating system specific trick (usually
952             by running some external command and parsing the output).
953              
954             If it cannot recognize your operating system an empty string is returned.
955             If it can recognize it but the external command failed, C<"? cpus">
956             is returned.
957              
958             In the first case (where we really have no idea how to proceed),
959             also a warning (C) is sent to STDERR.
960              
961             =over
962              
963             =item B
964              
965             If you get the warning C, you will
966             need to help us-- how does one tell the number of available CPUs in
967             your operating system? Sometimes there are several different ways:
968             please try to find the fastest one, and a one that does not require
969             superuser (administrator) rights.
970              
971             Thanks to Jarkko Hietaniemi for donating this!
972              
973             =back
974              
975             =cut
976              
977             sub get_ncpu {
978             # Only *nixy osses need this, so use ':'
979 1     1 1 833 local $ENV{PATH} = "$ENV{PATH}:/usr/sbin:/sbin";
980              
981 1         3 my $cpus = "?";
982             OS_CHECK: {
983 1 50       2 local $_ = shift or return "";
  1         11  
984              
985 1 50       5 /aix/i && do {
986 0         0 my @output = `lsdev -C -c processor -S Available`;
987 0         0 $cpus = scalar @output;
988 0         0 last OS_CHECK;
989             };
990              
991 1 50       5 /(?:darwin|.*bsd)/i && do {
992 0         0 chomp( my @output = `sysctl -n hw.ncpu` );
993 0         0 $cpus = $output[0];
994 0         0 last OS_CHECK;
995             };
996              
997 1 50       3 /hp-?ux/i && do {
998 0         0 my @output = grep /^processor/ => `ioscan -fnkC processor`;
999 0         0 $cpus = scalar @output;
1000 0         0 last OS_CHECK;
1001             };
1002              
1003 1 50       4 /irix/i && do {
1004 0         0 my @output = grep /\s+processors?$/i => `hinv -c processor`;
1005 0         0 $cpus = (split " ", $output[0])[0];
1006 0         0 last OS_CHECK;
1007             };
1008              
1009 1 50       5 /linux/i && do {
1010 1         2 my @output; local *PROC;
  1         3  
1011 1 50       40 if ( open PROC, "< /proc/cpuinfo" ) {
1012 1         415 @output = grep /^processor/ => ;
1013 1         28 close PROC;
1014             }
1015 1 50       6 $cpus = @output ? scalar @output : '';
1016 1         5 last OS_CHECK;
1017             };
1018              
1019 0 0       0 /solaris|sunos|osf/i && do {
1020 0         0 my @output = grep /on-line/ => `psrinfo`;
1021 0         0 $cpus = scalar @output;
1022 0         0 last OS_CHECK;
1023             };
1024              
1025 0 0       0 /mswin32|cygwin/i && do {
1026             $cpus = exists $ENV{NUMBER_OF_PROCESSORS}
1027 0 0       0 ? $ENV{NUMBER_OF_PROCESSORS} : '';
1028 0         0 last OS_CHECK;
1029             };
1030              
1031 0 0       0 /vms/i && do {
1032 0         0 my @output = grep /CPU \d+ is in RUN state/ => `show cpu/active`;
1033 0 0       0 $cpus = @output ? scalar @output : '';
1034 0         0 last OS_CHECK;
1035             };
1036              
1037 0 0       0 /haiku/i && do {
1038 0         0 eval { require Haiku::SysInfo };
  0         0  
1039 0 0       0 if (!$@) {
1040 0         0 my $hsi = Haiku::SysInfo->new();
1041 0         0 $cpus = $hsi->cpu_count();
1042 0         0 last OS_CHECK;
1043             }
1044             };
1045              
1046 0         0 $cpus = "";
1047 0         0 require Carp;
1048 0         0 Carp::carp( "get_ncpu: unknown operationg system" );
1049             }
1050              
1051 1 50       11 return $cpus ? sprintf( "%s cpu%s", $cpus, $cpus ne "1" ? 's' : '' ) : "";
    50          
1052             }
1053              
1054             =head2 get_smoked_Config( $dir, @keys )
1055              
1056             C returns a hash (a listified hash) with the
1057             specified keys. It will try to find F to get those
1058             values, if that cannot be found (make error?) we can try F
1059             which is used to build F.
1060             If F is not there (./Configure error?) we try to get some
1061             fallback information from C and F.
1062              
1063             =cut
1064              
1065             sub get_smoked_Config {
1066 172     172 1 18575 my( $dir, @fields ) = @_;
1067 172         417 my %Config = map { ( lc $_ => undef ) } @fields;
  428         2207  
1068              
1069 172         1085 my $perl_Config_heavy = catfile ($dir, "lib", "Config_heavy.pl");
1070 172         642 my $perl_Config_pm = catfile ($dir, "lib", "Config.pm");
1071 172         618 my $perl_config_sh = catfile( $dir, 'config.sh' );
1072 172         832 local *CONF;
1073 172 100       3691 if ( open CONF, "< $perl_Config_heavy" ) {
1074              
1075 1         22 while () {
1076 15 100       41 if ( m/^(?:
1077             (?:our|my)\ \$[cC]onfig_[sS][hH].*
1078             |
1079             \$_
1080             )\ =\ <<'!END!';/x..m/^!END!/){
1081 8 100       20 m/!END!(?:';)?$/ and next;
1082 6 100       18 m/^([^=]+)='([^']*)'/ or next;
1083 5 50       22 exists $Config{lc $1} and $Config{lc $1} = $2;
1084             }
1085             }
1086 1         9 close CONF;
1087             }
1088             my %conf2 = map {
1089 423         1298 ( $_ => undef )
1090 172         1255 } grep !defined $Config{ $_ } => keys %Config;
1091 172 100       2212 if ( open CONF, "< $perl_Config_pm" ) {
1092              
1093 2         26 while () {
1094 31 100       86 if ( m/^(?:
1095             (?:our|my)\ \$[cC]onfig_[sS][hH].*
1096             |
1097             \$_
1098             )\ =\ <<'!END!';/x..m/^!END!/){
1099 16 100       37 m/!END!(?:';)?$/ and next;
1100 12 100       32 m/^([^=]+)='([^']*)'/ or next;
1101 10 50       40 exists $conf2{lc $1} and $Config{lc $1} = $2;
1102             }
1103             }
1104 2         18 close CONF;
1105             }
1106             %conf2 = map {
1107 413         873 ( $_ => undef )
1108 172         1016 } grep !defined $Config{ $_ } => keys %Config;
1109 172 100       4463 if ( open CONF, "< $perl_config_sh" ) {
1110 144         2843 while ( ) {
1111 444 100       1985 m/^([^=]+)='([^']*)'/ or next; # '
1112 148 100       1736 exists $conf2{ $1} and $Config{ lc $1 } = $2;
1113             }
1114 144         1466 close CONF;
1115             }
1116             %conf2 = map {
1117 312         935 ( $_ => undef )
1118 172         921 } grep !defined $Config{ $_ } => keys %Config;
1119 172 100       636 if ( keys %conf2 ) {
1120             # Fall-back values from POSIX::uname() (not reliable)
1121 119         1169 require POSIX;
1122 119         1510 my( $osname, undef, $osvers, undef, $arch) = POSIX::uname();
1123 119 100       422 $Config{osname} = lc $osname if exists $conf2{osname};
1124 119 100       299 $Config{osvers} = lc $osvers if exists $conf2{osvers};
1125 119 100       262 $Config{archname} = lc $arch if exists $conf2{archname};
1126             $Config{version} = version_from_patchlevel_h( $dir )
1127 119 100       423 if exists $conf2{version};
1128             }
1129              
1130             # There should be no under-bars in perl versions!
1131 172 100       500 exists $Config{version} and $Config{version} =~ s/_/./g;
1132 172         1324 return %Config;
1133             }
1134              
1135             =head2 parse_report_Config( $report )
1136              
1137             C returns a list attributes from a smoke report.
1138              
1139             my( $version, $plevel, $os, $osvers, $archname, $summary, $branch ) =
1140             parse_report_Config( $rpt );
1141              
1142             =cut
1143              
1144             sub parse_report_Config {
1145 10     10 1 5849 my( $report ) = @_;
1146              
1147 10 50       45 my $branch = $report =~ /^Automated.+branch (.+?) / ? $1 : 'blead';
1148 10 50       45 my $version = $report =~ /^Automated.*for(?: branch \S+)? (.+) patch/ ? $1 : '';
1149 10 50       73 my $plevel = $report =~ /^Automated.+?(\S+)$/m
1150             ? $1 : '';
1151 10 50       19 if ( !$plevel ) {
1152 0 0       0 $plevel = $report =~ /^Auto.*patch\s+\S+\s+(\S+)/ ? $1 : '';
1153             }
1154 10 50       43 my $osname = $report =~ /\bon\s+(.*) - / ? $1 : '';
1155 10 50       35 my $osvers = $report =~ /\bon\s+.* - (.*)/? $1 : '';
1156 10         16 $osvers =~ s/\s+\(.*//;
1157 10 50       32 my $archname = $report =~ /:.* \((.*)\)/ ? $1 : '';
1158 10 50       31 my $summary = $report =~ /^Summary: (.*)/m ? $1 : '';
1159              
1160 10         50 return ( $version, $plevel, $osname, $osvers, $archname, $summary, $branch );
1161             }
1162              
1163             =head2 get_regen_headers( $ddir )
1164              
1165             C looks in C<$ddir> to find either
1166             F or F (change 18851).
1167              
1168             Returns undef if not found or a string like C<< $^X "$regen_headers_pl" >>
1169              
1170             =cut
1171              
1172             sub get_regen_headers {
1173 14     14 1 14592 my( $ddir ) = @_;
1174              
1175 14   33     86 $ddir ||= File::Spec->curdir; # Don't smoke in a dir "0"!
1176              
1177 14         429 my $regen_headers_pl = File::Spec->catfile( $ddir, "regen_headers.pl" );
1178              
1179 14 100       315 -f $regen_headers_pl and return qq[$^X "$regen_headers_pl"];
1180              
1181 12         110 $regen_headers_pl = File::Spec->catfile( $ddir, "regen.pl" );
1182 12 100       155 -f $regen_headers_pl and return qq[$^X "$regen_headers_pl"];
1183              
1184 10         48 return; # Should this be "make regen_headers"?
1185             }
1186              
1187             =head2 run_regen_headers( $ddir, $verbose );
1188              
1189             C gets its executable from C
1190             and opens a pipe from it. warn()s on error.
1191              
1192             =cut
1193              
1194             sub run_regen_headers {
1195 0     0 1 0 my( $ddir, $verbose ) = @_;
1196              
1197 0         0 my $regen_headers = get_regen_headers( $ddir );
1198              
1199 0 0       0 defined $regen_headers or do {
1200 0         0 warn "Cannot find a regen_headers script\n";
1201 0         0 return;
1202             };
1203              
1204 0 0       0 $verbose and print "Running [$regen_headers]\n";
1205 0         0 local *REGENH;
1206 0 0       0 if ( open REGENH, "$regen_headers |" ) {
1207 0 0       0 while ( ) { $verbose > 1 and print }
  0         0  
1208 0 0       0 close REGENH or do {
1209 0         0 warn "Error in pipe [$regen_headers]\n";
1210 0         0 return;
1211             }
1212             } else {
1213 0         0 warn "Cannot fork [$regen_headers]\n";
1214 0         0 return;
1215             }
1216 0         0 return 1;
1217             }
1218              
1219             =head2 whereis( $prog )
1220              
1221             Try to find an executable instance of C<$prog> in $ENV{PATH}.
1222              
1223             Rreturns a full file-path (with extension) to it.
1224              
1225             =cut
1226              
1227             sub whereis {
1228 30     30 1 39921 my $prog = shift;
1229 30 50       198 return undef unless $prog; # you shouldn't call it '0'!
1230 30 50       156 $^O eq 'VMS' and return vms_whereis( $prog );
1231 30   50     408 my $logger = Test::Smoke::Logger->new(v => shift || 0);
1232              
1233 30         445 my $p_sep = $Config::Config{path_sep};
1234 30         303 my @path = split /\Q$p_sep\E/, $ENV{PATH};
1235 30   50     240 my @pext = split /\Q$p_sep\E/, $ENV{PATHEXT} || '';
1236 30         88 unshift @pext, '';
1237              
1238 30         84 foreach my $dir ( @path ) {
1239 241         915 $logger->log_debug("Looking in %s for %s", $dir, $prog);
1240 241         375 foreach my $ext ( @pext ) {
1241 241         1506 my $fname = File::Spec->catfile( $dir, "$prog$ext" );
1242 241         711 $logger->log_debug(" check executable %s", $fname);
1243 241 100       3006 if ( -x $fname ) {
1244 18         97 $logger->log_info("Found %s as %s", $prog, $fname);
1245 18         101 return $fname;
1246             #return $fname =~ /\s/ ? qq/"$fname"/ : $fname;
1247             }
1248             }
1249             }
1250 12         75 $logger->log_info("Could not find %s", $prog);
1251 12         57 return '';
1252             }
1253              
1254             =head2 vms_whereis( $prog )
1255              
1256             First look in the SYMBOLS to see if C<$prog> is there.
1257             Next look in the KFE-table C if it is there.
1258             As a last resort we can scan C like we do on *nix/Win32
1259              
1260             =cut
1261              
1262             sub vms_whereis {
1263 0     0 1 0 my $prog = shift;
1264              
1265             # Check SYMBOLS
1266 0         0 eval { require VMS::DCLsym };
  0         0  
1267 0 0       0 if ( $@ ) {
1268 0         0 require Carp;
1269 0         0 Carp::carp( "Oops, cannot load VMS::DCLsym: $@" );
1270             } else {
1271 0         0 my $syms = VMS::DCLsym->new;
1272 0 0       0 return $prog if scalar $syms->getsym( $prog );
1273             }
1274             # Check Known File Entry table (INSTALL LIST)
1275 0         0 my $img_re = '^\s+([\w\$]+);\d+';
1276             my %kfe = map {
1277 0 0       0 my $img = /$img_re/ ? $1 : '';
  0         0  
1278 0         0 ( uc $img => undef )
1279             } grep /$img_re/ => qx/INSTALL LIST/;
1280 0 0       0 return $prog if exists $kfe{ uc $prog };
1281              
1282 0         0 require Config;
1283 0         0 my $dclp_env = 'DCL$PATH';
1284 0   0     0 my $p_sep = $Config::Config{path_sep} || '|';
1285 0   0     0 my @path = split /\Q$p_sep\E/, $ENV{ $dclp_env }||"";
1286 0   0     0 my @pext = ( $Config::Config{exe_ext} || $Config::Config{_exe}, '.COM' );
1287              
1288 0         0 foreach my $dir ( @path ) {
1289 0         0 foreach my $ext ( @pext ) {
1290 0         0 my $fname = File::Spec->catfile( $dir, "$prog$ext" );
1291 0 0       0 if ( -x $fname ) {
1292 0 0       0 return $ext eq '.COM' ? "\@$fname" : "MCR $fname";
1293             }
1294             }
1295             }
1296 0         0 return '';
1297             }
1298              
1299             =head2 clean_filename( $fname )
1300              
1301             C basically returns a vmsify() type of filename for
1302             VMS, and returns an upcase filename for case-ignorant filesystems.
1303              
1304             =cut
1305              
1306             sub clean_filename {
1307 304     304 1 409 my $fname = shift;
1308              
1309 304 50       648 if ( $^O eq 'VMS' ) {
1310 0         0 my @parts = split /[.@#]/, $fname;
1311 0 0       0 if ( @parts > 1 ) {
1312 0   0     0 my $ext = ( pop @parts ) || '';
1313 0         0 $fname = join( "_", @parts ) . ".$ext";
1314             }
1315             }
1316 304 50       914 return $NOCASE ? uc $fname : $fname;
1317             }
1318              
1319             =head2 calc_timeout( $killtime[, $from] )
1320              
1321             C calculates the timeout in seconds.
1322             C<$killtime> can be one of two formats:
1323              
1324             =over 8
1325              
1326             =item B<+hh:mm>
1327              
1328             This format represents a duration and is the easy format as we only need
1329             to translate that to seconds.
1330              
1331             =item B
1332              
1333             This format represents a clock time (localtime). Calculate minutes
1334             from midnight for both C<$killtime> and C, and get
1335             the difference. If C<$from> is omitted, C is used.
1336              
1337             If C<$killtime> is the actual time, the timeout will be 24 hours!
1338              
1339             =back
1340              
1341             =cut
1342              
1343             sub calc_timeout {
1344 9     9 1 2232 my( $killtime, $from ) = @_;
1345 9         11 my $timeout = 0;
1346 9 100       71 if ( $killtime =~ /^\+(\d+):([0-5]?[0-9])$/ ) {
    100          
1347 2         8 $timeout = 60 * (60 * $1 + $2 );
1348             } elsif ( $killtime =~ /^((?:[0-1]?[0-9])|(?:2[0-3])):([0-5]?[0-9])$/ ) {
1349 6 100       17 defined $from or $from = time;
1350 6         237 my $time_min = 60 * $1 + $2;
1351 6         14 my( $now_m, $now_h ) = (localtime $from)[1, 2];
1352 6         410 my $now_min = 60 * $now_h + $now_m;
1353 6         9 my $kill_min = $time_min - $now_min;
1354 6 100       13 $kill_min += 60 * 24 if $kill_min <= 0;
1355 6         10 $timeout = 60 * $kill_min;
1356             }
1357 9         37 return $timeout;
1358             }
1359              
1360             =head2 time_in_hhmm( $diff )
1361              
1362             Create a string telling elapsed time in days, hours, minutes, seconds
1363             from the number of seconds.
1364              
1365             =cut
1366              
1367             sub time_in_hhmm {
1368 133     133 1 4733 my $diff = shift;
1369              
1370             # Only show decimal point for diffs < 5 minutes
1371 133 100       1560 my $digits = $diff =~ /\./ ? $diff < 5*60 ? 3 : 0 : 0;
    100          
1372 133         405 my $days = int( $diff / (24*60*60) );
1373 133         410 $diff -= 24*60*60 * $days;
1374 133         278 my $hour = int( $diff / (60*60) );
1375 133         208 $diff -= 60*60 * $hour;
1376 133         235 my $mins = int( $diff / 60 );
1377 133         205 $diff -= 60 * $mins;
1378 133         454 $diff = sprintf "%.${digits}f", $diff;
1379              
1380 133         207 my @parts;
1381 133 100       332 $days and push @parts, sprintf "%d day%s", $days, $days == 1 ? "" : 's';
    100          
1382 133 100       477 $hour and push @parts, sprintf "%d hour%s", $hour, $hour == 1 ? "" : 's';
    100          
1383 133 100       495 $mins and push @parts, sprintf "%d minute%s",$mins, $mins == 1 ? "" : 's';
    100          
1384 133 100 100     1482 $diff && !$days && !$hour and push @parts, "$diff seconds";
      100        
1385              
1386 133         888 return join " ", @parts;
1387             }
1388              
1389             =head2 do_pod2usage( %pod2usage_options )
1390              
1391             If L is there then call its C.
1392             In the other case, print the general message passed with the C key.
1393              
1394             =cut
1395              
1396             sub do_pod2usage {
1397 0     0 1 0 my %p2u_opt = @_;
1398 0         0 eval { require Pod::Usage };
  0         0  
1399 0 0       0 if ( $@ ) {
1400 0   0     0 my $usage = $p2u_opt{myusage} || <<__EO_USAGE__;
1401             Usage: $0 [options]
1402             __EO_USAGE__
1403 0         0 print <
1404             $usage
1405              
1406             Use 'perldoc $0' for the documentation.
1407             Please install 'Pod::Usage' for easy access to the docs.
1408              
1409             EO_MSG
1410 0 0       0 exit( exists $p2u_opt{exitval} ? $p2u_opt{exitval} : 1 );
1411             } else {
1412 0 0       0 exists $p2u_opt{myusage} and delete $p2u_opt{myusage};
1413 0         0 Pod::Usage::pod2usage( @_ );
1414             }
1415             }
1416              
1417             =head2 skip_config( $config )
1418              
1419             Returns true if this config should be skipped.
1420             C<$config> should be a B object.
1421              
1422             =cut
1423              
1424             sub skip_config {
1425 18     18 1 60 my( $config ) = @_;
1426              
1427 18   100     40 my $skip = $config->has_arg(qw( -Uuseperlio -Dusethreads )) ||
1428             $config->has_arg(qw( -Uuseperlio -Duseithreads )) ||
1429             ( $^O eq 'MSWin32' &&
1430             (( $config->has_arg(qw( -Duseithreads -Dusemymalloc )) &&
1431             !$config->has_arg( '-Uuseimpsys' ) ) ||
1432             ( $config->has_arg(qw( -Dusethreads -Dusemymalloc )) &&
1433             !$config->has_arg( '-Uuseimpsys' ) ))
1434             );
1435 18         68 return $skip;
1436             }
1437              
1438             =head2 skip_filter( $line )
1439              
1440             C returns true if the filter rules apply to C<$line>.
1441              
1442             =cut
1443              
1444             sub skip_filter {
1445 2339     2339 1 16667 local( $_ ) = @_;
1446             # Still to be extended
1447 2339   100     46998 return m,^ *$, ||
1448             m,^\t, ||
1449             m,^PERL=./perl\s+./runtests choose, ||
1450             m,^\s+AutoSplitting, ||
1451             m,^\./miniperl , ||
1452             m,^\s*autosplit_lib, ||
1453             m,^\s*PATH=\S+\s+./miniperl, ||
1454             m,^\s+Making , ||
1455             m,^make\[[12], ||
1456             m,make( TEST_ARGS=)? (_test|TESTFILE=|lib/\w+.pm), ||
1457             m,^make:.*Error\s+\d, ||
1458             m,^\s+make\s+lib/, ||
1459             m,^ *cd t &&, ||
1460             m,^if \(true, ||
1461             m,^else \\, ||
1462             m,^fi$, ||
1463             m,^lib/ftmp-security....File::Temp::_gettemp: Parent directory \((\.|/tmp/)\) is not safe, ||
1464             m,^File::Temp::_gettemp: Parent directory \((\.|/tmp/)\) is not safe, ||
1465             m,^ok$, ||
1466             m,^[-a-zA-Z0-9_/.]+\s*\.*\s*(ok|skipped|skipping test on this platform)$, ||
1467             m,^(xlc|cc_r) -c , ||
1468             # m,^\s+$testdir/, ||
1469             m,^sh mv-if-diff\b, ||
1470             m,File \S+ not changed, ||
1471             m,^(not\s+)?ok\s+\d+\s+[-#]\s+(?i:skip\S*[: ]),i ||
1472             # cygwin
1473             m,^dllwrap: no export definition file provided, ||
1474             m,^dllwrap: creating one. but that may not be what you want, ||
1475             m,^(GNUm|M)akefile:\d+: warning: overriding commands for target `perlmain.o', ||
1476             m,^(GNUm|M)akefile:\d+: warning: ignoring old commands for target `perlmain.o', ||
1477             m,^\s+CCCMD\s+=\s+, ||
1478             # Don't know why BSD's make does this
1479             m,^Extracting .*with variable substitutions, ||
1480             # Or these
1481             m,cc\s+-o\s+perl.*perlmain.o\s+lib/auto/DynaLoader/DynaLoader\.a\s+libperl\.a, ||
1482             m,^\S+ is up to date, ||
1483             m,^( )?### , ||
1484             # Clean up Win32's output
1485             m,^(?:\.\.[/\\])?[\w/\\-]+\.*ok$, ||
1486             m,^(?:\.\.[/\\])?[\w/\\-]+\.*ok\s+\d+(\.\d+)?\s*m?s$, ||
1487             m,^(?:\.\.[/\\])?[\w/\\-]+\.*ok\,\s+\d+/\d+\s+skipped:, ||
1488             m,^(?:\.\.[/\\])?[\w/\\-]+\.*skipped[: ], ||
1489             m,^\t?x?copy , ||
1490             m,\d+\s+[Ff]ile\(s\) copied, ||
1491             m,[/\\](?:mini)?perl\.exe ,||
1492             m,^\t?cd , ||
1493             m,^\b[ng]make\b, ||
1494             m,^\s+\d+/\d+ skipped: , ||
1495             m,^\s+all skipped: , ||
1496             m,^\s*pl2bat\.bat [\w\\]+, ||
1497             m,^Making , ||
1498             m,^Skip , ||
1499             m,^Creating library file: libExtTest\.dll\.a, ||
1500             m,^cc: warning 983: ,
1501             }
1502              
1503             1;
1504              
1505             =head1 COPYRIGHT
1506              
1507             (c) 2001-2014, All rights reserved.
1508              
1509             * H. Merijn Brand
1510             * Nicholas Clark
1511             * Jarkko Hietaniemi
1512             * Abe Timmerman
1513              
1514             This library is free software; you can redistribute it and/or modify
1515             it under the same terms as Perl itself.
1516              
1517             See:
1518              
1519             * ,
1520             *
1521              
1522             This program is distributed in the hope that it will be useful,
1523             but WITHOUT ANY WARRANTY; without even the implied warranty of
1524             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1525              
1526             =cut