In debugging plum, which is now split up into something like 200 files,
I got tired of manually telling vi to switch into whatever function I've
hit a breakpoint for. So I fixed it.
Here's the current setup:
Window 1: de{*filter*} command window
Window 2: program input/output window
Window 3: program source window
You issue breakpoints etc in window 1, your program runs in window 2
(screen-oriented program REALLY need alternate windows while debuging
them), and vi will automatically position itself to the proper line and
file. This means that you can keep hitting return in window 2 and watch
the window 3 cursor bop around. For a REALLY fun time, set trace mode in
window 1. :-)
If you'd like to use this, you should support TIOCSTI, named pipes, and
xterm. It's not in a generic, prettified state, so you'll have to edit
pathnames, etc. But for some applications, it seems worth it.
Here's how I did it: first, you modify perldb to talk to a FIFO if
there's one defined in $perldb_fifo in your environment. Here's the diff
to the existing perldb.pl:
*** /usr/local/lib/perl/perldb.pl Sat Dec 14 16:29:17 1991
--- fifoperldb.pl Mon Feb 10 12:12:02 1992
***************
*** 9,14 ****
--- 9,24 ----
# a do DB'DB(<linenum>); in front of every place that can
# have a breakpoint. It also inserts a do 'perldb.pl' before the first line.
+ if ($fifo = $ENV{'perldb_fifo'}) {
+ unless (-p $fifo) {
+ warn "ignoring non pipe $fifo";
+ undef $fifo;
+ } else {
+ open(FIFO, "> $fifo") || die "can't open $fifo: $!";
+ select((select(FIFO), $| = 1)[0]);
+ }
+ }
+
open(IN, "</dev/tty") || open(IN, "<&STDIN"); # so we don't dingle stdin
open(OUT,">/dev/tty") || open(OUT, ">&STDOUT"); # so we don't dongle stdout
select(OUT);
***************
*** 40,45 ****
--- 50,56 ----
if ($single || $trace || $signal) {
print OUT "$package'" unless $sub =~ /'/;
print OUT "$sub($filename:$line):\t",$dbline[$line];
+ print FIFO "$filename:$line\n" if $fifo;
for ($i = $line + 1; $i <= $max && $dbline[$i] == 0; ++$i) {
last if $dbline[$i] =~ /^\s*(;|}|#|\n)/;
print OUT "$sub($filename:$i):\t",$dbline[$i];
I almost think this should eventually become a standard thing, since
it's so neat, but for now, copy it into a personal file and set
your PERLDB envariable to "require 'fifoperldb.pl';" or whatever.
In order to start a vi with somebody to feed him file and line commands,
you run him through this script:
#!/usr/local/bin/perl
# muxvi.
$TIOCSTI = 0x80017472;
$pgrp = -$$;
if (!fork) {
system "vi";
warn "vi exited $?" if $?;
kill(15, $pgrp);
}
$fifo = $ENV{'perldb_fifo'} || "/tmp/muxpipe.$$";
open(FIFO, "< $fifo") || die "can't open $fifo: $!";
while (<FIFO>) {
s/(.*):(\d+)/:n +$2 $1/;
next if $1 eq '(eval)';
$_ = "$2G" if $1 eq $lastfile;
$lastfile = $1;
&jam($_);
}
&jam("ZZ");
print STDERR "$0: all done\n";
unlink($fifo);
sub jam {
for (split(//, $_[0])) {
ioctl(STDERR, $TIOCSTI, $_) || die "bad TIOCSTI: $!";
}
}
As you see, we keep reading de{*filter*} information from the pipe, and
stuff the appropriate command down vi's throat. The following is
a really ugly hack that works for this program. I've made plum accept a
"-t /dev/ttyp9" kind of option and then do this:
open (STDIN, "< $ttyname") || die "can't open $ttyname: $!";
open (STDOUT, "> $ttyname") || die "can't open $ttyname: $!";
I tried it with simple cmd line i/o redirection, but this didn't
seem to work. (BTW, I've got autowrite set.)
The initial things I jam into the de{*filter*} only make sense for this
program. See below for explanations.
#!/usr/local/bin/perl
# 3db: run debug session in 3 windows
system("stty -echo");
&jam(<<EOJAM);
b main
b de{*filter*}_escape
c
EOJAM
system("stty echo");
open(TMP, ">/tmp/plumdebug.$$");
print TMP <<EOF;
tty > /tmp/plumdebugtty.$$
stty intr undef
echo DEBUGGING
sleep 77777777
EOF
close TMP;
$fifo = "/tmp/muxpipe.$$";
unlink($fifo); system ("mknod $fifo p") && die "mknod failure: $?";
$ENV{'perldb_fifo'} = $fifo;
$ENV{PERLDB} = 'require "../tools/myperldb.pl";' unless defined $ENV{PERLDB};
# XXX: put in your personal db path here, or prese in your environment
system "xterm +ls -ut -n 'perldb source' -e muxvi &";
system "xterm +ls -ut -n 'perldb inferior' -e sh /tmp/plumdebug.$$ 2>/dev/null &";
sleep 1 until -e "/tmp/plumdebugtty.$$";
chop($bugtty = `cat /tmp/plumdebugtty.$$`);
print "slave tty is $bugtty\n";
$SIG{INT} = 'done';
system "perl -d $ARGV[0] -t $bugtty 2>&1 1>$bugtty";
&done;
sub done {
print "\n";
unlink </tmp/plumdebug*>, $fifo;
exit 0;
}
sub jam {
$TIOCSTI = 0x80017472;
for (split(//, $_[0])) {
ioctl(STDERR, $TIOCSTI, $_) || die "bad TIOCSTI: $!";
}
}
Finally, when I build a plum to debug, instead of having everything
merged together, I have everything except main be required:
require './activate_folder.pl';
require './alternate_folder.pl';
require './assert.pl';
require './auto_refile.pl';
require './autoload.pl';
# ...
require './version.pl';
require './warn.pl';
require './yorn.pl';
require './zedzed.pl';
sub de{*filter*}_escape { 0; }
sub main {
# main code starts here
}
&de{*filter*}_escape is just a dummy routine that I have the ESC key bound
to in plum, which allows me to get back to the de{*filter*} at will.
BTW, all your windows go away on a ^C, which is nice, but it does so
even if you're trapping it, which isn't. :-(
--tom