perl 2.0 (no announcement message available)
[p5sagit/p5-mst-13.2.git] / perldb
CommitLineData
378cc40b 1#!/usr/bin/perl
a559c259 2
378cc40b 3# $Header: perldb,v 2.0 88/06/05 00:09:45 root Exp $
a559c259 4#
5# $Log: perldb,v $
378cc40b 6# Revision 2.0 88/06/05 00:09:45 root
7# Baseline version 2.0.
a559c259 8#
9#
10
11$tmp = "/tmp/pdb$$"; # default temporary file, -o overrides.
12
13# parse any switches
14
15while ($ARGV[0] =~ /^-/) {
16 $_ = shift;
17 /^-o$/ && ($tmp = shift,next);
18 die "Unrecognized switch: $_";
19}
20
21$filename = shift;
22die "Usage: perldb [-o output] scriptname arguments" unless $filename;
23
24open(script,$filename) || die "Can't find $filename";
25
26open(tmp, ">$tmp") || die "Can't make temp script";
27
378cc40b 28$perl = '/usr/bin/perl';
a559c259 29$init = 1;
30$state = 'statement';
31
32# now translate script to contain DB calls at the appropriate places
33
34while (<script>) {
35 chop;
36 if ($. == 1) {
37 if (/^#! *([^ \t]*) (-[^ \t]*)/) {
38 $perl = $1;
39 $switch = $2;
40 }
41 elsif (/^#! *([^ \t]*)/) {
42 $perl = $1;
43 }
44 }
45 s/ *$//;
46 push(@script,$_); # remember line for DBinit
47 $line = $_;
48 next if /^$/; # blank lines are uninteresting
49 next if /^[ \t]*#/; # likewise comment lines
50 if ($init) {
51 print tmp "do DBinit($.);"; $init = '';
52 }
53 if ($inform) { # skip formats
54 if (/^\.$/) {
55 $inform = '';
56 $state = 'statement';
57 }
58 next;
59 }
60 if (/^[ \t]*format /) {
61 $inform++;
62 next;
63 }
378cc40b 64 if ($state eq 'statement' &&
65 !/^[ \t]*}|^[ \t]*else|^[ \t]*continue|^[ \t]*elsif/) {
a559c259 66 if (s/^([ \t]*[A-Za-z_0-9]+:)//) {
67 $label = $1;
68 }
69 else {
70 $label = '';
71 }
72 $line = $label . "do DB($.); " . $_; # all that work for this line
73 }
74 else {
75 $script[$#script - 1] .= ' '; # mark line as having continuation
76 }
77 do parse(); # set $state to correct eol value
78}
79continue {
80 print tmp $line,"\n";
81}
82
83# now put out our debugging subroutines. First the one that's called all over.
84
85print tmp '
86sub DB {
87 push(@DB,$. ,$@, $!, $[, $,, $/, $\ );
88 $[ = 0; $, = ""; $/ = "\n"; $\ = "";
89 $DBline=pop(@_);
90 if ($DBsingle || $DBstop[$DBline] || $DBtrace) {
91 print "$DBline:\t",$DBline[$DBline],"\n";
92 for ($DBi = $DBline; $DBline[$DBi++] =~ / $/; ) {
93 print "$DBi:\t",$DBline[$DBi],"\n";
94 }
95 }
96 if ($DBaction[$DBline]) {
97 eval $DBaction[$DBline]; print $@;
98 }
99 if ($DBstop[$DBline] || $DBsingle) {
100 for (;;) {
101 print "perldb> ";
102 $DBcmd = <stdin>;
103 last if $DBcmd =~ /^$/;
104 if ($DBcmd =~ /^q$/) {
105 exit 0;
106 }
107 if ($DBcmd =~ /^h$/) {
108 print "
109s Single step.
110c Continue.
111<CR> Repeat last s or c.
112l min-max List lines.
113l line List line.
114l List the whole program.
115L List breakpoints.
116t Toggle trace mode.
117b line Set breakpoint.
118d line Delete breakpoint.
119d Delete breakpoint at this line.
120a line command Set an action for this line.
121q Quit.
122command Execute as a perl statement.
123
124";
125 next;
126 }
127 if ($DBcmd =~ /^t$/) {
128 $DBtrace = !$DBtrace;
129 print "Trace = $DBtrace\n";
130 next;
131 }
132 if ($DBcmd =~ /^l (.*)[-,](.*)/) {
133 for ($DBi = $1; $DBi <= $2; $DBi++) {
134 print "$DBi:\t", $DBline[$DBi], "\n";
135 }
136 next;
137 }
138 if ($DBcmd =~ /^l (.*)/) {
139 print "$1:\t", $DBline[$1], "\n";
140 next;
141 }
142 if ($DBcmd =~ /^l$/) {
143 for ($DBi = 1; $DBi <= $DBmax ; $DBi++) {
144 print "$DBi:\t", $DBline[$DBi], "\n";
145 }
146 next;
147 }
148 if ($DBcmd =~ /^L$/) {
149 for ($DBi = 1; $DBi <= $DBmax ; $DBi++) {
150 print "$DBi:\t", $DBline[$DBi], "\n" if $DBstop[$DBi];
151 }
152 next;
153 }
154 if ($DBcmd =~ /^b (.*)/) {
155 $DBi = $1;
156 if ($DBline[$DBi-1] =~ / $/) {
157 print "Line $DBi not breakable.\n";
158 }
159 else {
160 $DBstop[$DBi] = 1;
161 }
162 next;
163 }
164 if ($DBcmd =~ /^d (.*)/) {
165 $DBstop[$1] = 0;
166 next;
167 }
168 if ($DBcmd =~ /^d$/) {
169 $DBstop[$DBline] = 0;
170 next;
171 }
172 if ($DBcmd =~ /^a ([0-9]+)[ \t]+(.*)/) {
173 $DBi = $1;
174 $DBaction = $2;
175 $DBaction .= ";" unless $DBaction =~ /[;}]$/;
176 $DBaction[$DBi] = $DBaction;
177 next;
178 }
179 if ($DBcmd =~ /^s$/) {
180 $DBsingle = 1;
181 last;
182 }
183 if ($DBcmd =~ /^c$/) {
184 $DBsingle = 0;
185 last;
186 }
187 chop($DBcmd);
188 $DBcmd .= ";" unless $DBcmd =~ /[;}]$/;
189 eval $DBcmd;
190 print $@,"\n";
191 }
192 }
193 $\ = pop(@DB);
194 $/ = pop(@DB);
195 $, = pop(@DB);
196 $[ = pop(@DB);
197 $! = pop(@DB);
198 $@ = pop(@DB);
199 $. = pop(@DB);
200}
201
202sub DBinit {
203 $DBstop[$_[0]] = 1;
204';
205print tmp " \$0 = '$script';\n";
206print tmp " \$DBmax = $.;\n";
207print tmp " unlink '/tmp/pdb$$';\n"; # expected to fail on -o.
208for ($i = 1; $#script >= 0; $i++) {
209 $_ = shift(@script);
210 s/'/\\'/g;
211 print tmp " \$DBline[$i] = '$_';\n";
212}
213print tmp '}
214';
215
216close tmp;
217
218# prepare to run the new script
219
220unshift(@ARGV,$tmp);
221unshift(@ARGV,$switch) if $switch;
222unshift(@ARGV,$perl);
223exec @ARGV;
224
225# This routine tokenizes one perl line good enough to tell what state we are
226# in by the end of the line, so we can tell if the next line should contain
227# a call to DB or not.
228
229sub parse {
230 until ($_ eq '') {
231 $ord = ord($_);
232 if ($quoting) {
233 if ($quote == $ord) {
234 $quoting--;
235 }
236 s/^.// if /^[\\]/;
237 s/^.//;
238 last if $_ eq "\n";
239 $state = 'term' unless $quoting;
240 next;
241 }
242 if ($ord > 64) {
243 do quote(ord($1),1), next if s/^m\b(.)//;
244 do quote(ord($1),2), next if s/^s\b(.)//;
245 do quote(ord($1),2), next if s/^y\b(.)//;
246 do quote(ord($1),2), next if s/^tr\b(.)//;
378cc40b 247 do quote($ord,1), next if s/^`//;
a559c259 248 next if s/^[A-Za-z_][A-Za-z_0-9]*://;
249 $state = 'term', next if s/^eof\b//;
250 $state = 'term', next if s/^shift\b//;
251 $state = 'term', next if s/^split\b//;
252 $state = 'term', next if s/^tell\b//;
253 $state = 'term', next if s/^write\b//;
254 $state = 'operator', next if s/^[A-Za-z_][A-Za-z_0-9]*//;
255 $state = 'operator', next if s/^[~^|]+//;
256 $state = 'statement', next if s/^{//;
257 $state = 'statement', next if s/^}[ \t]*$//;
258 $state = 'statement', next if s/^}[ \t]*#/#/;
259 $state = 'term', next if s/^}//;
260 $state = 'operator', next if s/^\[//;
261 $state = 'term', next if s/^]//;
262 die "Illegal character $_";
263 }
264 elsif ($ord < 33) {
378cc40b 265 next if s/[ \t\n\f]+//;
a559c259 266 die "Illegal character $_";
267 }
268 else {
269 $state = 'statement', next if s/^;//;
270 $state = 'term', next if s/^\.[0-9eE]+//;
271 $state = 'term', next if s/^[0-9][0-9xaAbBcCddeEfF.]*//;
272 $state = 'term', next if s/^\$[A-Za-z_][A-Za-z_0-9]*//;
273 $state = 'term', next if s/^\$.//;
274 $state = 'term', next if s/^@[A-Za-z_][A-Za-z_0-9]*//;
275 $state = 'term', next if s/^@.//;
276 $state = 'term', next if s/^<[A-Za-z_0-9]*>//;
277 next if s/^\+\+//;
278 next if s/^--//;
378cc40b 279 $state = 'operator', next if s/^[-(!%&*=+:,.<>]//;
a559c259 280 $state = 'term', next if s/^\)+//;
281 do quote($ord,1), next if s/^'//;
282 do quote($ord,1), next if s/^"//;
283 if (s|^[/?]||) {
284 if ($state =~ /stat|oper/) {
285 $state = 'term';
286 do quote($ord,1), next;
287 }
288 $state = 'operator', next;
289 }
290 next if s/^#.*//;
291 }
292 }
293}
294
295sub quote {
296 ($quote,$quoting) = @_;
297 $state = 'quote';
298}