#!/usr/bin/env perl # slowcat --- write output slowly, emulating physical serial terminal # Author: Noah Friedman # Created: 2003-01-01 # Public domain # $Id: slowcat,v 2.3 2006/08/11 23:02:48 friedman Exp $ # Commentary: # Code: $^W = 1; # enable warnings use strict; use Getopt::Long; use Symbol; (my $progname = $0) =~ s|.*/||; my $bits_per_sec = $ENV{BAUD} || 9600; # Due to HZ resolution in most kernels, it is unlikely that select will # return in a shorter period of time than 10ms. my $usec_interval_min = 10000; my $usec_interval = $usec_interval_min; sub slowcat ($$$) { my ($fh, $bits_per_sec, $usec_interval) = @_; $usec_interval = $usec_interval_min if $usec_interval < $usec_interval_min; my $bytes_per_sec = $bits_per_sec / 8; my $bytes_per_call = 0; my $sleep_interval; # Try to find a balance between the granularity of the sleep interval and # some roughly integral number of bytes to output with each call. If the # former is too large or the latter too fractional, the output will look # choppy, especially at slower speeds. while ($bytes_per_call < 1 || ($bytes_per_call - int ($bytes_per_call) >= .009)) { $sleep_interval = ($usec_interval++) / 1000000; $bytes_per_call = $bytes_per_sec * $sleep_interval; } $bytes_per_call = int ($bytes_per_call); while (sysread ($fh, $_, $bytes_per_call)) { syswrite (STDOUT, $_, $bytes_per_call); select (undef, undef, undef, $sleep_interval); } } sub usage (@) { print STDERR "$progname: @_\n\n" if @_; print STDERR "Usage: $progname {options} {files}\n Options are: -h, --help You're looking at it. -b, --bps BPS Output BPS bits per second. -i, --sleep-interval USEC Use USEC microseconds of granularity between writes.\n"; exit (1); } sub main () { Getopt::Long::config ('bundling', 'autoabbrev'); GetOptions ("h|help", sub { usage () }, "b|bps=i", \$bits_per_sec, "i|sleep-interval=i", \$usec_interval); # We need to be able to output at least 1 byte at a time. $bits_per_sec = 8 if $bits_per_sec < 8; unless (@ARGV) { slowcat (*STDIN{IO}, $bits_per_sec, $usec_interval); exit (0); } my $fh = gensym; while (@ARGV) { my $filename = shift @ARGV; sysopen ($fh, $filename, 0) || die "$filename: $!"; slowcat ($fh, $bits_per_sec, $usec_interval); close ($fh); } exit (0); } main (); # slowcat ends here