X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2Fperl5db.pl;h=63b4381339ce25b8de4c0112074d65c7022164c0;hb=191740791d4b6865c4f2665c148ea4f4d8ec7cc3;hp=0eac57390167ceaa07a8d45d6c5c27a64596b321;hpb=6657d1ba4710621ab81a7d6261844badc687513c;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/perl5db.pl b/lib/perl5db.pl index 0eac573..63b4381 100644 --- a/lib/perl5db.pl +++ b/lib/perl5db.pl @@ -2,17 +2,9 @@ package DB; # Debugger for Perl 5.00x; perl5db.pl patch level: -$VERSION = 1.0403; +$VERSION = 1.07; $header = "perl5db.pl version $VERSION"; -# Enhanced by ilya@math.ohio-state.edu (Ilya Zakharevich) -# Latest version available: ftp://ftp.math.ohio-state.edu/pub/users/ilya/perl - -# modified Perl debugger, to be run from Emacs in perldb-mode -# Ray Lischner (uunet!mntgfx!lisch) as of 5 Nov 1990 -# Johan Vromans -- upgrade to 4.0 pl 10 -# Ilya Zakharevich -- patches after 5.001 (and some before ;-) - # # This file is automatically included if you do perl -d. # It's probably not useful to include this yourself. @@ -33,7 +25,7 @@ $header = "perl5db.pl version $VERSION"; # if caller() is called from the package DB, it provides some # additional data. # -# The array @{$main::{'_<'.$filename} is the line-by-line contents of +# The array @{$main::{'_<'.$filename}} is the line-by-line contents of # $filename. # # The hash %{'_<'.$filename} contains breakpoints and action (it is @@ -42,7 +34,7 @@ $header = "perl5db.pl version $VERSION"; # interpreter, though the values used by perl5db.pl have the form # "$break_condition\0$action". Values are magical in numeric context. # -# The scalar ${'_<'.$filename} contains "_<$filename". +# The scalar ${'_<'.$filename} contains $filename. # # Note that no subroutine call is possible until &DB::sub is defined # (for subroutines defined outside of the package DB). In fact the same is @@ -76,6 +68,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"); @@ -86,6 +80,15 @@ $header = "perl5db.pl version $VERSION"; # reset LineInfo to something "interactive"!) # ################################################################## + +# Enhanced by ilya@math.ohio-state.edu (Ilya Zakharevich) +# Latest version available: ftp://ftp.math.ohio-state.edu/pub/users/ilya/perl + +# modified Perl debugger, to be run from Emacs in perldb-mode +# Ray Lischner (uunet!mntgfx!lisch) as of 5 Nov 1990 +# Johan Vromans -- upgrade to 4.0 pl 10 +# Ilya Zakharevich -- patches after 5.001 (and some before ;-) + # Changelog: # A lot of things changed after 0.94. First of all, core now informs @@ -142,6 +145,48 @@ $header = "perl5db.pl version $VERSION"; # `b load' strips trailing whitespace. # completion ignores leading `|'; takes into account current package # when completing a subroutine name (same for `l'). +# Changes: 1.07: Many fixed by tchrist 13-March-2000 +# BUG FIXES: +# + Added bare mimimal security checks on perldb rc files, plus +# comments on what else is needed. +# + Fixed the ornaments that made "|h" completely unusable. +# They are not used in print_help if they will hurt. Strip pod +# if we're paging to less. +# + Fixed mis-formatting of help messages caused by ornaments +# to restore Larry's original formatting. +# + Fixed many other formatting errors. The code is still suboptimal, +# and needs a lot of work at restructuing. It's also misindented +# in many places. +# + Fixed bug where trying to look at an option like your pager +# shows "1". +# + Fixed some $? processing. Note: if you use csh or tcsh, you will +# lose. You should consider shell escapes not using their shell, +# or else not caring about detailed status. This should really be +# unified into one place, too. +# + Fixed bug where invisible trailing whitespace on commands hoses you, +# tricking Perl into thinking you wern't calling a debugger command! +# + Fixed bug where leading whitespace on commands hoses you. (One +# suggests a leading semicolon or any other irrelevant non-whitespace +# to indicate literal Perl code.) +# + Fixed bugs that ate warnings due to wrong selected handle. +# + Fixed a precedence bug on signal stuff. +# + Fixed some unseemly wording. +# + Fixed bug in help command trying to call perl method code. +# + Fixed to call dumpvar from exception handler. SIGPIPE killed us. +# ENHANCEMENTS: +# + Added some comments. This code is still nasty spaghetti. +# + Added message if you clear your pre/post command stacks which was +# very easy to do if you just typed a bare >, <, or {. (A command +# without an argument should *never* be a destructive action; this +# API is fundamentally screwed up; likewise option setting, which +# is equally buggered.) +# + Added command stack dump on argument of "?" for >, <, or {. +# + Added a semi-built-in doc viewer command that calls man with the +# proper %Config::Config path (and thus gets caching, man -k, etc), +# or else perldoc on obstreperous platforms. +# + Added to and rearranged the help information. +# + Detected apparent misuse of { ... } to declare a block; this used +# to work but now is a command, and mysteriously gave no complaint. #################################################################### @@ -179,7 +224,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 +243,7 @@ $inhibit_exit = $option{PrintRet} = 1; inhibit_exit => \$inhibit_exit, maxTraceLen => \$maxtrace, ImmediateStop => \$ImmediateStop, + RemotePort => \$remoteport, ); %optionAction = ( @@ -216,6 +263,7 @@ $inhibit_exit = $option{PrintRet} = 1; dieLevel => \&dieLevel, tkRunning => \&tkRunning, ornaments => \&ornaments, + RemotePort => \&RemotePort, ); %optionRequire = ( @@ -225,43 +273,93 @@ $inhibit_exit = $option{PrintRet} = 1; ); # These guys may be defined in $ENV{PERL5DB} : -$rl = 1 unless defined $rl; -$warnLevel = 1 unless defined $warnLevel; -$dieLevel = 1 unless defined $dieLevel; -$signalLevel = 1 unless defined $signalLevel; -$pre = [] unless defined $pre; -$post = [] unless defined $post; -$pretype = [] unless defined $pretype; +$rl = 1 unless defined $rl; +$warnLevel = 0 unless defined $warnLevel; +$dieLevel = 0 unless defined $dieLevel; +$signalLevel = 1 unless defined $signalLevel; +$pre = [] unless defined $pre; +$post = [] unless defined $post; +$pretype = [] unless defined $pretype; + warnLevel($warnLevel); dieLevel($dieLevel); signalLevel($signalLevel); -&pager((defined($ENV{PAGER}) + +&pager( + (defined($ENV{PAGER}) ? $ENV{PAGER} : ($^O eq 'os2' ? 'cmd /c more' : 'more'))) unless defined $pager; +setman(); &recallCommand("!") unless defined $prc; &shellBang("!") unless defined $psh; $maxtrace = 400 unless defined $maxtrace; -if (-e "/dev/tty") { +if (-e "/dev/tty") { # this is the wrong metric! $rcfile=".perldb"; } else { $rcfile="perldb.ini"; } +# This isn't really safe, because there's a race +# between checking and opening. The solution is to +# open and fstat the handle, but then you have to read and +# eval the contents. But then the silly thing gets +# your lexical scope, which is unfortunately at best. +sub safe_do { + my $file = shift; + + # Just exactly what part of the word "CORE::" don't you understand? + local $SIG{__WARN__}; + local $SIG{__DIE__}; + + unless (is_safe_file($file)) { + CORE::warn <$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 "Unable to connect to remote host: $remoteport\n"; } + $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); @@ -347,10 +462,10 @@ if ($notty) { $header =~ s/.Header: ([^,]+),v(\s+\S+\s+\S+).*$/$1$2/; unless ($runnonstop) { print $OUT "\nLoading DB routines from $header\n"; - print $OUT ("Emacs support ", - $emacs ? "enabled" : "available", + print $OUT ("Editor support ", + $slave_editor ? "enabled" : "available", ".\n"); - print $OUT "\nEnter h or `h h' for help.\n\n"; + print $OUT "\nEnter h or `h h' for help, or `$doccmd perldebug' for more help.\n\n"; } } @@ -423,7 +538,7 @@ EOP $was_signal = $signal; $signal = 0; if ($single || ($trace & 1) || $was_signal) { - if ($emacs) { + if ($slave_editor) { $position = "\032\032$filename:$line:0\n"; print $LINEINFO $position; } elsif ($package eq 'DB::fake') { @@ -434,7 +549,7 @@ Debugged program terminated. Use B to quit or B to restart, B, B or B 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/\'/::/; @@ -484,7 +599,8 @@ EOP ($term_pid == $$ or &resetterm), defined ($cmd=&readline(" DB" . ('<' x $level) . ($#hist+1) . ('>' x $level) . - " "))) { + " "))) + { $single = 0; $signal = 0; $cmd =~ s/\\$/\n/ && do { @@ -494,19 +610,34 @@ EOP $cmd =~ /^$/ && ($cmd = $laststep); push(@hist,$cmd) if length($cmd) > 1; PIPE: { + $cmd =~ s/^\s+//s; # trim annoying leading whitespace + $cmd =~ s/\s+$//s; # trim annoying trailing whitespace ($i) = split(/\s+/,$cmd); - eval "\$cmd =~ $alias{$i}", print $OUT $@ if $alias{$i}; - $cmd =~ /^q$/ && ($exiting = 1) && exit 0; + if ($alias{$i}) { + # squelch the sigmangler + local $SIG{__DIE__}; + local $SIG{__WARN__}; + eval "\$cmd =~ $alias{$i}"; + if ($@) { + print $OUT "Couldn't evaluate `$i' alias: $@"; + next CMD; + } + } + $cmd =~ /^q$/ && ($fall_off_end = 1) && exit $?; $cmd =~ /^h$/ && do { print_help($help); next CMD; }; $cmd =~ /^h\s+h$/ && do { print_help($summary); next CMD; }; - $cmd =~ /^h\s+(\S)$/ && do { - my $asked = "\Q$1"; - if ($help =~ /^(?:[IB]<)$asked/m) { - while ($help =~ /^((?:[IB]<)$asked([\s\S]*?)\n)(?!\s)/mg) { + # support long commands; otherwise bogus errors + # happen when you ask for h on for example + $cmd =~ /^h\s+(\S.*)$/ && do { + my $asked = $1; # for proper errmsg + my $qasked = quotemeta($asked); # for searching + # XXX: finds CR but not + if ($help =~ /^\s*(.*)/ && do { - $post = [], next CMD unless $1; + unless ($1) { + print $OUT "All > actions cleared.\n"; + $post = []; + next CMD; + } + if ($1 eq '?') { + unless (@$post) { + print $OUT "No post-prompt Perl actions.\n"; + next CMD; + } + print $OUT "Perl commands run after each prompt:\n"; + for my $action ( @$post ) { + print $OUT "\t> -- $action\n"; + } + next CMD; + } $post = [action($1)]; next CMD; }; $cmd =~ /^\{\{\s*(.*)/ && do { + if ($cmd =~ /^\{.*\}$/ && unbalanced(substr($cmd,2))) { + print $OUT "{{ is now a debugger command\n", + "use `;{{' if you mean Perl code\n"; + $cmd = "h {{"; + redo CMD; + } push @$pretype, $1; next CMD; }; $cmd =~ /^\{\s*(.*)/ && do { - $pretype = [], next CMD unless $1; + unless ($1) { + print $OUT "All { actions cleared.\n"; + $pretype = []; + next CMD; + } + if ($1 eq '?') { + unless (@$pretype) { + print $OUT "No pre-prompt debugger actions.\n"; + next CMD; + } + print $OUT "Debugger commands run before each prompt:\n"; + for my $action ( @$pretype ) { + print $OUT "\t{ -- $action\n"; + } + next CMD; + } + if ($cmd =~ /^\{.*\}$/ && unbalanced(substr($cmd,1))) { + print $OUT "{ is now a debugger command\n", + "use `;{' if you mean Perl code\n"; + $cmd = "h {"; + redo CMD; + } $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 +1088,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 +1100,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 { @@ -913,7 +1137,7 @@ EOP set_list("PERLDB_INC", @ini_INC); if ($0 eq '-e') { for (1..$#{'::_<-e'}) { # The first line is PERL5DB - chomp ($cl = $ {'::_<-e'}[$_]); + chomp ($cl = ${'::_<-e'}[$_]); push @script, '-e', $cl; } } else { @@ -977,8 +1201,8 @@ EOP set_list("PERLDB_POST", @$post); set_list("PERLDB_TYPEAHEAD", @typeahead); $ENV{PERLDB_RESTART} = 1; - #print "$^X, '-d', @flags, @script, ($emacs ? '-emacs' : ()), @ARGS"; - exec $^X, '-d', @flags, @script, ($emacs ? '-emacs' : ()), @ARGS; + #print "$^X, '-d', @flags, @script, ($slave_editor ? '-emacs' : ()), @ARGS"; + exec $^X, '-d', @flags, @script, ($slave_editor ? '-emacs' : ()), @ARGS; print $OUT "exec failed: $!\n"; last CMD; }; $cmd =~ /^T$/ && do { @@ -1000,6 +1224,9 @@ EOP $inpat = $1; $inpat =~ s:([^\\])/$:$1:; if ($inpat ne "") { + # squelch the sigmangler + local $SIG{__DIE__}; + local $SIG{__WARN__}; eval '$inpat =~ m'."\a$inpat\a"; if ($@ ne "") { print $OUT "$@"; @@ -1015,7 +1242,7 @@ EOP $start = 1 if ($start > $max); last if ($start == $end); if ($dbline[$start] =~ m' . "\a$pat\a" . 'i) { - if ($emacs) { + if ($slave_editor) { print $OUT "\032\032$filename:$start:0\n"; } else { print $OUT "$start:\t", $dbline[$start], "\n"; @@ -1029,9 +1256,12 @@ EOP $inpat = $1; $inpat =~ s:([^\\])\?$:$1:; if ($inpat ne "") { + # squelch the sigmangler + local $SIG{__DIE__}; + local $SIG{__WARN__}; eval '$inpat =~ m'."\a$inpat\a"; if ($@ ne "") { - print $OUT "$@"; + print $OUT $@; next CMD; } $pat = $inpat; @@ -1044,7 +1274,7 @@ EOP $start = $max if ($start <= 0); last if ($start == $end); if ($dbline[$start] =~ m' . "\a$pat\a" . 'i) { - if ($emacs) { + if ($slave_editor) { print $OUT "\032\032$filename:$start:0\n"; } else { print $OUT "$start:\t", $dbline[$start], "\n"; @@ -1056,7 +1286,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; }; @@ -1080,31 +1310,56 @@ EOP &system($ENV{SHELL}||"/bin/sh"); next CMD; }; $cmd =~ /^$sh\s*([\x00-\xff]*)/ && do { + # XXX: using csh or tcsh destroys sigint retvals! + #&system($1); # use this instead &system($ENV{SHELL}||"/bin/sh","-c",$1); next CMD; }; $cmd =~ /^H\b\s*(-(\d+))?/ && do { - $end = $2?($#hist-$2):0; + $end = $2 ? ($#hist-$2) : 0; $hist = 0 if $hist < 0; for ($i=$#hist; $i>$end; $i--) { print $OUT "$i: ",$hist[$i],"\n" unless $hist[$i] =~ /^.?$/; }; next CMD; }; + $cmd =~ /^(?:man|(?:perl)?doc)\b(?:\s+([^(]*))?$/ && do { + runman($1); + next CMD; }; $cmd =~ s/^p$/print {\$DB::OUT} \$_/; $cmd =~ s/^p\b/print {\$DB::OUT} /; - $cmd =~ /^=/ && do { - if (local($k,$v) = ($cmd =~ /^=\s*(\S+)\s+(.*)/)) { - $alias{$k}="s~$k~$v~"; - print $OUT "$k = $v\n"; - } elsif ($cmd =~ /^=\s*$/) { - foreach $k (sort keys(%alias)) { - if (($v = $alias{$k}) =~ s~^s\~$k\~(.*)\~$~$1~) { - print $OUT "$k = $v\n"; - } else { + $cmd =~ s/^=\s*// && do { + my @keys; + if (length $cmd == 0) { + @keys = sort keys %alias; + } + elsif (my($k,$v) = ($cmd =~ /^(\S+)\s+(\S.*)/)) { + # can't use $_ or kill //g state + for my $x ($k, $v) { $x =~ s/\a/\\a/g } + $alias{$k} = "s\a$k\a$v\a"; + # squelch the sigmangler + local $SIG{__DIE__}; + local $SIG{__WARN__}; + unless (eval "sub { s\a$k\a$v\a }; 1") { + print $OUT "Can't alias $k to $v: $@\n"; + delete $alias{$k}; + next CMD; + } + @keys = ($k); + } + else { + @keys = ($cmd); + } + for my $k (@keys) { + if ((my $v = $alias{$k}) =~ ss\a$k\a(.*)\a$1) { + print $OUT "$k\t= $1\n"; + } + elsif (defined $alias{$k}) { print $OUT "$k\t$alias{$k}\n"; - }; - }; - }; + } + else { + print "No alias for $k\n"; + } + } next CMD; }; $cmd =~ /^\|\|?\s*[^|]/ && do { if ($pager =~ /^\|/) { @@ -1113,25 +1368,29 @@ EOP } else { open(SAVEOUT,">&OUT") || &warn("Can't save DB::OUT"); } + fix_less(); unless ($piped=open(OUT,$pager)) { &warn("Can't pipe output to `$pager'"); if ($pager =~ /^\|/) { - open(OUT,">&STDOUT") || &warn("Can't restore DB::OUT"); + open(OUT,">&STDOUT") # XXX: lost message + || &warn("Can't restore DB::OUT"); open(STDOUT,">&SAVEOUT") || &warn("Can't restore STDOUT"); close(SAVEOUT); } else { - open(OUT,">&STDOUT") || &warn("Can't restore DB::OUT"); + open(OUT,">&STDOUT") # XXX: lost message + || &warn("Can't restore DB::OUT"); } next CMD; } $SIG{PIPE}= \&DB::catch if $pager =~ /^\|/ - && "" eq $SIG{PIPE} || "DEFAULT" eq $SIG{PIPE}; + && ("" eq $SIG{PIPE} || "DEFAULT" eq $SIG{PIPE}); $selected= select(OUT); $|= 1; select( $selected ), $selected= "" unless $cmd =~ /^\|\|/; $cmd =~ s/^\|+\s*//; - redo PIPE; }; + redo PIPE; + }; # XXX Local variants do not work! $cmd =~ s/^t\s/\$DB::trace |= 1;\n/; $cmd =~ s/^s\s/\$DB::single = 1;\n/ && do {$laststep = 's'}; @@ -1146,14 +1405,27 @@ EOP } continue { # CMD: if ($piped) { if ($pager =~ /^\|/) { - $?= 0; close(OUT) || &warn("Can't close DB::OUT"); - &warn( "Pager `$pager' failed: ", - ($?>>8) > 128 ? ($?>>8)-256 : ($?>>8), - ( $? & 128 ) ? " (core dumped)" : "", - ( $? & 127 ) ? " (SIG ".($?&127).")" : "", "\n" ) if $?; + $? = 0; + # we cannot warn here: the handle is missing --tchrist + close(OUT) || print SAVEOUT "\nCan't close DB::OUT\n"; + + # most of the $? crud was coping with broken cshisms + if ($?) { + print SAVEOUT "Pager `$pager' failed: "; + if ($? == -1) { + print SAVEOUT "shell returned -1\n"; + } elsif ($? >> 8) { + print SAVEOUT + ( $? & 127 ) ? " (SIG#".($?&127).")" : "", + ( $? & 128 ) ? " -- core dumped" : "", "\n"; + } else { + print SAVEOUT "status ", ($? >> 8), "\n"; + } + } + open(OUT,">&STDOUT") || &warn("Can't restore DB::OUT"); open(STDOUT,">&SAVEOUT") || &warn("Can't restore STDOUT"); - $SIG{PIPE}= "DEFAULT" if $SIG{PIPE} eq \&DB::catch; + $SIG{PIPE} = "DEFAULT" if $SIG{PIPE} eq \&DB::catch; # Will stop ignoring SIGPIPE if done like nohup(1) # does SIGINT but Perl doesn't give us a choice. } else { @@ -1164,7 +1436,7 @@ EOP $piped= ""; } } # CMD: - $exiting = 1 unless defined $cmd; + $fall_off_end = 1 unless defined $cmd; # Emulate `q' on EOF foreach $evalarg (@$post) { &eval; } @@ -1238,11 +1510,14 @@ sub save { # The following takes its argument via $evalarg to preserve current @_ sub eval { - my @res; + # 'my' would make it visible from user code + # but so does local! --tchrist + local @res; { - my $otrace = $trace; - my $osingle = $single; - my $od = $^D; + local $otrace = $trace; + local $osingle = $single; + local $od = $^D; + { ($evalarg) = $evalarg =~ /(.*)/s; } @res = eval "$usercontext $evalarg;\n"; # '\n' for nice recursive debug $trace = $otrace; $single = $osingle; @@ -1271,7 +1546,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,11 +1574,11 @@ 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}}) { - $dbline{$key} = $ {$postponed_file{$filename}}{$key}; + $dbline{$key} = ${$postponed_file{$filename}}{$key}; } delete $postponed_file{$filename}; } @@ -1419,27 +1694,50 @@ sub action { $action; } +sub unbalanced { + # i hate using globals! + $balanced_brace_re ||= qr{ + ^ \{ + (?: + (?> [^{}] + ) # Non-parens without backtracking + | + (??{ $balanced_brace_re }) # Group with matching parens + ) * + \} $ + }x; + return $_[0] !~ m/$balanced_brace_re/; +} + sub gets { - local($.); - #; &readline("cont: "); } sub system { # We save, change, then restore STDIN and STDOUT to avoid fork() since - # many non-Unix systems can do system() but have problems with fork(). + # some non-Unix systems can do system() but have problems with fork(). open(SAVEIN,"<&STDIN") || &warn("Can't save STDIN"); open(SAVEOUT,">&STDOUT") || &warn("Can't save STDOUT"); open(STDIN,"<&IN") || &warn("Can't redirect STDIN"); open(STDOUT,">&OUT") || &warn("Can't redirect STDOUT"); + + # XXX: using csh or tcsh destroys sigint retvals! system(@_); open(STDIN,"<&SAVEIN") || &warn("Can't restore STDIN"); open(STDOUT,">&SAVEOUT") || &warn("Can't restore STDOUT"); - close(SAVEIN); close(SAVEOUT); - &warn( "(Command returned ", ($?>>8) > 128 ? ($?>>8)-256 : ($?>>8), ")", - ( $? & 128 ) ? " (core dumped)" : "", - ( $? & 127 ) ? " (SIG ".($?&127).")" : "", "\n" ) if $?; - $?; + close(SAVEIN); + close(SAVEOUT); + + + # most of the $? crud was coping with broken cshisms + if ($? >> 8) { + &warn("(Command exited ", ($? >> 8), ")\n"); + } elsif ($?) { + &warn( "(Command died of SIG#", ($? & 127), + (($? & 128) ? " -- core dumped" : "") , ")", "\n"); + } + + return $?; + } sub setterm { @@ -1456,7 +1754,7 @@ sub setterm { $| = 1; select($sel); } else { - eval "require Term::Rendezvous;" or die $@; + eval "require Term::Rendezvous;" or die; my $rv = $ENV{PERLDB_NOTTY} || "/tmp/perldbtty$$"; my $term_rv = new Term::Rendezvous $rv; $IN = $term_rv->IN; @@ -1515,6 +1813,7 @@ EOP } sub readline { + local $.; if (@typeahead) { my $left = @typeahead; my $got = shift @typeahead; @@ -1525,7 +1824,15 @@ sub readline { } local $frame = 0; local $doret = -2; - $term->readline(@_); + if (ref $OUT and UNIVERSAL::isa($OUT, 'IO::Socket::INET')) { + $OUT->write(join('', @_)); + my $stuff; + $IN->recv( $stuff, 2048 ); # XXX: what's wrong with sysread? + $stuff; + } + else { + $term->readline(@_); + } } sub dump_option { @@ -1539,15 +1846,15 @@ sub option_val { my ($opt, $default)= @_; my $val; if (defined $optionVars{$opt} - and defined $ {$optionVars{$opt}}) { - $val = $ {$optionVars{$opt}}; + and defined ${$optionVars{$opt}}) { + $val = ${$optionVars{$opt}}; } elsif (defined $optionAction{$opt} and defined &{$optionAction{$opt}}) { $val = &{$optionAction{$opt}}(); } elsif (defined $optionAction{$opt} and not defined $option{$opt} or defined $optionVars{$opt} - and not defined $ {$optionVars{$opt}}) { + and not defined ${$optionVars{$opt}}) { $val = $default; } else { $val = $option{$opt}; @@ -1557,8 +1864,16 @@ sub option_val { sub parse_options { local($_)= @_; - while ($_ ne "") { - s/^(\w+)(\s*$|\W)// or print($OUT "Invalid option `$_'\n"), last; + # too dangerous to let intuitive usage overwrite important things + # defaultion should never be the default + my %opt_needs_val = map { ( $_ => 1 ) } qw{ + arrayDepth hashDepth LineInfo maxTraceLen ornaments + pager quote ReadLine recallCommand RemotePort ShellBang TTY + }; + while (length) { + my $val_defaulted; + s/^\s+// && next; + s/^(\w+)(\W?)// or print($OUT "Invalid option `$_'\n"), last; my ($opt,$sep) = ($1,$2); my $val; if ("?" eq $sep) { @@ -1566,59 +1881,83 @@ sub parse_options { if /^\S/; #&dump_option($opt); } elsif ($sep !~ /\S/) { - $val = "1"; + $val_defaulted = 1; + $val = "1"; # this is an evil default; make 'em set it! } elsif ($sep eq "=") { - s/^(\S*)($|\s+)//; + + if (s/ (["']) ( (?: \\. | (?! \1 ) [^\\] )* ) \1 //x) { + my $quote = $1; + ($val = $2) =~ s/\\([$quote\\])/$1/g; + } else { + s/^(\S*)//; $val = $1; + print OUT qq(Option better cleared using $opt=""\n) + unless length $val; + } + } else { #{ to "let some poor schmuck bounce on the % key in B." my ($end) = "\\" . substr( ")]>}$sep", index("([<{",$sep), 1 ); #} s/^(([^\\$end]|\\[\\$end])*)$end($|\s+)// or print($OUT "Unclosed option value `$opt$sep$_'\n"), last; - $val = $1; - $val =~ s/\\([\\$end])/$1/g; + ($val = $1) =~ s/\\([\\$end])/$1/g; } - my ($option); - my $matches = - grep( /^\Q$opt/ && ($option = $_), @options ); - $matches = grep( /^\Q$opt/i && ($option = $_), @options ) - unless $matches; - print $OUT "Unknown option `$opt'\n" unless $matches; - print $OUT "Ambiguous option `$opt'\n" if $matches > 1; - $option{$option} = $val if $matches == 1 and defined $val; - eval "local \$frame = 0; local \$doret = -2; - require '$optionRequire{$option}'" - if $matches == 1 and defined $optionRequire{$option} and defined $val; - $ {$optionVars{$option}} = $val - if $matches == 1 - and defined $optionVars{$option} and defined $val; - & {$optionAction{$option}} ($val) - if $matches == 1 - and defined $optionAction{$option} - and defined &{$optionAction{$option}} and defined $val; - &dump_option($option) if $matches == 1 && $OUT ne \*STDERR; # Not $rcfile - s/^\s+//; + + my $option; + my $matches = grep( /^\Q$opt/ && ($option = $_), @options ) + || grep( /^\Q$opt/i && ($option = $_), @options ); + + print($OUT "Unknown option `$opt'\n"), next unless $matches; + print($OUT "Ambiguous option `$opt'\n"), next if $matches > 1; + + if ($opt_needs_val{$option} && $val_defaulted) { + print $OUT "Option `$opt' is non-boolean. Use `O $option=VAL' to set, `O $option?' to query\n"; + next; + } + + $option{$option} = $val if defined $val; + + eval qq{ + local \$frame = 0; + local \$doret = -2; + require '$optionRequire{$option}'; + 1; + } || die # XXX: shouldn't happen + if defined $optionRequire{$option} && + defined $val; + + ${$optionVars{$option}} = $val + if defined $optionVars{$option} && + defined $val; + + &{$optionAction{$option}} ($val) + if defined $optionAction{$option} && + defined &{$optionAction{$option}} && + defined $val; + + # Not $rcfile + dump_option($option) unless $OUT eq \*STDERR; } } sub set_list { my ($stem,@list) = @_; my $val; - $ENV{"$ {stem}_n"} = @list; + $ENV{"${stem}_n"} = @list; for $i (0 .. $#list) { $val = $list[$i]; $val =~ s/\\/\\\\/g; $val =~ s/([\0-\37\177\200-\377])/"\\0x" . unpack('H2',$1)/eg; - $ENV{"$ {stem}_$i"} = $val; + $ENV{"${stem}_$i"} = $val; } } sub get_list { my $stem = shift; my @list; - my $n = delete $ENV{"$ {stem}_n"}; + my $n = delete $ENV{"${stem}_n"}; my $val; for $i (0 .. $n - 1) { - $val = delete $ENV{"$ {stem}_$i"}; + $val = delete $ENV{"${stem}_$i"}; $val =~ s/\\((\\)|0x(..))/ $2 ? $2 : pack('H2', $3) /ge; push @list, $val; } @@ -1673,8 +2012,16 @@ 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}) { + if (${$term->Features}{tkRunning}) { return $term->tkRunning(@_); } else { print $OUT "tkRunning not supported by current ReadLine package.\n"; @@ -1736,7 +2083,7 @@ sub LineInfo { return $lineinfo unless @_; $lineinfo = shift; my $stream = ($lineinfo =~ /^(\+?\>|\|)/) ? $lineinfo : ">$lineinfo"; - $emacs = ($stream =~ /^\|/); + $slave_editor = ($stream =~ /^\|/); open(LINEINFO, "$stream") || &warn("Cannot open `$stream' for write"); $LINEINFO = \*LINEINFO; my $save = select($LINEINFO); @@ -1754,8 +2101,8 @@ sub list_versions { s,/,::,g ; s/^perl5db$/DB/; s/^Term::ReadLine::readline$/readline/; - if (defined $ { $_ . '::VERSION' }) { - $version{$file} = "$ { $_ . '::VERSION' } from "; + if (defined ${ $_ . '::VERSION' }) { + $version{$file} = "${ $_ . '::VERSION' } from "; } $version{$file} .= $INC{$file}; } @@ -1763,6 +2110,10 @@ sub list_versions { } sub sethelp { + # XXX: make sure these are tabs between the command and explantion, + # or print_help will screw up your formatting if you have + # eeevil ornaments enabled. This is an insane mess. + $help = " B Stack trace. B [I] Single step [in I]. @@ -1775,11 +2126,18 @@ B IB<+>I List I+1 lines starting at I. B IB<->I List lines I through I. B I List single I. B I List first window of lines from subroutine. +B I<\$var> List first window of lines from subroutine referenced by I<\$var>. B List next window of lines. B<-> List previous window of lines. B [I] List window around I. B<.> Return to the executed line. -B I Switch to viewing I. Must be loaded. +B I Switch to viewing I. File must be already loaded. + I may be either the full name of the file, or a regular + expression matching the full file name: + B I and B I may access the same file. + Evals (with saved bodies) are considered to be filenames: + B I<(eval 7)> and B I access the body of the 7th eval + (in the order of execution). BIB Search forwards for I; final B is optional. BIB Search backwards for I; final B is optional. B List all breakpoints and actions. @@ -1791,6 +2149,7 @@ B [I] [I] I breaks if it evaluates to true, defaults to '1'. B I [I] Set breakpoint at first line of subroutine. +B I<\$var> Set breakpoint at first line of subroutine referenced by I<\$var>. B B I Set breakpoint on `require'ing the given file. B B I [I] Set breakpoint at first line of subroutine after @@ -1800,51 +2159,32 @@ B B I B [I] Delete the breakpoint for I. B Delete all breakpoints. B [I] I - Set an action to be done before the I is executed. + Set an action to be done before the I is executed; + I 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 [I] Delete the action for I. B Delete all actions. B I Add a global watch-expression. B Delete all watch-expressions. B [I [I]] List some (default all) variables in package (default current). Use B<~>I and BI for positive and negative regexps. B [I] Same as \"B I [I]\". -B I Evals expression in array context, dumps the result. -B I Evals expression in array context, prints methods callable +B I Evals expression in list context, dumps the result. +B I Evals expression in list context, prints methods callable on the first element of the result. B I Prints methods callable via the given class. -B [I[B<=>I]] [IB<\">IB<\">] [IB]... - Set or query values of options. I defaults to 1. I can - be abbreviated. Several options can be listed. - I, I: chars used to recall command or spawn shell; - I: program for output of \"|cmd\"; - I: run Tk while prompting (with ReadLine); - I I I: level of verbosity; - I Allows stepping off the end of the script. - I Debugger should stop as early as possible. - The following options affect what happens with B, B, and B commands: - I, I: print only first N elements ('' for all); - I, I: change style of array and hash dump; - I: whether to print contents of globs; - I: dump arrays holding debugged files; - I: dump symbol tables of packages; - I: dump contents of \"reused\" addresses; - I, I, I: change style of string dump; - I: Do not print the overload-stringified value; - Option I affects printing of return value after B command, - I affects printing messages on entry and exit from subroutines. - I affects printing messages on every possible breaking point. - I gives maximal length of evals/args listed in stack trace. - I affects screen appearance of the command line. - During startup options are initialized from \$ENV{PERLDB_OPTS}. - You can put additional initialization options I, I, - I, and I there (or use `B' after you set them). + +B<<> ? List Perl commands to run before each prompt. B<<> I Define Perl command to run before each prompt. B<<<> I Add to the list of Perl commands to run before each prompt. +B<>> ? List Perl commands to run after each prompt. B<>> I Define Perl command to run after each prompt. -B<>>B<>> I Add to the list of Perl commands to run after each prompt. +B<>>B<>> I Add to the list of Perl commands to run after each prompt. B<{> I Define debugger command to run before each prompt. +B<{> ? List debugger commands to run before each prompt. +B<<> I Define Perl command to run before each prompt. B<{{> I Add to the list of debugger commands to run before each prompt. B<$prc> I Redo a previous command (default previous command). B<$prc> I<-number> Redo number'th-to-last command. @@ -1866,46 +2206,137 @@ B Pure-man-restart of debugger, some of debugger state Currently the following setting are preserved: history, breakpoints and actions, debugger Bptions and the following command-line options: I<-w>, I<-I>, I<-e>. + +B [I] ... Set boolean option to true +B [IB] Query options +B [IB<=>I] [I=B<\">IB<\">] ... + Set options. Use quotes in spaces in value. + I, I chars used to recall command or spawn shell; + I program for output of \"|cmd\"; + I run Tk while prompting (with ReadLine); + I I I level of verbosity; + I Allows stepping off the end of the script. + I Debugger should stop as early as possible. + I Remote hostname:port for remote debugging + The following options affect what happens with B, B, and B commands: + I, I print only first N elements ('' for all); + I, I change style of array and hash dump; + I whether to print contents of globs; + I dump arrays holding debugged files; + I dump symbol tables of packages; + I dump contents of \"reused\" addresses; + I, I, I change style of string dump; + I Do not print the overload-stringified value; + Other options include: + I affects printing of return value after B command, + I affects printing messages on entry and exit from subroutines. + I affects printing messages on every possible breaking point. + I gives maximal length of evals/args listed in stack trace. + I affects screen appearance of the command line. + During startup options are initialized from \$ENV{PERLDB_OPTS}. + You can put additional initialization options I, I, + I, I, and I there (or use + `B' after you set them). + +B or B<^D> Quit. Set B<\$DB::finished = 0> to debug global destruction. B [I] Get help [on a specific debugger command], enter B<|h> to page. B Summary of debugger commands. -B or B<^D> Quit. Set B<\$DB::finished = 0> to debug global destruction. +B<$doccmd> I Runs the external doc viewer B<$doccmd> command on the + named Perl I, or on B<$doccmd> itself if omitted. + Set B<\$DB::doccmd> to change viewer. + +Type `|h' for a paged display if this was too hard to read. + +"; # Fix balance of vi % matching: } }} -"; $summary = <<"END_SUM"; I I B [I|I] List source code B Stack trace B<-> or B<.> List previous/current line B [I] Single step [in expr] B [I] List around line B [I] Next, steps over subs - B I View source in file > Repeat last B or B + B I View source in file /B> Repeat last B or B BIB BIB Search forw/backw B Return from subroutine B Show versions of modules B [I|I] Continue until position I B List break/watch/actions B [...] Set debugger options B [I] Toggle trace [trace expr] - B<<>[B<<>] or B<{>[B<{>] [I] Do before prompt B [I|I] [I] Set breakpoint - B<>>[B<>>] [I] Do after prompt B I [I] Set breakpoint for sub + B<<>[B<<>]|B<{>[B<{>]|B<>>[B<>>] [I] Do pre/post-prompt B [I|I|I] [I] Set breakpoint B<$prc> [I|I] Redo a previous command B [I] or B Delete a/all breakpoints B [I<-num>] Display last num commands B [I] I Do cmd before line B<=> [I I] Define/list an alias B I Add a watch expression B [I] Get help on command B or B Delete all actions/watch - B<|>[B<|>]I Send output to pager B<$psh>\[B<$psh>\] I Run cmd in a subprocess + B<|>[B<|>]I Send output to pager B<$psh>\[B<$psh>\] I Run cmd in a subprocess B or B<^D> Quit B Attempt a restart I B Execute perl code, also see: B,B,B I - B|B I Evals expr in array context, dumps the result or lists methods. + B|B I Evals expr in list context, dumps the result or lists methods. B

