perl 4.0 patch 29: patch #20, continued
[p5sagit/p5-mst-13.2.git] / lib / perldb.pl
1 package DB;
2
3 # modified Perl debugger, to be run from Emacs in perldb-mode
4 # Ray Lischner (uunet!mntgfx!lisch) as of 5 Nov 1990
5 # Johan Vromans -- upgrade to 4.0 pl 10
6
7 $header = '$RCSfile: perldb.pl,v $$Revision: 4.0.1.3 $$Date: 92/06/08 13:43:57 $';
8 #
9 # This file is automatically included if you do perl -d.
10 # It's probably not useful to include this yourself.
11 #
12 # Perl supplies the values for @line and %sub.  It effectively inserts
13 # a do DB'DB(<linenum>); in front of every place that can
14 # have a breakpoint.  It also inserts a do 'perldb.pl' before the first line.
15 #
16 # $Log: perldb.pl,v $
17 # Revision 4.0.1.3  92/06/08  13:43:57  lwall
18 # patch20: support for MSDOS folded into perldb.pl
19 # patch20: perldb couldn't debug file containing '-', such as STDIN designator
20
21 # Revision 4.0.1.2  91/11/05  17:55:58  lwall
22 # patch11: perldb.pl modified to run within emacs in perldb-mode
23
24 # Revision 4.0.1.1  91/06/07  11:17:44  lwall
25 # patch4: added $^P variable to control calling of perldb routines
26 # patch4: debugger sometimes listed wrong number of lines for a statement
27
28 # Revision 4.0  91/03/20  01:25:50  lwall
29 # 4.0 baseline.
30
31 # Revision 3.0.1.6  91/01/11  18:08:58  lwall
32 # patch42: @_ couldn't be accessed from debugger
33
34 # Revision 3.0.1.5  90/11/10  01:40:26  lwall
35 # patch38: the debugger wouldn't stop correctly or do action routines
36
37 # Revision 3.0.1.4  90/10/15  17:40:38  lwall
38 # patch29: added caller
39 # patch29: the debugger now understands packages and evals
40 # patch29: scripts now run at almost full speed under the debugger
41 # patch29: more variables are settable from debugger
42
43 # Revision 3.0.1.3  90/08/09  04:00:58  lwall
44 # patch19: debugger now allows continuation lines
45 # patch19: debugger can now dump lists of variables
46 # patch19: debugger can now add aliases easily from prompt
47
48 # Revision 3.0.1.2  90/03/12  16:39:39  lwall
49 # patch13: perl -d didn't format stack traces of *foo right
50 # patch13: perl -d wiped out scalar return values of subroutines
51
52 # Revision 3.0.1.1  89/10/26  23:14:02  lwall
53 # patch1: RCS expanded an unintended $Header in lib/perldb.pl
54
55 # Revision 3.0  89/10/18  15:19:46  lwall
56 # 3.0 baseline
57
58 # Revision 2.0  88/06/05  00:09:45  root
59 # Baseline version 2.0.
60
61 #
62
63 if (-e "/dev/tty") {
64     $console = "/dev/tty";
65     $rcfile=".perldb";
66 }
67 else {
68     $console = "con";
69     $rcfile="perldb.ini";
70 }
71
72 open(IN, "<$console") || open(IN,  "<&STDIN");  # so we don't dingle stdin
73 open(OUT,">$console") || open(OUT, ">&STDOUT"); # so we don't dongle stdout
74 select(OUT);
75 $| = 1;                         # for DB'OUT
76 select(STDOUT);
77 $| = 1;                         # for real STDOUT
78 $sub = '';
79
80 # Is Perl being run from Emacs?
81 $emacs = $main'ARGV[$[] eq '-emacs';
82 shift(@main'ARGV) if $emacs;
83
84 $header =~ s/.Header: ([^,]+),v(\s+\S+\s+\S+).*$/$1$2/;
85 print OUT "\nLoading DB routines from $header\n";
86 print OUT ("Emacs support ",
87            $emacs ? "enabled" : "available",
88            ".\n");
89 print OUT "\nEnter h for help.\n\n";
90
91 sub DB {
92     &save;
93     ($package, $filename, $line) = caller;
94     $usercontext = '($@, $!, $[, $,, $/, $\) = @saved;' .
95         "package $package;";            # this won't let them modify, alas
96     local($^P) = 0;                     # don't debug our own evals
97     local(*dbline) = "_<$filename";
98     $max = $#dbline;
99     if (($stop,$action) = split(/\0/,$dbline{$line})) {
100         if ($stop eq '1') {
101             $signal |= 1;
102         }
103         else {
104             $evalarg = "\$DB'signal |= do {$stop;}"; &eval;
105             $dbline{$line} =~ s/;9($|\0)/$1/;
106         }
107     }
108     if ($single || $trace || $signal) {
109         if ($emacs) {
110             print OUT "\032\032$filename:$line:0\n";
111         } else {
112             print OUT "$package'" unless $sub =~ /'/;
113             print OUT "$sub($filename:$line):\t",$dbline[$line];
114             for ($i = $line + 1; $i <= $max && $dbline[$i] == 0; ++$i) {
115                 last if $dbline[$i] =~ /^\s*(}|#|\n)/;
116                 print OUT "$sub($filename:$i):\t",$dbline[$i];
117             }
118         }
119     }
120     $evalarg = $action, &eval if $action;
121     if ($single || $signal) {
122         $evalarg = $pre, &eval if $pre;
123         print OUT $#stack . " levels deep in subroutine calls!\n"
124             if $single & 4;
125         $start = $line;
126       CMD:
127         while ((print OUT "  DB<", $#hist+1, "> "), $cmd=&gets) {
128             {
129                 $single = 0;
130                 $signal = 0;
131                 $cmd eq '' && exit 0;
132                 chop($cmd);
133                 $cmd =~ s/\\$// && do {
134                     print OUT "  cont: ";
135                     $cmd .= &gets;
136                     redo CMD;
137                 };
138                 $cmd =~ /^q$/ && exit 0;
139                 $cmd =~ /^$/ && ($cmd = $laststep);
140                 push(@hist,$cmd) if length($cmd) > 1;
141                 ($i) = split(/\s+/,$cmd);
142                 eval "\$cmd =~ $alias{$i}", print OUT $@ if $alias{$i};
143                 $cmd =~ /^h$/ && do {
144                     print OUT "
145 T               Stack trace.
146 s               Single step.
147 n               Next, steps over subroutine calls.
148 r               Return from current subroutine.
149 c [line]        Continue; optionally inserts a one-time-only breakpoint 
150                 at the specified line.
151 <CR>            Repeat last n or s.
152 l min+incr      List incr+1 lines starting at min.
153 l min-max       List lines.
154 l line          List line;
155 l               List next window.
156 -               List previous window.
157 w line          List window around line.
158 l subname       List subroutine.
159 f filename      Switch to filename.
160 /pattern/       Search forwards for pattern; final / is optional.
161 ?pattern?       Search backwards for pattern.
162 L               List breakpoints and actions.
163 S               List subroutine names.
164 t               Toggle trace mode.
165 b [line] [condition]
166                 Set breakpoint; line defaults to the current execution line; 
167                 condition breaks if it evaluates to true, defaults to \'1\'.
168 b subname [condition]
169                 Set breakpoint at first line of subroutine.
170 d [line]        Delete breakpoint.
171 D               Delete all breakpoints.
172 a [line] command
173                 Set an action to be done before the line is executed.
174                 Sequence is: check for breakpoint, print line if necessary,
175                 do action, prompt user if breakpoint or step, evaluate line.
176 A               Delete all actions.
177 V [pkg [vars]]  List some (default all) variables in package (default current).
178 X [vars]        Same as \"V currentpackage [vars]\".
179 < command       Define command before prompt.
180 > command       Define command after prompt.
181 ! number        Redo command (default previous command).
182 ! -number       Redo number\'th to last command.
183 H -number       Display last number commands (default all).
184 q or ^D         Quit.
185 p expr          Same as \"print DB'OUT expr\" in current package.
186 = [alias value] Define a command alias, or list current aliases.
187 command         Execute as a perl statement in current package.
188
189 ";
190                     next CMD; };
191                 $cmd =~ /^t$/ && do {
192                     $trace = !$trace;
193                     print OUT "Trace = ".($trace?"on":"off")."\n";
194                     next CMD; };
195                 $cmd =~ /^S$/ && do {
196                     foreach $subname (sort(keys %sub)) {
197                         print OUT $subname,"\n";
198                     }
199                     next CMD; };
200                 $cmd =~ s/^X\b/V $package/;
201                 $cmd =~ /^V$/ && do {
202                     $cmd = 'V $package'; };
203                 $cmd =~ /^V\b\s*(\S+)\s*(.*)/ && do {
204                     $packname = $1;
205                     @vars = split(' ',$2);
206                     do 'dumpvar.pl' unless defined &main'dumpvar;
207                     if (defined &main'dumpvar) {
208                         &main'dumpvar($packname,@vars);
209                     }
210                     else {
211                         print DB'OUT "dumpvar.pl not available.\n";
212                     }
213                     next CMD; };
214                 $cmd =~ /^f\b\s*(.*)/ && do {
215                     $file = $1;
216                     if (!$file) {
217                         print OUT "The old f command is now the r command.\n";
218                         print OUT "The new f command switches filenames.\n";
219                         next CMD;
220                     }
221                     if (!defined $_main{'_<' . $file}) {
222                         if (($try) = grep(m#^_<.*$file#, keys %_main)) {
223                             $file = substr($try,2);
224                             print "\n$file:\n";
225                         }
226                     }
227                     if (!defined $_main{'_<' . $file}) {
228                         print OUT "There's no code here anything matching $file.\n";
229                         next CMD;
230                     }
231                     elsif ($file ne $filename) {
232                         *dbline = "_<$file";
233                         $max = $#dbline;
234                         $filename = $file;
235                         $start = 1;
236                         $cmd = "l";
237                     } };
238                 $cmd =~ /^l\b\s*(['A-Za-z_]['\w]*)/ && do {
239                     $subname = $1;
240                     $subname = "main'" . $subname unless $subname =~ /'/;
241                     $subname = "main" . $subname if substr($subname,0,1) eq "'";
242                     ($file,$subrange) = split(/:/,$sub{$subname});
243                     if ($file ne $filename) {
244                         *dbline = "_<$file";
245                         $max = $#dbline;
246                         $filename = $file;
247                     }
248                     if ($subrange) {
249                         if (eval($subrange) < -$window) {
250                             $subrange =~ s/-.*/+/;
251                         }
252                         $cmd = "l $subrange";
253                     } else {
254                         print OUT "Subroutine $1 not found.\n";
255                         next CMD;
256                     } };
257                 $cmd =~ /^w\b\s*(\d*)$/ && do {
258                     $incr = $window - 1;
259                     $start = $1 if $1;
260                     $start -= $preview;
261                     $cmd = 'l ' . $start . '-' . ($start + $incr); };
262                 $cmd =~ /^-$/ && do {
263                     $incr = $window - 1;
264                     $cmd = 'l ' . ($start-$window*2) . '+'; };
265                 $cmd =~ /^l$/ && do {
266                     $incr = $window - 1;
267                     $cmd = 'l ' . $start . '-' . ($start + $incr); };
268                 $cmd =~ /^l\b\s*(\d*)\+(\d*)$/ && do {
269                     $start = $1 if $1;
270                     $incr = $2;
271                     $incr = $window - 1 unless $incr;
272                     $cmd = 'l ' . $start . '-' . ($start + $incr); };
273                 $cmd =~ /^l\b\s*(([\d\$\.]+)([-,]([\d\$\.]+))?)?/ && do {
274                     $end = (!$2) ? $max : ($4 ? $4 : $2);
275                     $end = $max if $end > $max;
276                     $i = $2;
277                     $i = $line if $i eq '.';
278                     $i = 1 if $i < 1;
279                     if ($emacs) {
280                         print OUT "\032\032$filename:$i:0\n";
281                         $i = $end;
282                     } else {
283                         for (; $i <= $end; $i++) {
284                             print OUT "$i:\t", $dbline[$i];
285                             last if $signal;
286                         }
287                     }
288                     $start = $i;        # remember in case they want more
289                     $start = $max if $start > $max;
290                     next CMD; };
291                 $cmd =~ /^D$/ && do {
292                     print OUT "Deleting all breakpoints...\n";
293                     for ($i = 1; $i <= $max ; $i++) {
294                         if (defined $dbline{$i}) {
295                             $dbline{$i} =~ s/^[^\0]+//;
296                             if ($dbline{$i} =~ s/^\0?$//) {
297                                 delete $dbline{$i};
298                             }
299                         }
300                     }
301                     next CMD; };
302                 $cmd =~ /^L$/ && do {
303                     for ($i = 1; $i <= $max; $i++) {
304                         if (defined $dbline{$i}) {
305                             print OUT "$i:\t", $dbline[$i];
306                             ($stop,$action) = split(/\0/, $dbline{$i});
307                             print OUT "  break if (", $stop, ")\n" 
308                                 if $stop;
309                             print OUT "  action:  ", $action, "\n" 
310                                 if $action;
311                             last if $signal;
312                         }
313                     }
314                     next CMD; };
315                 $cmd =~ /^b\b\s*(['A-Za-z_]['\w]*)\s*(.*)/ && do {
316                     $subname = $1;
317                     $cond = $2 || '1';
318                     $subname = "$package'" . $subname unless $subname =~ /'/;
319                     $subname = "main" . $subname if substr($subname,0,1) eq "'";
320                     ($filename,$i) = split(/:/, $sub{$subname});
321                     $i += 0;
322                     if ($i) {
323                         *dbline = "_<$filename";
324                         ++$i while $dbline[$i] == 0 && $i < $#dbline;
325                         $dbline{$i} =~ s/^[^\0]*/$cond/;
326                     } else {
327                         print OUT "Subroutine $subname not found.\n";
328                     }
329                     next CMD; };
330                 $cmd =~ /^b\b\s*(\d*)\s*(.*)/ && do {
331                     $i = ($1?$1:$line);
332                     $cond = $2 || '1';
333                     if ($dbline[$i] == 0) {
334                         print OUT "Line $i not breakable.\n";
335                     } else {
336                         $dbline{$i} =~ s/^[^\0]*/$cond/;
337                     }
338                     next CMD; };
339                 $cmd =~ /^d\b\s*(\d+)?/ && do {
340                     $i = ($1?$1:$line);
341                     $dbline{$i} =~ s/^[^\0]*//;
342                     delete $dbline{$i} if $dbline{$i} eq '';
343                     next CMD; };
344                 $cmd =~ /^A$/ && do {
345                     for ($i = 1; $i <= $max ; $i++) {
346                         if (defined $dbline{$i}) {
347                             $dbline{$i} =~ s/\0[^\0]*//;
348                             delete $dbline{$i} if $dbline{$i} eq '';
349                         }
350                     }
351                     next CMD; };
352                 $cmd =~ /^<\s*(.*)/ && do {
353                     $pre = do action($1);
354                     next CMD; };
355                 $cmd =~ /^>\s*(.*)/ && do {
356                     $post = do action($1);
357                     next CMD; };
358                 $cmd =~ /^a\b\s*(\d+)(\s+(.*))?/ && do {
359                     $i = $1;
360                     if ($dbline[$i] == 0) {
361                         print OUT "Line $i may not have an action.\n";
362                     } else {
363                         $dbline{$i} =~ s/\0[^\0]*//;
364                         $dbline{$i} .= "\0" . do action($3);
365                     }
366                     next CMD; };
367                 $cmd =~ /^n$/ && do {
368                     $single = 2;
369                     $laststep = $cmd;
370                     last CMD; };
371                 $cmd =~ /^s$/ && do {
372                     $single = 1;
373                     $laststep = $cmd;
374                     last CMD; };
375                 $cmd =~ /^c\b\s*(\d*)\s*$/ && do {
376                     $i = $1;
377                     if ($i) {
378                         if ($dbline[$i] == 0) {
379                             print OUT "Line $i not breakable.\n";
380                             next CMD;
381                         }
382                         $dbline{$i} =~ s/(\0|$)/;9$1/;  # add one-time-only b.p.
383                     }
384                     for ($i=0; $i <= $#stack; ) {
385                         $stack[$i++] &= ~1;
386                     }
387                     last CMD; };
388                 $cmd =~ /^r$/ && do {
389                     $stack[$#stack] |= 2;
390                     last CMD; };
391                 $cmd =~ /^T$/ && do {
392                     local($p,$f,$l,$s,$h,$a,@a,@sub);
393                     for ($i = 1; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
394                         @a = @args;
395                         for (@a) {
396                             if (/^StB\000/ && length($_) == length($_main{'_main'})) {
397                                 $_ = sprintf("%s",$_);
398                             }
399                             else {
400                                 s/'/\\'/g;
401                                 s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
402                                 s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
403                                 s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
404                             }
405                         }
406                         $w = $w ? '@ = ' : '$ = ';
407                         $a = $h ? '(' . join(', ', @a) . ')' : '';
408                         push(@sub, "$w&$s$a from file $f line $l\n");
409                         last if $signal;
410                     }
411                     for ($i=0; $i <= $#sub; $i++) {
412                         last if $signal;
413                         print OUT $sub[$i];
414                     }
415                     next CMD; };
416                 $cmd =~ /^\/(.*)$/ && do {
417                     $inpat = $1;
418                     $inpat =~ s:([^\\])/$:$1:;
419                     if ($inpat ne "") {
420                         eval '$inpat =~ m'."\n$inpat\n";        
421                         if ($@ ne "") {
422                             print OUT "$@";
423                             next CMD;
424                         }
425                         $pat = $inpat;
426                     }
427                     $end = $start;
428                     eval '
429                     for (;;) {
430                         ++$start;
431                         $start = 1 if ($start > $max);
432                         last if ($start == $end);
433                         if ($dbline[$start] =~ m'."\n$pat\n".'i) {
434                             if ($emacs) {
435                                 print OUT "\032\032$filename:$start:0\n";
436                             } else {
437                                 print OUT "$start:\t", $dbline[$start], "\n";
438                             }
439                             last;
440                         }
441                     } ';
442                     print OUT "/$pat/: not found\n" if ($start == $end);
443                     next CMD; };
444                 $cmd =~ /^\?(.*)$/ && do {
445                     $inpat = $1;
446                     $inpat =~ s:([^\\])\?$:$1:;
447                     if ($inpat ne "") {
448                         eval '$inpat =~ m'."\n$inpat\n";        
449                         if ($@ ne "") {
450                             print OUT "$@";
451                             next CMD;
452                         }
453                         $pat = $inpat;
454                     }
455                     $end = $start;
456                     eval '
457                     for (;;) {
458                         --$start;
459                         $start = $max if ($start <= 0);
460                         last if ($start == $end);
461                         if ($dbline[$start] =~ m'."\n$pat\n".'i) {
462                             if ($emacs) {
463                                 print OUT "\032\032$filename:$start:0\n";
464                             } else {
465                                 print OUT "$start:\t", $dbline[$start], "\n";
466                             }
467                             last;
468                         }
469                     } ';
470                     print OUT "?$pat?: not found\n" if ($start == $end);
471                     next CMD; };
472                 $cmd =~ /^!+\s*(-)?(\d+)?$/ && do {
473                     pop(@hist) if length($cmd) > 1;
474                     $i = ($1?($#hist-($2?$2:1)):($2?$2:$#hist));
475                     $cmd = $hist[$i] . "\n";
476                     print OUT $cmd;
477                     redo CMD; };
478                 $cmd =~ /^!(.+)$/ && do {
479                     $pat = "^$1";
480                     pop(@hist) if length($cmd) > 1;
481                     for ($i = $#hist; $i; --$i) {
482                         last if $hist[$i] =~ $pat;
483                     }
484                     if (!$i) {
485                         print OUT "No such command!\n\n";
486                         next CMD;
487                     }
488                     $cmd = $hist[$i] . "\n";
489                     print OUT $cmd;
490                     redo CMD; };
491                 $cmd =~ /^H\b\s*(-(\d+))?/ && do {
492                     $end = $2?($#hist-$2):0;
493                     $hist = 0 if $hist < 0;
494                     for ($i=$#hist; $i>$end; $i--) {
495                         print OUT "$i: ",$hist[$i],"\n"
496                             unless $hist[$i] =~ /^.?$/;
497                     };
498                     next CMD; };
499                 $cmd =~ s/^p( .*)?$/print DB'OUT$1/;
500                 $cmd =~ /^=/ && do {
501                     if (local($k,$v) = ($cmd =~ /^=\s*(\S+)\s+(.*)/)) {
502                         $alias{$k}="s~$k~$v~";
503                         print OUT "$k = $v\n";
504                     } elsif ($cmd =~ /^=\s*$/) {
505                         foreach $k (sort keys(%alias)) {
506                             if (($v = $alias{$k}) =~ s~^s\~$k\~(.*)\~$~$1~) {
507                                 print OUT "$k = $v\n";
508                             } else {
509                                 print OUT "$k\t$alias{$k}\n";
510                             };
511                         };
512                     };
513                     next CMD; };
514             }
515             $evalarg = $cmd; &eval;
516             print OUT "\n";
517         }
518         if ($post) {
519             $evalarg = $post; &eval;
520         }
521     }
522     ($@, $!, $[, $,, $/, $\) = @saved;
523 }
524
525 sub save {
526     @saved = ($@, $!, $[, $,, $/, $\);
527     $[ = 0; $, = ""; $/ = "\n"; $\ = "";
528 }
529
530 # The following takes its argument via $evalarg to preserve current @_
531
532 sub eval {
533     eval "$usercontext $evalarg; &DB'save";
534     print OUT $@;
535 }
536
537 sub action {
538     local($action) = @_;
539     while ($action =~ s/\\$//) {
540         print OUT "+ ";
541         $action .= &gets;
542     }
543     $action;
544 }
545
546 sub gets {
547     local($.);
548     <IN>;
549 }
550
551 sub catch {
552     $signal = 1;
553 }
554
555 sub sub {
556     push(@stack, $single);
557     $single &= 1;
558     $single |= 4 if $#stack == $deep;
559     if (wantarray) {
560         @i = &$sub;
561         $single |= pop(@stack);
562         @i;
563     }
564     else {
565         $i = &$sub;
566         $single |= pop(@stack);
567         $i;
568     }
569 }
570
571 $single = 1;                    # so it stops on first executable statement
572 @hist = ('?');
573 $SIG{'INT'} = "DB'catch";
574 $deep = 100;            # warning if stack gets this deep
575 $window = 10;
576 $preview = 3;
577
578 @stack = (0);
579 @ARGS = @ARGV;
580 for (@args) {
581     s/'/\\'/g;
582     s/(.*)/'$1'/ unless /^-?[\d.]+$/;
583 }
584
585 if (-f $rcfile) {
586     do "./$rcfile";
587 }
588 elsif (-f "$ENV{'LOGDIR'}/$rcfile") {
589     do "$ENV{'LOGDIR'}/$rcfile";
590 }
591 elsif (-f "$ENV{'HOME'}/$rcfile") {
592     do "$ENV{'HOME'}/$rcfile";
593 }
594
595 1;