#! /usr/bin/perl
+
+# Copyright (c) 2012-2014. The SimGrid Team.
+# All rights reserved.
+
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
eval 'exec perl -S $0 ${1+"$@"}'
if $running_under_some_shell;
my $path = $0;
my $OS;
my $enable_coverage=0;
+my $sort_prefix = 19;
my $tesh_file;
my $tesh_name;
my $error=0;
my $exitcode=0;
my @bg_cmds;
+my (%environ);
$path =~ s|[^/]*$||;
push @INC,$path;
use Getopt::Long qw(GetOptions);
use strict;
use Term::ANSIColor;
+use Text::ParseWords;
use IPC::Open3;
use IO::File;
$ENV{"PRINTF_EXPONENT_DIGITS"} = "2";
}
-
-sub trim($)
-{
- my $string = shift;
- $string =~ s/^\s+//;
- $string =~ s/\s+$//;
- return $string;
-}
-
-# make sure we received a tesh file
-scalar @ARGV > 0 || die "Usage:\n tesh [*options*] *tesh_file*\n";
-
-#Add current directory to path
-$ENV{PATH} = "$ENV{PATH}:.";
-
##
## Command line option handling
##
+sub var_subst {
+ my ($text, $name, $value) = @_;
+ if ($value) {
+ $text =~ s/\${$name(?::[=-][^}]*)?}/$value/g;
+ $text =~ s/\$$name(\W|$)/$value$1/g;
+ }
+ else {
+ $text =~ s/\${$name:=([^}]*)}/$1/g;
+ $text =~ s/\${$name}//g;
+ $text =~ s/\$$name(\W|$)/$1/g;
+ }
+ return $text;
+}
+
# option handling helper subs
sub cd_cmd {
my $directory=$_[1];
die "[Tesh/CRITICAL] Malformed argument to setenv: expected 'name=value' but got '$_[1]'\n";
}
- if($var =~ /bindir/){
- print "[Tesh/INFO] setenv $var=$ctn\n";
- $bindir = $ctn;
- }
- else
- {
- if($var =~ /srcdir/){
- $srcdir = $ctn;
- }
- else{
- $ENV{$var} = $ctn;
- print "[Tesh/INFO] setenv $var=$ctn\n";
- }
- }
+ print "[Tesh/INFO] setenv $var=$ctn\n";
+ $environ{$var} = $ctn;
}
# Main option parsing sub
}
# cleanup the command line
- if($OS eq "WIN"){
- $cmd{'cmd'} =~ s/\${EXEEXT:=}/.exe/g;
- $cmd{'cmd'} =~ s/\${EXEEXT}/.exe/g;
- $cmd{'cmd'} =~ s/\$EXEEXT/.exe/g;
- }
- else{
- $cmd{'cmd'} =~ s/\${EXEEXT:=}//g;
- }
- $cmd{'cmd'} =~ s/\${bindir:=}/$bindir/g;
- $cmd{'cmd'} =~ s/\${srcdir:=}/$srcdir/g;
- $cmd{'cmd'} =~ s/\${bindir:=.}/$bindir/g;
- $cmd{'cmd'} =~ s/\${srcdir:=.}/$srcdir/g;
- $cmd{'cmd'} =~ s/\${bindir}/$bindir/g;
- $cmd{'cmd'} =~ s/\${srcdir}/$srcdir/g;
-# $cmd{'cmd'} =~ s|^\./||g;
-# $cmd{'cmd'} =~ s|tesh|tesh.pl|g;
- $cmd{'cmd'} =~ s/\(%i:%P@%h\)/\\\(%i:%P@%h\\\)/g;
+ if($OS eq "WIN") {
+ var_subst($cmd{'cmd'}, "EXEEXT", ".exe");
+ } else {
+ var_subst($cmd{'cmd'}, "EXEEXT", "");
+ }
+
+ # substitute environ variables
+ foreach my $key (keys %environ) {
+ $cmd{'cmd'} = var_subst($cmd{'cmd'}, $key, $environ{$key});
+ }
+ # substitute remaining variables, if any
+ while ($cmd{'cmd'} =~ /\${(\w+)(?::[=-][^}]*)?}/) {
+ $cmd{'cmd'} = var_subst($cmd{'cmd'}, $1, "");
+ }
+ while ($cmd{'cmd'} =~ /\$(\w+)/) {
+ $cmd{'cmd'} = var_subst($cmd{'cmd'}, $1, "");
+ }
+
+ # add cfg options
$cmd{'cmd'} .= " $opts{'cfg'}" if (defined($opts{'cfg'}) && length($opts{'cfg'}));
+ # final cleanup
+ $cmd{'cmd'} =~ s/^\s+//;
+ $cmd{'cmd'} =~ s/\s+$//;
+
print "[$tesh_name:$cmd{'line'}] $cmd{'cmd'}\n" ;
###
$cmd{'got'} = IO::File->new_tmpfile;
$cmd{'got'}->autoflush(1);
local *E = $cmd{'got'};
- $cmd{'pid'} = open3(\*CHILD_IN, ">&E", ">&E", $cmd{'cmd'} );
+ $cmd{'pid'} = open3(\*CHILD_IN, ">&E", ">&E",
+ quotewords('\s+', 0, $cmd{'cmd'}));
# push all provided input to executing child
map { print CHILD_IN "$_\n"; } @{$cmd{'in'}};
my @got;
while(defined(my $got=<got>)) {
$got =~ s/\r//g;
- $got =~ s/^( )*//g;
chomp $got;
- $got=trim($got);
- if( $got ne ""){
- if (!($enable_coverage and $got=~ /^profiling:/)){
- push @got, "$got";
- }
- }
+ if (!($enable_coverage and $got=~ /^profiling:/)){
+ push @got, $got;
+ }
}
if ($cmd{'sort'}){
sub mysort{
- $a cmp $b
+ substr($a, 0, $sort_prefix) cmp substr($b, 0, $sort_prefix)
}
- use sort qw(defaults _quicksort); # force quicksort
+ use sort 'stable';
@got = sort mysort @got;
+ while (@got and $got[0] eq "") {
+ shift @got;
+ }
+
#also resort the other one, as perl sort is not the same as the C one used to generate teshes
if(defined($cmd{'out'})){
@{$cmd{'out'}}=sort mysort @{$cmd{'out'}};
+ while (@{$cmd{'out'}} and ${$cmd{'out'}}[0] eq "") {
+ shift @{$cmd{'out'}};
+ }
}
}
}
# Push delayed commands on empty lines
- unless ($line =~ m/^(.).(.*)$/) {
+ unless ($line =~ m/^(.)(.*)$/) {
if (defined($cmd{'cmd'})) {
exec_cmd(\%cmd);
%cmd = ();
}
my ($cmd,$arg) = ($1,$2);
+ $arg =~ s/^ //g;
$arg =~ s/\r//g;
$arg =~ s/\\\\/\\/g;
# handle the commands
if ($cmd =~ /^#/) { #comment
} elsif ($cmd eq '>'){ #expected result line
print "[TESH/debug] push expected result\n" if $opts{'debug'};
- $arg=trim($arg);
- if($arg ne ""){
push @{$cmd{'out'}}, $arg;
- }
} elsif ($cmd eq '<') { # provided input
print "[TESH/debug] push provided input\n" if $opts{'debug'};
%cmd = ();
}
$cmd{'sort'} = 1;
+ if ($line =~ /^!\s*output sort\s+(\d+)/) {
+ $sort_prefix = $1;
+ }
}
elsif($line =~ /^!\s*output ignore/){ #output ignore
if (defined($cmd{'cmd'})) {
$line =~ s/\r//g;
setenv_cmd($line);
}
- elsif($line =~ /^!\s*include/){ #output sort
+ elsif($line =~ /^!\s*include/){ #include
if (defined($cmd{'cmd'})) {
exec_cmd(\%cmd);
%cmd = ();