I Print expression (uses script's current package). B [[B]I] List subroutine names [not] matching pattern B [I [I]] List Variables in Package. Vars can be ~pattern or !pattern. B [I] Same as \"B I [I]\". +For more help, type B I, or run B<$doccmd perldebug> for all docs. END_SUM - # ')}}; # Fix balance of Emacs parsing + # ')}}; # Fix balance of vi % matching } sub print_help { - my $message = shift; - if (@Term::ReadLine::TermCap::rl_term_set) { - $message =~ s/B<([^>]+|>)>/$Term::ReadLine::TermCap::rl_term_set[2]$1$Term::ReadLine::TermCap::rl_term_set[3]/g; - $message =~ s/I<([^>]+|>)>/$Term::ReadLine::TermCap::rl_term_set[0]$1$Term::ReadLine::TermCap::rl_term_set[1]/g; - } - print $OUT $message; + local $_ = shift; + + # Restore proper alignment destroyed by eeevil I<> and B<> + # ornaments: A pox on both their houses! + # + # A help command will have everything up to and including + # the first tab sequence paddeed into a field 16 (or if indented 20) + # wide. If it's wide than that, an extra space will be added. + s{ + ^ # only matters at start of line + ( \040{4} | \t )* # some subcommands are indented + ( < ? # so works + [BI] < [^\t\n] + ) # find an eeevil ornament + ( \t+ ) # original separation, discarded + ( .* ) # this will now start (no earlier) than + # column 16 + } { + my($leadwhite, $command, $midwhite, $text) = ($1, $2, $3, $4); + my $clean = $command; + $clean =~ s/[BI]<([^>]*)>/$1/g; + # replace with this whole string: + (length($leadwhite) ? " " x 4 : "") + . $command + . ((" " x (16 + (length($leadwhite) ? 4 : 0) - length($clean))) || " ") + . $text; + + }mgex; + + s{ # handle bold ornaments + B < ( [^>] + | > ) > + } { + $Term::ReadLine::TermCap::rl_term_set[2] + . $1 + . $Term::ReadLine::TermCap::rl_term_set[3] + }gex; + + s{ # handle italic ornaments + I < ( [^>] + | > ) > + } { + $Term::ReadLine::TermCap::rl_term_set[0] + . $1 + . $Term::ReadLine::TermCap::rl_term_set[1] + }gex; + + print $OUT $_; +} + +sub fix_less { + return if defined $ENV{LESS} && $ENV{LESS} =~ /r/; + my $is_less = $pager =~ /\bless\b/; + if ($pager =~ /\bmore\b/) { + my @st_more = stat('/usr/bin/more'); + my @st_less = stat('/usr/bin/less'); + $is_less = @st_more && @st_less + && $st_more[0] == $st_less[0] + && $st_more[1] == $st_less[1]; + } + # changes environment! + $ENV{LESS} .= 'r' if $is_less; } sub diesignal { @@ -1956,8 +2387,10 @@ sub dbdie { } eval { require Carp } if defined $^S; # If error/warning during compilation, # require may be broken. + die(@_, "\nCannot print stack trace, load with -MCarp option to see stack") unless defined &Carp::longmess; + # We do not want to debug this chunk (automatic disabling works # inside DB::DB, but not in Carp). my ($mysingle,$mytrace) = ($single,$trace); @@ -2015,10 +2448,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) { @@ -2043,18 +2497,81 @@ sub methods_via { my $prefix = shift; my $prepend = $prefix ? "via $prefix: " : ''; my $name; - for $name (grep {defined &{$ {"$ {class}::"}{$_}}} - sort keys %{"$ {class}::"}) { + for $name (grep {defined &{${"${class}::"}{$_}}} + sort keys %{"${class}::"}) { next if $seen{ $name }++; print $DB::OUT "$prepend$name\n"; } return unless shift; # Recurse? - for $name (@{"$ {class}::ISA"}) { + for $name (@{"${class}::ISA"}) { $prepend = $prefix ? $prefix . " -> $name" : $name; methods_via($name, $prepend, 1); } } +sub setman { + $doccmd = $^O !~ /^(?:MSWin32|VMS|os2|dos|amigaos|riscos|MacOS)\z/s + ? "man" # O Happy Day! + : "perldoc"; # Alas, poor unfortunates +} + +sub runman { + my $page = shift; + unless ($page) { + &system("$doccmd $doccmd"); + return; + } + # this way user can override, like with $doccmd="man -Mwhatever" + # or even just "man " to disable the path check. + unless ($doccmd eq 'man') { + &system("$doccmd $page"); + return; + } + + $page = 'perl' if lc($page) eq 'help'; + + require Config; + my $man1dir = $Config::Config{'man1dir'}; + my $man3dir = $Config::Config{'man3dir'}; + for ($man1dir, $man3dir) { s#/[^/]*\z## if /\S/ } + my $manpath = ''; + $manpath .= "$man1dir:" if $man1dir =~ /\S/; + $manpath .= "$man3dir:" if $man3dir =~ /\S/ && $man1dir ne $man3dir; + chop $manpath if $manpath; + # harmless if missing, I figure + my $oldpath = $ENV{MANPATH}; + $ENV{MANPATH} = $manpath if $manpath; + my $nopathopt = $^O =~ /dunno what goes here/; + if (system($doccmd, + # I just *know* there are men without -M + (($manpath && !$nopathopt) ? ("-M", $manpath) : ()), + split ' ', $page) ) + { + unless ($page =~ /^perl\w/) { + if (grep { $page eq $_ } qw{ + 5004delta 5005delta amiga api apio book boot bot call compile + cygwin data dbmfilter debug debguts delta diag doc dos dsc embed + faq faq1 faq2 faq3 faq4 faq5 faq6 faq7 faq8 faq9 filter fork + form func guts hack hist hpux intern ipc lexwarn locale lol mod + modinstall modlib number obj op opentut os2 os390 pod port + ref reftut run sec style sub syn thrtut tie toc todo toot tootc + trap unicode var vms win32 xs xstut + }) + { + $page =~ s/^/perl/; + system($doccmd, + (($manpath && !$nopathopt) ? ("-M", $manpath) : ()), + $page); + } + } + } + if (defined $oldpath) { + $ENV{MANPATH} = $manpath; + } else { + delete $ENV{MANPATH}; + } +} + # The following BEGIN is very handy if debugger goes havoc, debugging debugger? BEGIN { # This does not compile, alas. @@ -2092,7 +2609,7 @@ sub db_complete { # Specific code for b c l V m f O, &blah, $blah, @blah, %blah my($text, $line, $start) = @_; my ($itext, $search, $prefix, $pack) = - ($text, "^\Q$ {'package'}::\E([^:]+)\$"); + ($text, "^\Q${'package'}::\E([^:]+)\$"); return sort grep /^\Q$text/, (keys %sub), qw(postpone load compile), # subroutines (map { /$search/ ? ($1) : () } keys %sub) @@ -2173,10 +2690,11 @@ sub end_report { } END { - $finished = $inhibit_exit; # So that some keys may be disabled. + $finished = 1 if $inhibit_exit; # So that some keys may be disabled. + $fall_off_end = 1 unless $inhibit_exit; # Do not stop in at_exit() and destructors on exit: - $DB::single = !$exiting && !$runnonstop; - DB::fake::at_exit() unless $exiting or $runnonstop; + $DB::single = !$fall_off_end && !$runnonstop; + DB::fake::at_exit() unless $fall_off_end or $runnonstop; } package DB::fake;