This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Problems with SKIP in makemaker
[perl5.git] / lib / diagnostics.pm
CommitLineData
4633a7c4 1package diagnostics;
4633a7c4
LW
2
3=head1 NAME
4
5diagnostics - Perl compiler pragma to force verbose warning diagnostics
6
7splain - standalone program to do the same thing
8
9=head1 SYNOPSIS
10
11As a pragma:
12
13 use diagnostics;
14 use diagnostics -verbose;
15
16 enable diagnostics;
17 disable diagnostics;
18
19Aa a program:
20
21 perl program 2>diag.out
22 splain [-v] [-p] diag.out
23
24
25=head1 DESCRIPTION
26
27=head2 The C<diagnostics> Pragma
28
29This module extends the terse diagnostics normally emitted by both the
1fef88e7 30perl compiler and the perl interpeter, augmenting them with the more
4633a7c4 31explicative and endearing descriptions found in L<perldiag>. Like the
1fef88e7 32other pragmata, it affects the compilation phase of your program rather
4633a7c4
LW
33than merely the execution phase.
34
35To use in your program as a pragma, merely invoke
36
37 use diagnostics;
38
39at the start (or near the start) of your program. (Note
40that this I<does> enable perl's B<-w> flag.) Your whole
41compilation will then be subject(ed :-) to the enhanced diagnostics.
42These still go out B<STDERR>.
43
44Due to the interaction between runtime and compiletime issues,
45and because it's probably not a very good idea anyway,
46you may not use C<no diagnostics> to turn them off at compiletime.
47However, you may control there behaviour at runtime using the
48disable() and enable() methods to turn them off and on respectively.
49
50The B<-verbose> flag first prints out the L<perldiag> introduction before
1fef88e7
JM
51any other diagnostics. The $diagnostics::PRETTY variable can generate nicer
52escape sequences for pagers.
4633a7c4
LW
53
54=head2 The I<splain> Program
55
56While apparently a whole nuther program, I<splain> is actually nothing
57more than a link to the (executable) F<diagnostics.pm> module, as well as
58a link to the F<diagnostics.pod> documentation. The B<-v> flag is like
59the C<use diagnostics -verbose> directive.
60The B<-p> flag is like the
61$diagnostics::PRETTY variable. Since you're post-processing with
62I<splain>, there's no sense in being able to enable() or disable() processing.
63
64Output from I<splain> is directed to B<STDOUT>, unlike the pragma.
65
66=head1 EXAMPLES
67
68The following file is certain to trigger a few errors at both
69runtime and compiletime:
70
71 use diagnostics;
72 print NOWHERE "nothing\n";
73 print STDERR "\n\tThis message should be unadorned.\n";
74 warn "\tThis is a user warning";
75 print "\nDIAGNOSTIC TESTER: Please enter a <CR> here: ";
76 my $a, $b = scalar <STDIN>;
77 print "\n";
78 print $x/$y;
79
80If you prefer to run your program first and look at its problem
81afterwards, do this:
82
83 perl -w test.pl 2>test.out
84 ./splain < test.out
85
86Note that this is not in general possible in shells of more dubious heritage,
1fef88e7 87as the theoretical
4633a7c4
LW
88
89 (perl -w test.pl >/dev/tty) >& test.out
90 ./splain < test.out
91
92Because you just moved the existing B<stdout> to somewhere else.
93
94If you don't want to modify your source code, but still have on-the-fly
95warnings, do this:
96
97 exec 3>&1; perl -w test.pl 2>&1 1>&3 3>&- | splain 1>&2 3>&-
98
99Nifty, eh?
100
101If you want to control warnings on the fly, do something like this.
102Make sure you do the C<use> first, or you won't be able to get
103at the enable() or disable() methods.
104
105 use diagnostics; # checks entire compilation phase
106 print "\ntime for 1st bogus diags: SQUAWKINGS\n";
107 print BOGUS1 'nada';
108 print "done with 1st bogus\n";
109
110 disable diagnostics; # only turns off runtime warnings
111 print "\ntime for 2nd bogus: (squelched)\n";
112 print BOGUS2 'nada';
113 print "done with 2nd bogus\n";
114
115 enable diagnostics; # turns back on runtime warnings
116 print "\ntime for 3rd bogus: SQUAWKINGS\n";
117 print BOGUS3 'nada';
118 print "done with 3rd bogus\n";
119
120 disable diagnostics;
121 print "\ntime for 4th bogus: (squelched)\n";
122 print BOGUS4 'nada';
123 print "done with 4th bogus\n";
124
125=head1 INTERNALS
126
127Diagnostic messages derive from the F<perldiag.pod> file when available at
128runtime. Otherwise, they may be embedded in the file itself when the
129splain package is built. See the F<Makefile> for details.
130
131If an extant $SIG{__WARN__} handler is discovered, it will continue
1fef88e7 132to be honored, but only after the diagnostics::splainthis() function
4633a7c4
LW
133(the module's $SIG{__WARN__} interceptor) has had its way with your
134warnings.
135
136There is a $diagnostics::DEBUG variable you may set if you're desperately
137curious what sorts of things are being intercepted.
138
139 BEGIN { $diagnostics::DEBUG = 1 }
140
141
142=head1 BUGS
143
144Not being able to say "no diagnostics" is annoying, but may not be
145insurmountable.
146
147The C<-pretty> directive is called too late to affect matters.
148You have to to this instead, and I<before> you load the module.
149
150 BEGIN { $diagnostics::PRETTY = 1 }
151
152I could start up faster by delaying compilation until it should be
a6006777 153needed, but this gets a "panic: top_level" when using the pragma form
154in Perl 5.001e.
4633a7c4
LW
155
156While it's true that this documentation is somewhat subserious, if you use
157a program named I<splain>, you should expect a bit of whimsy.
158
159=head1 AUTHOR
160
352854fa 161Tom Christiansen <F<tchrist@mox.perl.com>>, 25 June 1995.
4633a7c4
LW
162
163=cut
164
5f05dabc 165require 5.001;
5f05dabc 166use Carp;
167
168use Config;
169if ($^O eq 'VMS') {
170 $PODFILE = VMS::Filespec::unixify($Config{privlibexp}).'/pod/perldiag.pod';
171}
172else {
173 $PODFILE = $Config{privlibexp} . "/pod/perldiag.pod";
174}
175
4633a7c4
LW
176$DEBUG ||= 0;
177my $WHOAMI = ref bless []; # nobody's business, prolly not even mine
178
6dab8668 179$| = 1;
4633a7c4
LW
180
181local $_;
182
183CONFIG: {
184 $opt_p = $opt_d = $opt_v = $opt_f = '';
185 %HTML_2_Troff = %HTML_2_Latin_1 = %HTML_2_ASCII_7 = ();
186 %exact_duplicate = ();
187
188 unless (caller) {
189 $standalone++;
190 require Getopt::Std;
191 Getopt::Std::getopts('pdvf:') || die "Usage: $0 [-v] [-p] [-f splainpod]";
192 $PODFILE = $opt_f if $opt_f;
193 $DEBUG = 2 if $opt_d;
194 $VERBOSE = $opt_v;
195 $PRETTY = $opt_p;
196 }
197
198 if (open(POD_DIAG, $PODFILE)) {
199 warn "Happy happy podfile from real $PODFILE\n" if $DEBUG;
200 last CONFIG;
201 }
202
203 if (caller) {
204 INCPATH: {
205 for $file ( (map { "$_/$WHOAMI.pm" } @INC), $0) {
206 warn "Checking $file\n" if $DEBUG;
207 if (open(POD_DIAG, $file)) {
208 while (<POD_DIAG>) {
209 next unless /^__END__\s*# wish diag dbase were more accessible/;
210 print STDERR "podfile is $file\n" if $DEBUG;
211 last INCPATH;
212 }
213 }
214 }
215 }
216 } else {
217 print STDERR "podfile is <DATA>\n" if $DEBUG;
218 *POD_DIAG = *main::DATA;
219 }
220}
221if (eof(POD_DIAG)) {
222 die "couldn't find diagnostic data in $PODFILE @INC $0";
223}
224
225
226%HTML_2_Troff = (
227 'amp' => '&', # ampersand
228 'lt' => '<', # left chevron, less-than
229 'gt' => '>', # right chevron, greater-than
230 'quot' => '"', # double quote
231
232 "Aacute" => "A\\*'", # capital A, acute accent
233 # etc
234
235);
236
237%HTML_2_Latin_1 = (
238 'amp' => '&', # ampersand
239 'lt' => '<', # left chevron, less-than
240 'gt' => '>', # right chevron, greater-than
241 'quot' => '"', # double quote
242
243 "Aacute" => "\xC1" # capital A, acute accent
244
245 # etc
246);
247
248%HTML_2_ASCII_7 = (
249 'amp' => '&', # ampersand
250 'lt' => '<', # left chevron, less-than
251 'gt' => '>', # right chevron, greater-than
252 'quot' => '"', # double quote
253
254 "Aacute" => "A" # capital A, acute accent
255 # etc
256);
257
258*HTML_Escapes = do {
259 if ($standalone) {
260 $PRETTY ? \%HTML_2_Latin_1 : \%HTML_2_ASCII_7;
261 } else {
262 \%HTML_2_Latin_1;
263 }
264};
265
266*THITHER = $standalone ? *STDOUT : *STDERR;
267
268$transmo = <<EOFUNC;
269sub transmo {
270 local \$^W = 0; # recursive warnings we do NOT need!
271 study;
272EOFUNC
273
274### sub finish_compilation { # 5.001e panic: top_level for embedded version
275 print STDERR "FINISHING COMPILATION for $_\n" if $DEBUG;
276 ### local
277 $RS = '';
278 local $_;
279 while (<POD_DIAG>) {
280 #s/(.*)\n//;
281 #$header = $1;
282
283 unescape();
284 if ($PRETTY) {
285 sub noop { return $_[0] } # spensive for a noop
286 sub bold { my $str =$_[0]; $str =~ s/(.)/$1\b$1/g; return $str; }
287 sub italic { my $str = $_[0]; $str =~ s/(.)/_\b$1/g; return $str; }
288 s/[BC]<(.*?)>/bold($1)/ges;
289 s/[LIF]<(.*?)>/italic($1)/ges;
290 } else {
291 s/[BC]<(.*?)>/$1/gs;
292 s/[LIF]<(.*?)>/$1/gs;
293 }
294 unless (/^=/) {
295 if (defined $header) {
296 if ( $header eq 'DESCRIPTION' &&
297 ( /Optional warnings are enabled/
298 || /Some of these messages are generic./
299 ) )
300 {
301 next;
302 }
303 s/^/ /gm;
304 $msg{$header} .= $_;
305 }
306 next;
307 }
308 unless ( s/=item (.*)\s*\Z//) {
309
310 if ( s/=head1\sDESCRIPTION//) {
311 $msg{$header = 'DESCRIPTION'} = '';
312 }
313 next;
314 }
4fdae800 315
316 # strip formatting directives in =item line
317 ($header = $1) =~ s/[A-Z]<(.*?)>/$1/g;
4633a7c4
LW
318
319 if ($header =~ /%[sd]/) {
320 $rhs = $lhs = $header;
321 #if ($lhs =~ s/(.*?)%d(?!%d)(.*)/\Q$1\E\\d+\Q$2\E\$/g) {
322 if ($lhs =~ s/(.*?)%d(?!%d)(.*)/\Q$1\E\\d+\Q$2\E/g) {
323 $lhs =~ s/\\%s/.*?/g;
324 } else {
325 # if i had lookbehind negations, i wouldn't have to do this \377 noise
326 $lhs =~ s/(.*?)%s/\Q$1\E.*?\377/g;
327 #$lhs =~ s/\377([^\377]*)$/\Q$1\E\$/;
328 $lhs =~ s/\377([^\377]*)$/\Q$1\E/;
329 $lhs =~ s/\377//g;
e7ea3e70 330 $lhs =~ s/\.\*\?$/.*/; # Allow %s at the end to eat it all
4633a7c4 331 }
e7ea3e70 332 $transmo .= " s{^$lhs}\n {\Q$rhs\E}s\n\t&& return 1;\n";
4633a7c4
LW
333 } else {
334 $transmo .= " m{^\Q$header\E} && return 1;\n";
335 }
336
eff9c6e2
CS
337 print STDERR "$WHOAMI: Duplicate entry: \"$header\"\n"
338 if $msg{$header};
4633a7c4
LW
339
340 $msg{$header} = '';
341 }
342
343
344 close POD_DIAG unless *main::DATA eq *POD_DIAG;
345
346 die "No diagnostics?" unless %msg;
347
348 $transmo .= " return 0;\n}\n";
349 print STDERR $transmo if $DEBUG;
350 eval $transmo;
351 die $@ if $@;
352 $RS = "\n";
353### }
354
355if ($standalone) {
356 if (!@ARGV and -t STDIN) { print STDERR "$0: Reading from STDIN\n" }
40da2db3 357 while (defined ($error = <>)) {
4633a7c4
LW
358 splainthis($error) || print THITHER $error;
359 }
360 exit;
361} else {
362 $old_w = 0; $oldwarn = ''; $olddie = '';
363}
364
365sub import {
366 shift;
367 $old_w = $^W;
368 $^W = 1; # yup, clobbered the global variable; tough, if you
369 # want diags, you want diags.
370 return if $SIG{__WARN__} eq \&warn_trap;
371
372 for (@_) {
373
374 /^-d(ebug)?$/ && do {
375 $DEBUG++;
376 next;
377 };
378
379 /^-v(erbose)?$/ && do {
380 $VERBOSE++;
381 next;
382 };
383
384 /^-p(retty)?$/ && do {
385 print STDERR "$0: I'm afraid it's too late for prettiness.\n";
386 $PRETTY++;
387 next;
388 };
389
390 warn "Unknown flag: $_";
391 }
392
393 $oldwarn = $SIG{__WARN__};
394 $olddie = $SIG{__DIE__};
395 $SIG{__WARN__} = \&warn_trap;
396 $SIG{__DIE__} = \&death_trap;
397}
398
399sub enable { &import }
400
401sub disable {
402 shift;
403 $^W = $old_w;
404 return unless $SIG{__WARN__} eq \&warn_trap;
405 $SIG{__WARN__} = $oldwarn;
406 $SIG{__DIE__} = $olddie;
407}
408
409sub warn_trap {
410 my $warning = $_[0];
411 if (caller eq $WHOAMI or !splainthis($warning)) {
412 print STDERR $warning;
413 }
37120919 414 &$oldwarn if defined $oldwarn and $oldwarn and $oldwarn ne \&warn_trap;
4633a7c4
LW
415};
416
417sub death_trap {
418 my $exception = $_[0];
55497cff 419
420 # See if we are coming from anywhere within an eval. If so we don't
421 # want to explain the exception because it's going to get caught.
422 my $in_eval = 0;
423 my $i = 0;
424 while (1) {
425 my $caller = (caller($i++))[3] or last;
426 if ($caller eq '(eval)') {
427 $in_eval = 1;
428 last;
429 }
430 }
431
432 splainthis($exception) unless $in_eval;
4633a7c4 433 if (caller eq $WHOAMI) { print STDERR "INTERNAL EXCEPTION: $exception"; }
37120919 434 &$olddie if defined $olddie and $olddie and $olddie ne \&death_trap;
55497cff 435
436 # We don't want to unset these if we're coming from an eval because
437 # then we've turned off diagnostics. (Actually what does this next
438 # line do? -PSeibel)
439 $SIG{__DIE__} = $SIG{__WARN__} = '' unless $in_eval;
6f48387a 440 local($Carp::CarpLevel) = 1;
441 confess "Uncaught exception from user code:\n\t$exception";
4633a7c4
LW
442 # up we go; where we stop, nobody knows, but i think we die now
443 # but i'm deeply afraid of the &$olddie guy reraising and us getting
444 # into an indirect recursion loop
445};
446
447sub splainthis {
448 local $_ = shift;
449 ### &finish_compilation unless %msg;
450 s/\.?\n+$//;
451 my $orig = $_;
452 # return unless defined;
453 if ($exact_duplicate{$_}++) {
454 return 1;
455 }
456 s/, <.*?> (?:line|chunk).*$//;
457 $real = s/(.*?) at .*? (?:line|chunk) \d+.*/$1/;
458 s/^\((.*)\)$/$1/;
459 return 0 unless &transmo;
460 $orig = shorten($orig);
461 if ($old_diag{$_}) {
462 autodescribe();
463 print THITHER "$orig (#$old_diag{$_})\n";
464 $wantspace = 1;
465 } else {
466 autodescribe();
467 $old_diag{$_} = ++$count;
468 print THITHER "\n" if $wantspace;
469 $wantspace = 0;
470 print THITHER "$orig (#$old_diag{$_})\n";
471 if ($msg{$_}) {
472 print THITHER $msg{$_};
473 } else {
474 if (0 and $standalone) {
475 print THITHER " **** Error #$old_diag{$_} ",
476 ($real ? "is" : "appears to be"),
477 " an unknown diagnostic message.\n\n";
478 }
479 return 0;
480 }
481 }
482 return 1;
483}
484
485sub autodescribe {
486 if ($VERBOSE and not $count) {
487 print THITHER &{$PRETTY ? \&bold : \&noop}("DESCRIPTION OF DIAGNOSTICS"),
488 "\n$msg{DESCRIPTION}\n";
489 }
490}
491
492sub unescape {
493 s {
494 E<
495 ( [A-Za-z]+ )
496 >
497 } {
498 do {
499 exists $HTML_Escapes{$1}
500 ? do { $HTML_Escapes{$1} }
501 : do {
f02a87df 502 warn "Unknown escape: E<$1> in $_";
4633a7c4
LW
503 "E<$1>";
504 }
505 }
506 }egx;
507}
508
509sub shorten {
510 my $line = $_[0];
774d564b 511 if (length($line) > 79 and index($line, "\n") == -1) {
4633a7c4
LW
512 my $space_place = rindex($line, ' ', 79);
513 if ($space_place != -1) {
514 substr($line, $space_place, 1) = "\n\t";
515 }
516 }
517 return $line;
518}
519
520
521# have to do this: RS isn't set until run time, but we're executing at compile time
522$RS = "\n";
523
5241 unless $standalone; # or it'll complain about itself
525__END__ # wish diag dbase were more accessible