+ next LINE;
+ }
+
+ my ($cmd,$arg) = ($1,$2);
+ $arg =~ s/\r//g;
+
+ # handle the commands
+ if ($cmd =~ /^#/) { #comment
+ } elsif ($cmd eq '> '){ #expected result line
+ print "[TESH/debug] push expected result\n" if $opts{'debug'};
+ push @{$cmd{'out'}}, $arg;
+
+ } elsif ($cmd eq '< ') { # provided input
+ print "[TESH/debug] push provided input\n" if $opts{'debug'};
+ push @{$cmd{'in'}}, $arg;
+
+ } elsif ($cmd eq 'p ') { # comment
+ print "[Tesh/INFO] $arg\n";
+
+ } elsif ($cmd eq '$ ') { # Command
+ # if we have something buffered, run it now
+ if (defined($cmd{'cmd'})) {
+ exec_cmd(\%cmd);
+ %cmd = ();
+ }
+ if ($arg =~ /^ *mkfile /){ # "mkfile" command line
+ die "[TESH/CRITICAL] Output expected from mkfile command!\n" if scalar @{cmd{'out'}};
+
+ $cmd{'arg'} = $arg;
+ $cmd{'arg'} =~ s/ *mkfile //;
+ mkfile_cmd(\%cmd);
+ %cmd = ();
+
+ } elsif ($arg =~ /^ *cd /) {
+ die "[TESH/CRITICAL] Input provided to cd command!\n" if scalar @{cmd{'in'}};
+ die "[TESH/CRITICAL] Output expected from cd command!\n" if scalar @{cmd{'out'}};
+
+ $arg =~ s/^ *cd //;
+ cd_cmd("",$arg);
+ %cmd = ();
+
+ } else { # regular command
+ $cmd{'cmd'} = $arg;
+ $cmd{'file'} = $tesh_file;
+ $cmd{'line'} = $line_num;
+ }
+ }
+ elsif($cmd eq '& '){ # parallel command line
+ $cmd{'background'} = 1;
+ $cmd{'cmd'} = $arg;
+ }
+ elsif($line =~ /^! output sort/){ #output sort
+ $cmd{'sort'} = 1;
+ }
+ elsif($line =~ /^! output ignore/){ #output ignore
+ $cmd{'output ignore'} = 1;
+ }
+ elsif($line =~ /^! expect signal SIGABRT$/) {#expect signal SIGABRT
+ $cmd{'expect'} = "SIGABRT";
+ }
+ elsif($line =~ /^! expect return/){ #expect return
+ $line =~ s/^! expect return //g;
+ $line =~ s/\r//g;
+ $cmd{'return'} = $line;
+ }
+ elsif($line =~ /^! setenv/){ #setenv
+ $line =~ s/^! setenv //g;
+ $line =~ s/\r//g;
+ setenv_cmd($line);
+ }
+ elsif($line =~ /^! include/){ #output sort
+ print color("red"), "[Tesh/CRITICAL] need include";
+ print color("reset"), "\n";
+ die;
+ }
+ elsif($line =~ /^! timeout/){ #timeout
+ $line =~ s/^! timeout //;
+ $line =~ s/\r//g;
+ $cmd{'timeout'} = $line;
+ } else {
+ die "[TESH/CRITICAL] parse error: $line\n";
+ }
+}
+
+# Deal with last command
+if (defined($cmd{'cmd'})) {
+ exec_cmd(\%cmd);
+ %cmd = ();
+}
+
+#my (@a,@b);
+#push @a,"bl1"; push @b,"bl1";
+#push @a,"bl2"; push @b,"bl2";
+#push @a,"bl3"; push @b,"bl3";
+#push @a,"bl4"; push @b,"bl4";
+#push @a,"bl5"; push @b,"bl5";
+#push @a,"bl6"; push @b,"bl6";
+#push @a,"bl7"; push @b,"bl7";
+##push @a,"Perl"; push @b,"ruby";
+#push @a,"END1"; push @b,"END1";
+#push @a,"END2"; push @b,"END2";
+#push @a,"END3"; push @b,"END3";
+#push @a,"END4"; push @b,"END4";
+#push @a,"END5"; push @b,"END5";
+#push @a,"END6"; push @b,"END6";
+#push @a,"END7"; push @b,"END7";
+#print "Identical:\n". build_diff(\@a,\@b);
+
+#@a = (); @b =();
+#push @a,"AZE"; push @b,"EZA";
+#print "Different:\n".build_diff(\@a,\@b);
+
+use Diff qw(diff); # postpone a bit to have time to change INC
+
+sub build_diff {
+ my $res;
+ my $diff = Diff->new(@_);
+
+ $diff->Base( 1 ); # Return line numbers, not indices
+ my $chunk_count = $diff->Next(-1); # Compute the amount of chuncks
+ return "" if ($chunk_count == 1 && $diff->Same());
+ $diff->Reset();
+ while( $diff->Next() ) {
+ my @same = $diff->Same();
+ if ($diff->Same() ) {
+ if ($diff->Next(0) > 1) { # not first chunk: print 2 first lines
+ $res .= ' '.$same[0]."\n" ;
+ $res .= ' '.$same[1]."\n" if (scalar @same>1);
+ }
+ $res .= "...\n" if (scalar @same>2);
+# $res .= $diff->Next(0)."/$chunk_count\n";
+ if ($diff->Next(0) < $chunk_count) { # not last chunk: print 2 last lines
+ $res .= ' '.$same[scalar @same -2]."\n" if (scalar @same>1);
+ $res .= ' '.$same[scalar @same -1]."\n";
+ }
+ }
+ next if $diff->Same();
+ map { $res .= "- $_\n" } $diff->Items(1);
+ map { $res .= "+ $_\n" } $diff->Items(2);
+ }
+ return $res;
+}
+
+