This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[PATCH] long C<=item>s in pod/perlunicode.pod
[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
327219e7 7splain - filter to produce verbose descriptions of perl warning diagnostics
4633a7c4
LW
8
9=head1 SYNOPSIS
10
11As a pragma:
12
13 use diagnostics;
14 use diagnostics -verbose;
15
16 enable diagnostics;
17 disable diagnostics;
18
327219e7 19As a program:
4633a7c4
LW
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
f610777f 30perl compiler and the perl interpreter, 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
ae2c041d 44Due to the interaction between runtime and compiletime issues,
4633a7c4 45and because it's probably not a very good idea anyway,
ae2c041d 46you may not use C<no diagnostics> to turn them off at compiletime.
3d0ae7ba 47However, you may control their behaviour at runtime using the
4633a7c4
LW
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 53
097b73fc
BB
54Warnings dispatched from perl itself (or more accurately, those that match
55descriptions found in L<perldiag>) are only displayed once (no duplicate
49704364 56descriptions). User code generated warnings a la warn() are unaffected,
097b73fc
BB
57allowing duplicate user messages to be displayed.
58
4633a7c4
LW
59=head2 The I<splain> Program
60
61While apparently a whole nuther program, I<splain> is actually nothing
62more than a link to the (executable) F<diagnostics.pm> module, as well as
63a link to the F<diagnostics.pod> documentation. The B<-v> flag is like
64the C<use diagnostics -verbose> directive.
65The B<-p> flag is like the
66$diagnostics::PRETTY variable. Since you're post-processing with
67I<splain>, there's no sense in being able to enable() or disable() processing.
68
69Output from I<splain> is directed to B<STDOUT>, unlike the pragma.
70
71=head1 EXAMPLES
72
73The following file is certain to trigger a few errors at both
ae2c041d 74runtime and compiletime:
4633a7c4
LW
75
76 use diagnostics;
77 print NOWHERE "nothing\n";
78 print STDERR "\n\tThis message should be unadorned.\n";
79 warn "\tThis is a user warning";
80 print "\nDIAGNOSTIC TESTER: Please enter a <CR> here: ";
81 my $a, $b = scalar <STDIN>;
82 print "\n";
83 print $x/$y;
84
85If you prefer to run your program first and look at its problem
86afterwards, do this:
87
88 perl -w test.pl 2>test.out
89 ./splain < test.out
90
91Note that this is not in general possible in shells of more dubious heritage,
1fef88e7 92as the theoretical
4633a7c4
LW
93
94 (perl -w test.pl >/dev/tty) >& test.out
95 ./splain < test.out
96
97Because you just moved the existing B<stdout> to somewhere else.
98
99If you don't want to modify your source code, but still have on-the-fly
100warnings, do this:
101
102 exec 3>&1; perl -w test.pl 2>&1 1>&3 3>&- | splain 1>&2 3>&-
103
104Nifty, eh?
105
106If you want to control warnings on the fly, do something like this.
107Make sure you do the C<use> first, or you won't be able to get
108at the enable() or disable() methods.
109
110 use diagnostics; # checks entire compilation phase
111 print "\ntime for 1st bogus diags: SQUAWKINGS\n";
112 print BOGUS1 'nada';
113 print "done with 1st bogus\n";
114
115 disable diagnostics; # only turns off runtime warnings
116 print "\ntime for 2nd bogus: (squelched)\n";
117 print BOGUS2 'nada';
118 print "done with 2nd bogus\n";
119
120 enable diagnostics; # turns back on runtime warnings
121 print "\ntime for 3rd bogus: SQUAWKINGS\n";
122 print BOGUS3 'nada';
123 print "done with 3rd bogus\n";
124
125 disable diagnostics;
126 print "\ntime for 4th bogus: (squelched)\n";
127 print BOGUS4 'nada';
128 print "done with 4th bogus\n";
129
130=head1 INTERNALS
131
132Diagnostic messages derive from the F<perldiag.pod> file when available at
133runtime. Otherwise, they may be embedded in the file itself when the
134splain package is built. See the F<Makefile> for details.
135
136If an extant $SIG{__WARN__} handler is discovered, it will continue
1fef88e7 137to be honored, but only after the diagnostics::splainthis() function
4633a7c4
LW
138(the module's $SIG{__WARN__} interceptor) has had its way with your
139warnings.
140
141There is a $diagnostics::DEBUG variable you may set if you're desperately
142curious what sorts of things are being intercepted.
143
144 BEGIN { $diagnostics::DEBUG = 1 }
145
146
147=head1 BUGS
148
149Not being able to say "no diagnostics" is annoying, but may not be
150insurmountable.
151
152The C<-pretty> directive is called too late to affect matters.
864e1151 153You have to do this instead, and I<before> you load the module.
4633a7c4
LW
154
155 BEGIN { $diagnostics::PRETTY = 1 }
156
157I could start up faster by delaying compilation until it should be
a6006777 158needed, but this gets a "panic: top_level" when using the pragma form
159in Perl 5.001e.
4633a7c4
LW
160
161While it's true that this documentation is somewhat subserious, if you use
162a program named I<splain>, you should expect a bit of whimsy.
163
164=head1 AUTHOR
165
352854fa 166Tom Christiansen <F<tchrist@mox.perl.com>>, 25 June 1995.
4633a7c4
LW
167
168=cut
169
7a4340ed 170use strict;
3b825e41 171use 5.006;
5f05dabc 172use Carp;
173
88d01e8d 174our $VERSION = 1.1;
7a4340ed
GS
175our $DEBUG;
176our $VERBOSE;
177our $PRETTY;
1e4e2d84 178
5f05dabc 179use Config;
7a4340ed 180my($privlib, $archlib) = @Config{qw(privlibexp archlibexp)};
5f05dabc 181if ($^O eq 'VMS') {
91a06757
CS
182 require VMS::Filespec;
183 $privlib = VMS::Filespec::unixify($privlib);
184 $archlib = VMS::Filespec::unixify($archlib);
5f05dabc 185}
7a4340ed 186my @trypod = (
7ec2cea4 187 "$archlib/pod/perldiag.pod",
0ff3fa1a 188 "$privlib/pod/perldiag-$Config{version}.pod",
5459498c 189 "$privlib/pod/perldiag.pod",
7ec2cea4 190 "$archlib/pods/perldiag.pod",
0ff3fa1a 191 "$privlib/pods/perldiag-$Config{version}.pod",
5459498c 192 "$privlib/pods/perldiag.pod",
7ec2cea4 193 );
fb73857a 194# handy for development testing of new warnings etc
195unshift @trypod, "./pod/perldiag.pod" if -e "pod/perldiag.pod";
7a4340ed 196(my $PODFILE) = ((grep { -e } @trypod), $trypod[$#trypod])[0];
5f05dabc 197
95e8664e
CN
198if ($^O eq 'MacOS') {
199 # just updir one from each lib dir, we'll find it ...
200 ($PODFILE) = grep { -e } map { "$_:pod:perldiag.pod" } @INC;
201}
202
203
4633a7c4
LW
204$DEBUG ||= 0;
205my $WHOAMI = ref bless []; # nobody's business, prolly not even mine
206
7a4340ed 207local $| = 1;
4633a7c4
LW
208local $_;
209
7a4340ed
GS
210my $standalone;
211my(%HTML_2_Troff, %HTML_2_Latin_1, %HTML_2_ASCII_7);
212
4633a7c4 213CONFIG: {
7a4340ed 214 our $opt_p = our $opt_d = our $opt_v = our $opt_f = '';
4633a7c4 215
7a4340ed 216 unless (caller) {
4633a7c4
LW
217 $standalone++;
218 require Getopt::Std;
91a06757
CS
219 Getopt::Std::getopts('pdvf:')
220 or die "Usage: $0 [-v] [-p] [-f splainpod]";
4633a7c4
LW
221 $PODFILE = $opt_f if $opt_f;
222 $DEBUG = 2 if $opt_d;
223 $VERBOSE = $opt_v;
224 $PRETTY = $opt_p;
7a4340ed 225 }
4633a7c4
LW
226
227 if (open(POD_DIAG, $PODFILE)) {
228 warn "Happy happy podfile from real $PODFILE\n" if $DEBUG;
229 last CONFIG;
230 }
231
232 if (caller) {
233 INCPATH: {
7a4340ed 234 for my $file ( (map { "$_/$WHOAMI.pm" } @INC), $0) {
4633a7c4
LW
235 warn "Checking $file\n" if $DEBUG;
236 if (open(POD_DIAG, $file)) {
237 while (<POD_DIAG>) {
7a4340ed
GS
238 next unless
239 /^__END__\s*# wish diag dbase were more accessible/;
4633a7c4
LW
240 print STDERR "podfile is $file\n" if $DEBUG;
241 last INCPATH;
242 }
243 }
244 }
245 }
246 } else {
247 print STDERR "podfile is <DATA>\n" if $DEBUG;
248 *POD_DIAG = *main::DATA;
249 }
250}
251if (eof(POD_DIAG)) {
252 die "couldn't find diagnostic data in $PODFILE @INC $0";
253}
254
255
256%HTML_2_Troff = (
257 'amp' => '&', # ampersand
258 'lt' => '<', # left chevron, less-than
259 'gt' => '>', # right chevron, greater-than
260 'quot' => '"', # double quote
261
262 "Aacute" => "A\\*'", # capital A, acute accent
263 # etc
264
265);
266
267%HTML_2_Latin_1 = (
268 'amp' => '&', # ampersand
269 'lt' => '<', # left chevron, less-than
270 'gt' => '>', # right chevron, greater-than
271 'quot' => '"', # double quote
272
273 "Aacute" => "\xC1" # capital A, acute accent
274
275 # etc
276);
277
278%HTML_2_ASCII_7 = (
279 'amp' => '&', # ampersand
280 'lt' => '<', # left chevron, less-than
281 'gt' => '>', # right chevron, greater-than
282 'quot' => '"', # double quote
283
284 "Aacute" => "A" # capital A, acute accent
285 # etc
286);
287
7a4340ed 288our %HTML_Escapes;
4633a7c4
LW
289*HTML_Escapes = do {
290 if ($standalone) {
291 $PRETTY ? \%HTML_2_Latin_1 : \%HTML_2_ASCII_7;
292 } else {
293 \%HTML_2_Latin_1;
294 }
295};
296
297*THITHER = $standalone ? *STDOUT : *STDERR;
298
49704364 299my %transfmt = ();
7a4340ed 300my $transmo = <<EOFUNC;
4633a7c4 301sub transmo {
599cee73 302 #local \$^W = 0; # recursive warnings we do NOT need!
4633a7c4
LW
303 study;
304EOFUNC
305
7a4340ed
GS
306my %msg;
307{
4633a7c4 308 print STDERR "FINISHING COMPILATION for $_\n" if $DEBUG;
7a4340ed 309 local $/ = '';
4633a7c4 310 local $_;
7a4340ed
GS
311 my $header;
312 my $for_item;
4633a7c4 313 while (<POD_DIAG>) {
4633a7c4
LW
314
315 unescape();
316 if ($PRETTY) {
317 sub noop { return $_[0] } # spensive for a noop
318 sub bold { my $str =$_[0]; $str =~ s/(.)/$1\b$1/g; return $str; }
319 sub italic { my $str = $_[0]; $str =~ s/(.)/_\b$1/g; return $str; }
320 s/[BC]<(.*?)>/bold($1)/ges;
321 s/[LIF]<(.*?)>/italic($1)/ges;
322 } else {
323 s/[BC]<(.*?)>/$1/gs;
324 s/[LIF]<(.*?)>/$1/gs;
325 }
326 unless (/^=/) {
327 if (defined $header) {
328 if ( $header eq 'DESCRIPTION' &&
329 ( /Optional warnings are enabled/
330 || /Some of these messages are generic./
331 ) )
332 {
333 next;
49704364 334 }
4633a7c4
LW
335 s/^/ /gm;
336 $msg{$header} .= $_;
7a4340ed 337 undef $for_item;
4633a7c4
LW
338 }
339 next;
340 }
7a4340ed 341 unless ( s/=item (.*?)\s*\z//) {
4633a7c4
LW
342
343 if ( s/=head1\sDESCRIPTION//) {
344 $msg{$header = 'DESCRIPTION'} = '';
7a4340ed 345 undef $for_item;
4633a7c4 346 }
7a4340ed
GS
347 elsif( s/^=for\s+diagnostics\s*\n(.*?)\s*\z// ) {
348 $for_item = $1;
349 }
4633a7c4
LW
350 next;
351 }
4fdae800 352
5cd5c422
RB
353 if( $for_item ) { $header = $for_item; undef $for_item }
354 else {
355 $header = $1;
356 while( $header =~ /[;,]\z/ ) {
357 <POD_DIAG> =~ /^\s*(.*?)\s*\z/;
358 $header .= ' '.$1;
359 }
360 }
361
49704364 362 # strip formatting directives from =item line
7a4340ed 363 $header =~ s/[A-Z]<(.*?)>/$1/g;
4633a7c4 364
49704364
WL
365 my @toks = split( /(%l?[dx]|%c|%(?:\.\d+)?s)/, $header );
366 if (@toks > 1) {
367 my $conlen = 0;
368 for my $i (0..$#toks){
369 if( $i % 2 ){
370 if( $toks[$i] eq '%c' ){
371 $toks[$i] = '.';
372 } elsif( $toks[$i] eq '%d' ){
373 $toks[$i] = '\d+';
374 } elsif( $toks[$i] eq '%s' ){
375 $toks[$i] = $i == $#toks ? '.*' : '.*?';
376 } elsif( $toks[$i] =~ '%.(\d+)s' ){
377 $toks[$i] = ".{$1}";
378 } elsif( $toks[$i] =~ '^%l*x$' ){
379 $toks[$i] = '[\da-f]+';
380 }
381 } elsif( length( $toks[$i] ) ){
382 $toks[$i] =~ s/^.*$/\Q$&\E/;
383 $conlen += length( $toks[$i] );
384 }
385 }
386 my $lhs = join( '', @toks );
387 $transfmt{$header}{pat} =
388 " s{^$lhs}\n {\Q$header\E}s\n\t&& return 1;\n";
389 $transfmt{$header}{len} = $conlen;
4633a7c4 390 } else {
49704364
WL
391 $transfmt{$header}{pat} =
392 " m{^\Q$header\E} && return 1;\n";
393 $transfmt{$header}{len} = length( $header );
4633a7c4
LW
394 }
395
eff9c6e2
CS
396 print STDERR "$WHOAMI: Duplicate entry: \"$header\"\n"
397 if $msg{$header};
4633a7c4
LW
398
399 $msg{$header} = '';
400 }
401
402
403 close POD_DIAG unless *main::DATA eq *POD_DIAG;
404
405 die "No diagnostics?" unless %msg;
406
49704364
WL
407 # Apply patterns in order of decreasing sum of lengths of fixed parts
408 # Seems the best way of hitting the right one.
409 for my $hdr ( sort { $transfmt{$b}{len} <=> $transfmt{$a}{len} }
410 keys %transfmt ){
411 $transmo .= $transfmt{$hdr}{pat};
412 }
4633a7c4
LW
413 $transmo .= " return 0;\n}\n";
414 print STDERR $transmo if $DEBUG;
415 eval $transmo;
416 die $@ if $@;
7a4340ed 417}
4633a7c4
LW
418
419if ($standalone) {
420 if (!@ARGV and -t STDIN) { print STDERR "$0: Reading from STDIN\n" }
7a4340ed 421 while (defined (my $error = <>)) {
4633a7c4
LW
422 splainthis($error) || print THITHER $error;
423 }
424 exit;
7a4340ed
GS
425}
426
427my $olddie;
428my $oldwarn;
4633a7c4
LW
429
430sub import {
431 shift;
7a4340ed
GS
432 $^W = 1; # yup, clobbered the global variable;
433 # tough, if you want diags, you want diags.
0dc02ca5 434 return if defined $SIG{__WARN__} && ($SIG{__WARN__} eq \&warn_trap);
4633a7c4
LW
435
436 for (@_) {
437
438 /^-d(ebug)?$/ && do {
439 $DEBUG++;
440 next;
441 };
442
443 /^-v(erbose)?$/ && do {
444 $VERBOSE++;
445 next;
446 };
447
448 /^-p(retty)?$/ && do {
449 print STDERR "$0: I'm afraid it's too late for prettiness.\n";
450 $PRETTY++;
451 next;
452 };
453
454 warn "Unknown flag: $_";
455 }
456
457 $oldwarn = $SIG{__WARN__};
458 $olddie = $SIG{__DIE__};
459 $SIG{__WARN__} = \&warn_trap;
460 $SIG{__DIE__} = \&death_trap;
461}
462
463sub enable { &import }
464
465sub disable {
466 shift;
4633a7c4 467 return unless $SIG{__WARN__} eq \&warn_trap;
3d0ae7ba
GS
468 $SIG{__WARN__} = $oldwarn || '';
469 $SIG{__DIE__} = $olddie || '';
4633a7c4
LW
470}
471
472sub warn_trap {
473 my $warning = $_[0];
474 if (caller eq $WHOAMI or !splainthis($warning)) {
475 print STDERR $warning;
476 }
37120919 477 &$oldwarn if defined $oldwarn and $oldwarn and $oldwarn ne \&warn_trap;
4633a7c4
LW
478};
479
480sub death_trap {
481 my $exception = $_[0];
55497cff 482
483 # See if we are coming from anywhere within an eval. If so we don't
484 # want to explain the exception because it's going to get caught.
485 my $in_eval = 0;
486 my $i = 0;
487 while (1) {
488 my $caller = (caller($i++))[3] or last;
489 if ($caller eq '(eval)') {
490 $in_eval = 1;
491 last;
492 }
493 }
494
495 splainthis($exception) unless $in_eval;
4633a7c4 496 if (caller eq $WHOAMI) { print STDERR "INTERNAL EXCEPTION: $exception"; }
37120919 497 &$olddie if defined $olddie and $olddie and $olddie ne \&death_trap;
55497cff 498
d23f0205
MS
499 return if $in_eval;
500
55497cff 501 # We don't want to unset these if we're coming from an eval because
d23f0205
MS
502 # then we've turned off diagnostics.
503
504 # Switch off our die/warn handlers so we don't wind up in our own
505 # traps.
506 $SIG{__DIE__} = $SIG{__WARN__} = '';
507
508 # Have carp skip over death_trap() when showing the stack trace.
6f48387a 509 local($Carp::CarpLevel) = 1;
d23f0205 510
6f48387a 511 confess "Uncaught exception from user code:\n\t$exception";
4633a7c4
LW
512 # up we go; where we stop, nobody knows, but i think we die now
513 # but i'm deeply afraid of the &$olddie guy reraising and us getting
514 # into an indirect recursion loop
515};
516
7a4340ed
GS
517my %exact_duplicate;
518my %old_diag;
519my $count;
520my $wantspace;
4633a7c4
LW
521sub splainthis {
522 local $_ = shift;
5025c45a 523 local $\;
4633a7c4
LW
524 ### &finish_compilation unless %msg;
525 s/\.?\n+$//;
526 my $orig = $_;
527 # return unless defined;
49704364
WL
528
529 # get rid of the where-are-we-in-input part
4633a7c4 530 s/, <.*?> (?:line|chunk).*$//;
49704364
WL
531
532 # Discard 1st " at <file> line <no>" and all text beyond
533 # but be aware of messsages containing " at this-or-that"
534 my $real = 0;
535 my @secs = split( / at / );
536 $_ = $secs[0];
537 for my $i ( 1..$#secs ){
538 if( $secs[$i] =~ /.+? (?:line|chunk) \d+/ ){
539 $real = 1;
540 last;
541 } else {
542 $_ .= ' at ' . $secs[$i];
543 }
544 }
545
546 # remove parenthesis occurring at the end of some messages
4633a7c4 547 s/^\((.*)\)$/$1/;
49704364 548
097b73fc
BB
549 if ($exact_duplicate{$orig}++) {
550 return &transmo;
49704364 551 } else {
097b73fc
BB
552 return 0 unless &transmo;
553 }
49704364 554
4633a7c4
LW
555 $orig = shorten($orig);
556 if ($old_diag{$_}) {
557 autodescribe();
558 print THITHER "$orig (#$old_diag{$_})\n";
559 $wantspace = 1;
560 } else {
561 autodescribe();
562 $old_diag{$_} = ++$count;
563 print THITHER "\n" if $wantspace;
564 $wantspace = 0;
565 print THITHER "$orig (#$old_diag{$_})\n";
566 if ($msg{$_}) {
567 print THITHER $msg{$_};
568 } else {
569 if (0 and $standalone) {
570 print THITHER " **** Error #$old_diag{$_} ",
571 ($real ? "is" : "appears to be"),
572 " an unknown diagnostic message.\n\n";
573 }
574 return 0;
575 }
576 }
577 return 1;
578}
579
580sub autodescribe {
581 if ($VERBOSE and not $count) {
582 print THITHER &{$PRETTY ? \&bold : \&noop}("DESCRIPTION OF DIAGNOSTICS"),
583 "\n$msg{DESCRIPTION}\n";
584 }
585}
586
587sub unescape {
588 s {
589 E<
590 ( [A-Za-z]+ )
591 >
592 } {
593 do {
594 exists $HTML_Escapes{$1}
595 ? do { $HTML_Escapes{$1} }
596 : do {
f02a87df 597 warn "Unknown escape: E<$1> in $_";
4633a7c4
LW
598 "E<$1>";
599 }
600 }
601 }egx;
602}
603
604sub shorten {
605 my $line = $_[0];
774d564b 606 if (length($line) > 79 and index($line, "\n") == -1) {
4633a7c4
LW
607 my $space_place = rindex($line, ' ', 79);
608 if ($space_place != -1) {
609 substr($line, $space_place, 1) = "\n\t";
610 }
611 }
612 return $line;
613}
614
615
4633a7c4
LW
6161 unless $standalone; # or it'll complain about itself
617__END__ # wish diag dbase were more accessible