lexical warnings update for docs and tests (from Paul Marquess)
[p5sagit/p5-mst-13.2.git] / lib / perl5db.pl
index 2314bf7..7c5b0a9 100644 (file)
@@ -2,7 +2,7 @@ package DB;
 
 # Debugger for Perl 5.00x; perl5db.pl patch level:
 
-$VERSION = 1.0403;
+$VERSION = 1.06;
 $header = "perl5db.pl version $VERSION";
 
 # Enhanced by ilya@math.ohio-state.edu (Ilya Zakharevich)
@@ -76,6 +76,8 @@ $header = "perl5db.pl version $VERSION";
 # LineInfo - file or pipe to print line number info to.  If it is a
 # pipe, a short "emacs like" message is used.
 #
+# RemotePort - host:port to connect to on remote host for remote debugging.
+#
 # Example $rcfile: (delete leading hashes!)
 #
 # &parse_options("NonStop=1 LineInfo=db.out");
@@ -179,7 +181,8 @@ $inhibit_exit = $option{PrintRet} = 1;
                  TTY noTTY ReadLine NonStop LineInfo maxTraceLen
                  recallCommand ShellBang pager tkRunning ornaments
                  signalLevel warnLevel dieLevel inhibit_exit
-                 ImmediateStop bareStringify);
+                 ImmediateStop bareStringify
+                 RemotePort);
 
 %optionVars    = (
                 hashDepth      => \$dumpvar::hashDepth,
@@ -197,6 +200,7 @@ $inhibit_exit = $option{PrintRet} = 1;
                 inhibit_exit   => \$inhibit_exit,
                 maxTraceLen    => \$maxtrace,
                 ImmediateStop  => \$ImmediateStop,
+                RemotePort     => \$remoteport,
 );
 
 %optionAction  = (
@@ -216,6 +220,7 @@ $inhibit_exit = $option{PrintRet} = 1;
                  dieLevel      => \&dieLevel,
                  tkRunning     => \&tkRunning,
                  ornaments     => \&ornaments,
+                 RemotePort    => \&RemotePort,
                 );
 
 %optionRequire = (
@@ -296,7 +301,7 @@ if ($notty) {
 
   #require Term::ReadLine;
 
-  if ($^O =~ /cygwin/) {
+  if ($^O eq 'cygwin') {
     # /dev/tty is binary. use stdin for textmode
     undef $console;
   } elsif (-e "/dev/tty") {
@@ -322,19 +327,30 @@ if ($notty) {
 
   $console = $tty if defined $tty;
 
-  if (defined $console) {
-    open(IN,"+<$console") || open(IN,"<$console") || open(IN,"<&STDIN");
-    open(OUT,"+>$console") || open(OUT,">$console") || open(OUT,">&STDERR")
-      || open(OUT,">&STDOUT"); # so we don't dongle stdout
-  } else {
-    open(IN,"<&STDIN");
-    open(OUT,">&STDERR") || open(OUT,">&STDOUT"); # so we don't dongle stdout
-    $console = 'STDIN/OUT';
+  if (defined $remoteport) {
+    require IO::Socket;
+    $OUT = new IO::Socket::INET( Timeout  => '10',
+                                 PeerAddr => $remoteport,
+                                 Proto    => 'tcp',
+                               );
+    if (!$OUT) { die "Could not create socket to connect to remote host."; }
+    $IN = $OUT;
   }
-  # so open("|more") can read from STDOUT and so we don't dingle stdin
-  $IN = \*IN;
+  else {
+    if (defined $console) {
+      open(IN,"+<$console") || open(IN,"<$console") || open(IN,"<&STDIN");
+      open(OUT,"+>$console") || open(OUT,">$console") || open(OUT,">&STDERR")
+        || open(OUT,">&STDOUT");       # so we don't dongle stdout
+    } else {
+      open(IN,"<&STDIN");
+      open(OUT,">&STDERR") || open(OUT,">&STDOUT"); # so we don't dongle stdout
+      $console = 'STDIN/OUT';
+    }
+    # so open("|more") can read from STDOUT and so we don't dingle stdin
+    $IN = \*IN;
 
-  $OUT = \*OUT;
+    $OUT = \*OUT;
+  }
   select($OUT);
   $| = 1;                      # for DB::OUT
   select(STDOUT);
@@ -434,7 +450,7 @@ Debugged program terminated.  Use B<q> to quit or B<R> to restart,
   B<h q>, B<h R> or B<h O> to get additional info.  
 EOP
          $package = 'main';
-         $usercontext = '($@, $!, $,, $/, $\, $^W) = @saved;' .
+         $usercontext = '($@, $!, $^E, $,, $/, $\, $^W) = @saved;' .
            "package $package;";        # this won't let them modify, alas
        } else {
            $sub =~ s/\'/::/;
@@ -514,7 +530,7 @@ EOP
                        }
                        next CMD; };
                    $cmd =~ /^t$/ && do {
-                       ($trace & 1) ? ($trace &= ~1) : ($trace |= 1);
+                       $trace ^= 1;
                        print $OUT "Trace = " .
                            (($trace & 1) ? "on" : "off" ) . "\n";
                        next CMD; };
@@ -581,16 +597,26 @@ EOP
                          }
                      };
                    $cmd =~ s/^l\s+-\s*$/-/;
-                   $cmd =~ /^l\b\s*([\':A-Za-z_][\':\w]*)/ && do {
+                   $cmd =~ /^([lb])\b\s*(\$.*)/s && do {
+                       $evalarg = $2;
+                       my ($s) = &eval;
+                       print($OUT "Error: $@\n"), next CMD if $@;
+                       $s = CvGV_name($s);
+                       print($OUT "Interpreted as: $1 $s\n");
+                       $cmd = "$1 $s";
+                   };
+                   $cmd =~ /^l\b\s*([\':A-Za-z_][\':\w]*(\[.*\])?)/s && do {
                        $subname = $1;
                        $subname =~ s/\'/::/;
                        $subname = $package."::".$subname 
                          unless $subname =~ /::/;
                        $subname = "main".$subname if substr($subname,0,2) eq "::";
-                       @pieces = split(/:/,find_sub($subname));
+                       @pieces = split(/:/,find_sub($subname) || $sub{$subname});
                        $subrange = pop @pieces;
                        $file = join(':', @pieces);
                        if ($file ne $filename) {
+                           print $OUT "Switching to file '$file'.\n"
+                               unless $emacs;
                            *dbline = $main::{'_<' . $file};
                            $max = $#dbline;
                            $filename = $file;
@@ -674,11 +700,14 @@ EOP
                                }
                            }
                        }
+                       
+                       if (not $had_breakpoints{$file} &= ~1) {
+                           delete $had_breakpoints{$file};
+                       }
                      }
                      undef %postponed;
                      undef %postponed_file;
                      undef %break_on_load;
-                     undef %had_breakpoints;
                      next CMD; };
                    $cmd =~ /^L$/ && do {
                      my $file;
@@ -753,7 +782,7 @@ EOP
                          $break_on_load{$::INC{$file}} = 1 if $::INC{$file};
                          $file .= '.pm', redo unless $file =~ /\./;
                        }
-                       $had_breakpoints{$file} = 1;
+                       $had_breakpoints{$file} |= 1;
                        print $OUT "Will stop on load of `@{[join '\', `', sort keys %break_on_load]}'.\n";
                        next CMD; };
                    $cmd =~ /^b\b\s*(postpone|compile)\b\s*([':A-Za-z_][':\w]*)\s*(.*)/ && do {
@@ -766,7 +795,7 @@ EOP
                        $postponed{$subname} = $break 
                          ? "break +0 if $cond" : "compile";
                        next CMD; };
-                   $cmd =~ /^b\b\s*([':A-Za-z_][':\w]*)\s*(.*)/ && do {
+                   $cmd =~ /^b\b\s*([':A-Za-z_][':\w]*(?:\[.*\])?)\s*(.*)/ && do {
                        $subname = $1;
                        $cond = $2 || '1';
                        $subname =~ s/\'/::/;
@@ -777,9 +806,9 @@ EOP
                        ($file,$i) = (find_sub($subname) =~ /^(.*):(.*)$/);
                        $i += 0;
                        if ($i) {
-                           $filename = $file;
-                           *dbline = $main::{'_<' . $filename};
-                           $had_breakpoints{$filename} = 1;
+                           local $filename = $file;
+                           local *dbline = $main::{'_<' . $filename};
+                           $had_breakpoints{$filename} |= 1;
                            $max = $#dbline;
                            ++$i while $dbline[$i] == 0 && $i < $max;
                            $dbline{$i} =~ s/^[^\0]*/$cond/;
@@ -788,21 +817,22 @@ EOP
                        }
                        next CMD; };
                    $cmd =~ /^b\b\s*(\d*)\s*(.*)/ && do {
-                       $i = ($1?$1:$line);
+                       $i = $1 || $line;
                        $cond = $2 || '1';
                        if ($dbline[$i] == 0) {
                            print $OUT "Line $i not breakable.\n";
                        } else {
-                           $had_breakpoints{$filename} = 1;
+                           $had_breakpoints{$filename} |= 1;
                            $dbline{$i} =~ s/^[^\0]*/$cond/;
                        }
                        next CMD; };
-                   $cmd =~ /^d\b\s*(\d+)?/ && do {
-                       $i = ($1?$1:$line);
+                   $cmd =~ /^d\b\s*(\d*)/ && do {
+                       $i = $1 || $line;
                        $dbline{$i} =~ s/^[^\0]*//;
                        delete $dbline{$i} if $dbline{$i} eq '';
                        next CMD; };
                    $cmd =~ /^A$/ && do {
+                     print $OUT "Deleting all actions...\n";
                      my $file;
                      for $file (keys %had_breakpoints) {
                        local *dbline = $main::{'_<' . $file};
@@ -815,6 +845,10 @@ EOP
                                delete $dbline{$i} if $dbline{$i} eq '';
                            }
                        }
+                       
+                       if (not $had_breakpoints{$file} &= ~2) {
+                           delete $had_breakpoints{$file};
+                       }
                      }
                      next CMD; };
                    $cmd =~ /^O\s*$/ && do {
@@ -846,13 +880,19 @@ EOP
                        $pretype = [], next CMD unless $1;
                        $pretype = [$1];
                        next CMD; };
-                   $cmd =~ /^a\b\s*(\d+)(\s+(.*))?/ && do {
-                       $i = $1; $j = $3;
-                       if ($dbline[$i] == 0) {
-                           print $OUT "Line $i may not have an action.\n";
+                   $cmd =~ /^a\b\s*(\d*)\s*(.*)/ && do {
+                       $i = $1 || $line; $j = $2;
+                       if (length $j) {
+                           if ($dbline[$i] == 0) {
+                               print $OUT "Line $i may not have an action.\n";
+                           } else {
+                               $had_breakpoints{$filename} |= 2;
+                               $dbline{$i} =~ s/\0[^\0]*//;
+                               $dbline{$i} .= "\0" . action($j);
+                           }
                        } else {
                            $dbline{$i} =~ s/\0[^\0]*//;
-                           $dbline{$i} .= "\0" . action($j);
+                           delete $dbline{$i} if $dbline{$i} eq '';
                        }
                        next CMD; };
                    $cmd =~ /^n$/ && do {
@@ -868,6 +908,10 @@ EOP
                    $cmd =~ /^c\b\s*([\w:]*)\s*$/ && do {
                        end_report(), next CMD if $finished and $level <= 1;
                        $subname = $i = $1;
+                       #  Probably not needed, since we finish an interactive
+                       #  sub-session anyway...
+                       # local $filename = $filename;
+                       # local *dbline = *dbline;      # XXX Would this work?!
                        if ($i =~ /\D/) { # subroutine name
                            $subname = $package."::".$subname 
                                unless $subname =~ /::/;
@@ -876,7 +920,7 @@ EOP
                            if ($i) {
                                $filename = $file;
                                *dbline = $main::{'_<' . $filename};
-                               $had_breakpoints{$filename}++;
+                               $had_breakpoints{$filename} |= 1;
                                $max = $#dbline;
                                ++$i while $dbline[$i] == 0 && $i < $max;
                            } else {
@@ -1056,7 +1100,7 @@ EOP
                        next CMD; };
                    $cmd =~ /^$rc+\s*(-)?(\d+)?$/ && do {
                        pop(@hist) if length($cmd) > 1;
-                       $i = $1 ? ($#hist-($2?$2:1)) : ($2?$2:$#hist);
+                       $i = $1 ? ($#hist-($2||1)) : ($2||$#hist);
                        $cmd = $hist[$i];
                        print $OUT $cmd, "\n";
                        redo CMD; };
@@ -1238,11 +1282,11 @@ sub save {
 # The following takes its argument via $evalarg to preserve current @_
 
 sub eval {
-    my @res;
+    local @res;                        # 'my' would make it visible from user code
     {
-       my $otrace = $trace;
-       my $osingle = $single;
-       my $od = $^D;
+       local $otrace = $trace;
+       local $osingle = $single;
+       local $od = $^D;
        @res = eval "$usercontext $evalarg;\n"; # '\n' for nice recursive debug
        $trace = $otrace;
        $single = $osingle;
@@ -1271,7 +1315,7 @@ sub postponed_sub {
       $i += $offset;
       local *dbline = $main::{'_<' . $file};
       local $^W = 0;           # != 0 is magical below
-      $had_breakpoints{$file}++;
+      $had_breakpoints{$file} |= 1;
       my $max = $#dbline;
       ++$i until $dbline[$i] != 0 or $i >= $max;
       $dbline{$i} = delete $postponed{$subname};
@@ -1299,7 +1343,7 @@ sub postponed {
     if $break_on_load{$filename};
   print $LINEINFO ' ' x $stack_depth, "Package $filename.\n" if $frame;
   return unless $postponed_file{$filename};
-  $had_breakpoints{$filename}++;
+  $had_breakpoints{$filename} |= 1;
   #%dbline = %{$postponed_file{$filename}}; # Cannot be done: unsufficient magic
   my $key;
   for $key (keys %{$postponed_file{$filename}}) {
@@ -1525,7 +1569,15 @@ sub readline {
   }
   local $frame = 0;
   local $doret = -2;
-  $term->readline(@_);
+  if (ref $OUT and UNIVERSAL::isa($OUT, 'IO::Socket::INET')) {
+    print $OUT @_;
+    my $stuff;
+    $IN->recv( $stuff, 2048 );
+    $stuff;
+  }
+  else {
+    $term->readline(@_);
+  }
 }
 
 sub dump_option {
@@ -1673,6 +1725,14 @@ sub ReadLine {
     $rl;
 }
 
+sub RemotePort {
+    if ($term) {
+        &warn("Too late to set RemotePort, enabled on next 'R'!\n") if @_;
+    }
+    $remoteport = shift if @_;
+    $remoteport;
+}
+
 sub tkRunning {
     if ($ {$term->Features}{tkRunning}) {
         return $term->tkRunning(@_);
@@ -1775,11 +1835,18 @@ B<l> I<min>B<+>I<incr>  List I<incr>+1 lines starting at I<min>.
 B<l> I<min>B<->I<max>  List lines I<min> through I<max>.
 B<l> I<line>           List single I<line>.
 B<l> I<subname>        List first window of lines from subroutine.
+B<l> I<\$var>          List first window of lines from subroutine referenced by I<\$var>.
 B<l>           List next window of lines.
 B<->           List previous window of lines.
 B<w> [I<line>] List window around I<line>.
 B<.>           Return to the executed line.
-B<f> I<filename>       Switch to viewing I<filename>. Must be loaded.
+B<f> I<filename>       Switch to viewing I<filename>. File must be already loaded.
+               I<filename> may be either the full name of the file, or a regular
+               expression matching the full file name:
+               B<f> I</home/me/foo.pl> and B<f> I<oo\\.> may access the same file.
+               Evals (with saved bodies) are considered to be filenames:
+               B<f> I<(eval 7)> and B<f> I<eval 7\\b> access the body of the 7th eval
+               (in the order of execution).
 B</>I<pattern>B</>     Search forwards for I<pattern>; final B</> is optional.
 B<?>I<pattern>B<?>     Search backwards for I<pattern>; final B<?> is optional.
 B<L>           List all breakpoints and actions.
@@ -1791,6 +1858,7 @@ B<b> [I<line>] [I<condition>]
                I<condition> breaks if it evaluates to true, defaults to '1'.
 B<b> I<subname> [I<condition>]
                Set breakpoint at first line of subroutine.
+B<b> I<\$var>          Set breakpoint at first line of subroutine referenced by I<\$var>.
 B<b> B<load> I<filename> Set breakpoint on `require'ing the given file.
 B<b> B<postpone> I<subname> [I<condition>]
                Set breakpoint at first line of subroutine after 
@@ -1800,10 +1868,12 @@ B<b> B<compile> I<subname>
 B<d> [I<line>] Delete the breakpoint for I<line>.
 B<D>           Delete all breakpoints.
 B<a> [I<line>] I<command>
-               Set an action to be done before the I<line> is executed.
+               Set an action to be done before the I<line> is executed;
+               I<line> defaults to the current execution line.
                Sequence is: check for breakpoint/watchpoint, print line
                if necessary, do action, prompt user if necessary,
-               execute expression.
+               execute line.
+B<a> [I<line>] Delete the action for I<line>.
 B<A>           Delete all actions.
 B<W> I<expr>           Add a global watch-expression.
 B<W>           Delete all watch-expressions.
@@ -1823,13 +1893,14 @@ B<O> [I<opt>[B<=>I<val>]] [I<opt>B<\">I<val>B<\">] [I<opt>B<?>]...
     I<signalLevel> I<warnLevel> I<dieLevel>:   level of verbosity;
     I<inhibit_exit>            Allows stepping off the end of the script.
     I<ImmediateStop>           Debugger should stop as early as possible.
+    I<RemotePort>:                     Remote hostname:port for remote debugging
   The following options affect what happens with B<V>, B<X>, and B<x> commands:
     I<arrayDepth>, I<hashDepth>:       print only first N elements ('' for all);
     I<compactDump>, I<veryCompact>:    change style of array and hash dump;
     I<globPrint>:                      whether to print contents of globs;
     I<DumpDBFiles>:            dump arrays holding debugged files;
     I<DumpPackages>:           dump symbol tables of packages;
-    I<DumpReused>:             dump contents of \"reused\" addresses;
+    I<DumpReused>:                     dump contents of \"reused\" addresses;
     I<quote>, I<HighBit>, I<undefPrint>:       change style of string dump;
     I<bareStringify>:          Do not print the overload-stringified value;
   Option I<PrintRet> affects printing of return value after B<r> command,
@@ -1839,11 +1910,12 @@ B<O> [I<opt>[B<=>I<val>]] [I<opt>B<\">I<val>B<\">] [I<opt>B<?>]...
         I<ornaments> affects screen appearance of the command line.
                During startup options are initialized from \$ENV{PERLDB_OPTS}.
                You can put additional initialization options I<TTY>, I<noTTY>,
-               I<ReadLine>, and I<NonStop> there (or use `B<R>' after you set them).
+               I<ReadLine>, I<NonStop>, and I<RemotePort> there (or use
+               `B<R>' after you set them).
 B<<> I<expr>           Define Perl command to run before each prompt.
 B<<<> I<expr>          Add to the list of Perl commands to run before each prompt.
 B<>> I<expr>           Define Perl command to run after each prompt.
-B<>>B<>> I<expr>       Add to the list of Perl commands to run after each prompt.
+B<>>B<>> I<expr>               Add to the list of Perl commands to run after each prompt.
 B<{> I<db_command>     Define debugger command to run before each prompt.
 B<{{> I<db_command>    Add to the list of debugger commands to run before each prompt.
 B<$prc> I<number>      Redo a previous command (default previous command).
@@ -2017,10 +2089,31 @@ sub signalLevel {
   $signalLevel;
 }
 
+sub CvGV_name {
+  my $in = shift;
+  my $name = CvGV_name_or_bust($in);
+  defined $name ? $name : $in;
+}
+
+sub CvGV_name_or_bust {
+  my $in = shift;
+  return if $skipCvGV;         # Backdoor to avoid problems if XS broken...
+  $in = \&$in;                 # Hard reference...
+  eval {require Devel::Peek; 1} or return;
+  my $gv = Devel::Peek::CvGV($in) or return;
+  *$gv{PACKAGE} . '::' . *$gv{NAME};
+}
+
 sub find_sub {
   my $subr = shift;
-  return unless defined &$subr;
   $sub{$subr} or do {
+    return unless defined &$subr;
+    my $name = CvGV_name_or_bust($subr);
+    my $data;
+    $data = $sub{$name} if defined $name;
+    return $data if defined $data;
+
+    # Old stupid way...
     $subr = \&$subr;           # Hard reference
     my $s;
     for (keys %sub) {