Using Perl to Test External Process STDOUT Piping

Last week, I was introduced to FreePascal and it’s recently released IDE Lazarus. I was made aware of it because I was sniffing around for something that would create native binaries of GUI windows, and that would be very quick to draw up (ideally, as powerful as the Microsoft .NET GUI designer).

Before jumping into the issue that this blog post is about, I’m happy to report that the form designer in Lazarus is top-notch. I think I just found a new rapid-prototyping GUI tool that costs me no money, and minimal time.

Now… onto the pain and embarrassment. I convinced myself that I had an issue where FreePascal’s TProcess component (an adapter class through to external processes) was ignoring its poUsePipes property (the one that ensures piped output from the external process is made available to Pascal as soon as it is generated). The symptoms were no matter what I tried, my long-running external process output wasn’t hitting the GUI memo widget I’d set up until the end of the process.

I built a small isolation test to confirm what I was seeing, and submitted a bug report. It was quickly marked as resolved with a comment that left me feeling very derpy indeed.

Of course! Did I ensure the STDOUT buffer was being flushed after every write? No, I did not! My problem turned out to be the external process, not FreePascal. Now, because I never want to forget this again, I’m leaving myself a note on Perl and flushing STDOUT when I know my utility’s output will be piped to other processes.

Turns out in Perl there a special variable devoted to autoflushing STDOUT whenever something is written to the stream. The toy metronome perl script I wrote and submitted as part of my bug report is reproduced below, with the key line to flush the STDOUT stream appearing on line 7.

#!/usr/local/bin/perl

package ToyMetronome;

use strict;

$| = 1;  # Autoflush, so other processes pipe in the STDOUT stream unbuffered

sub processCommandLineArgs() {
  my (@arguments) = @_;

  my $returnArgs = {
    Ticks => 5
  };

  for (my $argIdx= 0; $argIdx < scalar @arguments; $argIdx++) {
    my $arg = lc($arguments[$argIdx]);

    if ($arg eq "--ticks") {
      if ($argIdx + 1 >= scalar @arguments) {
        print "Error: invalid number of ticks specified.\n";
        exit 1;
      } else {
        $returnArgs->{Ticks} = $arguments[$argIdx + 1];
        $argIdx++;

        if ($returnArgs->{Ticks} !~ /^*\d$/) {
          print "Error: invalid number of ticks specified.\n";
          exit 1;
        }
      }
    }
  }

  return $returnArgs;
}

sub ToyMetronome() {
  my $args = &processCommandLineArgs(@_);

  for(my $tick = 1; $tick <= $args->{Ticks}; $tick++) {
    sleep(1);
    printf "ToyMetronome: tick %d.\n", $tick;
  }
};

####### Application below ########

&ToyMetronome(@ARGV);

If I ever again become suspicious about external processes not piping their output to my utilities, I now have a Perl script where I can knock out whether it’s the external process without first embarrassing myself with spurious bug reports.

Deep-derp learning! It’s the new shiz!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s