Initial bulk commit for "Git on MSys"
[msysgit/historical-msysgit.git] / lib / perl5 / 5.6.1 / diagnostics.pm
blob48bb04448c90beddea782d626cbc34e35deeea29
1 package diagnostics;
3 =head1 NAME
5 diagnostics - Perl compiler pragma to force verbose warning diagnostics
7 splain - standalone program to do the same thing
9 =head1 SYNOPSIS
11 As a pragma:
13 use diagnostics;
14 use diagnostics -verbose;
16 enable diagnostics;
17 disable diagnostics;
19 Aa a program:
21 perl program 2>diag.out
22 splain [-v] [-p] diag.out
25 =head1 DESCRIPTION
27 =head2 The C<diagnostics> Pragma
29 This module extends the terse diagnostics normally emitted by both the
30 perl compiler and the perl interpreter, augmenting them with the more
31 explicative and endearing descriptions found in L<perldiag>. Like the
32 other pragmata, it affects the compilation phase of your program rather
33 than merely the execution phase.
35 To use in your program as a pragma, merely invoke
37 use diagnostics;
39 at the start (or near the start) of your program. (Note
40 that this I<does> enable perl's B<-w> flag.) Your whole
41 compilation will then be subject(ed :-) to the enhanced diagnostics.
42 These still go out B<STDERR>.
44 Due to the interaction between runtime and compiletime issues,
45 and because it's probably not a very good idea anyway,
46 you may not use C<no diagnostics> to turn them off at compiletime.
47 However, you may control their behaviour at runtime using the
48 disable() and enable() methods to turn them off and on respectively.
50 The B<-verbose> flag first prints out the L<perldiag> introduction before
51 any other diagnostics. The $diagnostics::PRETTY variable can generate nicer
52 escape sequences for pagers.
54 Warnings dispatched from perl itself (or more accurately, those that match
55 descriptions found in L<perldiag>) are only displayed once (no duplicate
56 descriptions). User code generated warnings ala warn() are unaffected,
57 allowing duplicate user messages to be displayed.
59 =head2 The I<splain> Program
61 While apparently a whole nuther program, I<splain> is actually nothing
62 more than a link to the (executable) F<diagnostics.pm> module, as well as
63 a link to the F<diagnostics.pod> documentation. The B<-v> flag is like
64 the C<use diagnostics -verbose> directive.
65 The B<-p> flag is like the
66 $diagnostics::PRETTY variable. Since you're post-processing with
67 I<splain>, there's no sense in being able to enable() or disable() processing.
69 Output from I<splain> is directed to B<STDOUT>, unlike the pragma.
71 =head1 EXAMPLES
73 The following file is certain to trigger a few errors at both
74 runtime and compiletime:
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;
85 If you prefer to run your program first and look at its problem
86 afterwards, do this:
88 perl -w test.pl 2>test.out
89 ./splain < test.out
91 Note that this is not in general possible in shells of more dubious heritage,
92 as the theoretical
94 (perl -w test.pl >/dev/tty) >& test.out
95 ./splain < test.out
97 Because you just moved the existing B<stdout> to somewhere else.
99 If you don't want to modify your source code, but still have on-the-fly
100 warnings, do this:
102 exec 3>&1; perl -w test.pl 2>&1 1>&3 3>&- | splain 1>&2 3>&-
104 Nifty, eh?
106 If you want to control warnings on the fly, do something like this.
107 Make sure you do the C<use> first, or you won't be able to get
108 at the enable() or disable() methods.
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";
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";
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";
125 disable diagnostics;
126 print "\ntime for 4th bogus: (squelched)\n";
127 print BOGUS4 'nada';
128 print "done with 4th bogus\n";
130 =head1 INTERNALS
132 Diagnostic messages derive from the F<perldiag.pod> file when available at
133 runtime. Otherwise, they may be embedded in the file itself when the
134 splain package is built. See the F<Makefile> for details.
136 If an extant $SIG{__WARN__} handler is discovered, it will continue
137 to be honored, but only after the diagnostics::splainthis() function
138 (the module's $SIG{__WARN__} interceptor) has had its way with your
139 warnings.
141 There is a $diagnostics::DEBUG variable you may set if you're desperately
142 curious what sorts of things are being intercepted.
144 BEGIN { $diagnostics::DEBUG = 1 }
147 =head1 BUGS
149 Not being able to say "no diagnostics" is annoying, but may not be
150 insurmountable.
152 The C<-pretty> directive is called too late to affect matters.
153 You have to do this instead, and I<before> you load the module.
155 BEGIN { $diagnostics::PRETTY = 1 }
157 I could start up faster by delaying compilation until it should be
158 needed, but this gets a "panic: top_level" when using the pragma form
159 in Perl 5.001e.
161 While it's true that this documentation is somewhat subserious, if you use
162 a program named I<splain>, you should expect a bit of whimsy.
164 =head1 AUTHOR
166 Tom Christiansen <F<tchrist@mox.perl.com>>, 25 June 1995.
168 =cut
170 use strict;
171 use 5.6.0;
172 use Carp;
174 our $VERSION = 1.0;
175 our $DEBUG;
176 our $VERBOSE;
177 our $PRETTY;
179 use Config;
180 my($privlib, $archlib) = @Config{qw(privlibexp archlibexp)};
181 if ($^O eq 'VMS') {
182 require VMS::Filespec;
183 $privlib = VMS::Filespec::unixify($privlib);
184 $archlib = VMS::Filespec::unixify($archlib);
186 my @trypod = (
187 "$archlib/pod/perldiag.pod",
188 "$privlib/pod/perldiag-$Config{version}.pod",
189 "$privlib/pod/perldiag.pod",
190 "$archlib/pods/perldiag.pod",
191 "$privlib/pods/perldiag-$Config{version}.pod",
192 "$privlib/pods/perldiag.pod",
194 # handy for development testing of new warnings etc
195 unshift @trypod, "./pod/perldiag.pod" if -e "pod/perldiag.pod";
196 (my $PODFILE) = ((grep { -e } @trypod), $trypod[$#trypod])[0];
198 if ($^O eq 'MacOS') {
199 # just updir one from each lib dir, we'll find it ...
200 ($PODFILE) = grep { -e } map { "$_:pod:perldiag.pod" } @INC;
203 $DEBUG ||= 0;
204 my $WHOAMI = ref bless []; # nobody's business, prolly not even mine
206 local $| = 1;
207 local $_;
209 my $standalone;
210 my(%HTML_2_Troff, %HTML_2_Latin_1, %HTML_2_ASCII_7);
212 CONFIG: {
213 our $opt_p = our $opt_d = our $opt_v = our $opt_f = '';
215 unless (caller) {
216 $standalone++;
217 require Getopt::Std;
218 Getopt::Std::getopts('pdvf:')
219 or die "Usage: $0 [-v] [-p] [-f splainpod]";
220 $PODFILE = $opt_f if $opt_f;
221 $DEBUG = 2 if $opt_d;
222 $VERBOSE = $opt_v;
223 $PRETTY = $opt_p;
226 if (open(POD_DIAG, $PODFILE)) {
227 warn "Happy happy podfile from real $PODFILE\n" if $DEBUG;
228 last CONFIG;
231 if (caller) {
232 INCPATH: {
233 for my $file ( (map { "$_/$WHOAMI.pm" } @INC), $0) {
234 warn "Checking $file\n" if $DEBUG;
235 if (open(POD_DIAG, $file)) {
236 while (<POD_DIAG>) {
237 next unless
238 /^__END__\s*# wish diag dbase were more accessible/;
239 print STDERR "podfile is $file\n" if $DEBUG;
240 last INCPATH;
245 } else {
246 print STDERR "podfile is <DATA>\n" if $DEBUG;
247 *POD_DIAG = *main::DATA;
250 if (eof(POD_DIAG)) {
251 die "couldn't find diagnostic data in $PODFILE @INC $0";
255 %HTML_2_Troff = (
256 'amp' => '&', # ampersand
257 'lt' => '<', # left chevron, less-than
258 'gt' => '>', # right chevron, greater-than
259 'quot' => '"', # double quote
261 "Aacute" => "A\\*'", # capital A, acute accent
262 # etc
266 %HTML_2_Latin_1 = (
267 'amp' => '&', # ampersand
268 'lt' => '<', # left chevron, less-than
269 'gt' => '>', # right chevron, greater-than
270 'quot' => '"', # double quote
272 "Aacute" => "\xC1" # capital A, acute accent
274 # etc
277 %HTML_2_ASCII_7 = (
278 'amp' => '&', # ampersand
279 'lt' => '<', # left chevron, less-than
280 'gt' => '>', # right chevron, greater-than
281 'quot' => '"', # double quote
283 "Aacute" => "A" # capital A, acute accent
284 # etc
287 our %HTML_Escapes;
288 *HTML_Escapes = do {
289 if ($standalone) {
290 $PRETTY ? \%HTML_2_Latin_1 : \%HTML_2_ASCII_7;
291 } else {
292 \%HTML_2_Latin_1;
296 *THITHER = $standalone ? *STDOUT : *STDERR;
298 my $transmo = <<EOFUNC;
299 sub transmo {
300 #local \$^W = 0; # recursive warnings we do NOT need!
301 study;
302 EOFUNC
304 my %msg;
306 print STDERR "FINISHING COMPILATION for $_\n" if $DEBUG;
307 local $/ = '';
308 local $_;
309 my $header;
310 my $for_item;
311 while (<POD_DIAG>) {
313 unescape();
314 if ($PRETTY) {
315 sub noop { return $_[0] } # spensive for a noop
316 sub bold { my $str =$_[0]; $str =~ s/(.)/$1\b$1/g; return $str; }
317 sub italic { my $str = $_[0]; $str =~ s/(.)/_\b$1/g; return $str; }
318 s/[BC]<(.*?)>/bold($1)/ges;
319 s/[LIF]<(.*?)>/italic($1)/ges;
320 } else {
321 s/[BC]<(.*?)>/$1/gs;
322 s/[LIF]<(.*?)>/$1/gs;
324 unless (/^=/) {
325 if (defined $header) {
326 if ( $header eq 'DESCRIPTION' &&
327 ( /Optional warnings are enabled/
328 || /Some of these messages are generic./
331 next;
333 s/^/ /gm;
334 $msg{$header} .= $_;
335 undef $for_item;
337 next;
339 unless ( s/=item (.*?)\s*\z//) {
341 if ( s/=head1\sDESCRIPTION//) {
342 $msg{$header = 'DESCRIPTION'} = '';
343 undef $for_item;
345 elsif( s/^=for\s+diagnostics\s*\n(.*?)\s*\z// ) {
346 $for_item = $1;
348 next;
351 # strip formatting directives in =item line
352 $header = $for_item || $1;
353 undef $for_item;
354 $header =~ s/[A-Z]<(.*?)>/$1/g;
356 if ($header =~ /%[csd]/) {
357 my $rhs = my $lhs = $header;
358 if ($lhs =~ s/(.*?)%d(?!%d)(.*)/\Q$1\E-?\\d+\Q$2\E/g) {
359 $lhs =~ s/\\%s/.*?/g;
360 } else {
361 # if i had lookbehind negations,
362 # i wouldn't have to do this \377 noise
363 $lhs =~ s/(.*?)%s/\Q$1\E.*?\377/g;
364 $lhs =~ s/\377([^\377]*)$/\Q$1\E/;
365 $lhs =~ s/\377//g;
366 $lhs =~ s/\.\*\?$/.*/; # Allow %s at the end to eat it all
368 $lhs =~ s/\\%c/./g;
369 $transmo .= " s{^$lhs}\n {\Q$rhs\E}s\n\t&& return 1;\n";
370 } else {
371 $transmo .= " m{^\Q$header\E} && return 1;\n";
374 print STDERR "$WHOAMI: Duplicate entry: \"$header\"\n"
375 if $msg{$header};
377 $msg{$header} = '';
381 close POD_DIAG unless *main::DATA eq *POD_DIAG;
383 die "No diagnostics?" unless %msg;
385 $transmo .= " return 0;\n}\n";
386 print STDERR $transmo if $DEBUG;
387 eval $transmo;
388 die $@ if $@;
391 if ($standalone) {
392 if (!@ARGV and -t STDIN) { print STDERR "$0: Reading from STDIN\n" }
393 while (defined (my $error = <>)) {
394 splainthis($error) || print THITHER $error;
396 exit;
399 my $olddie;
400 my $oldwarn;
402 sub import {
403 shift;
404 $^W = 1; # yup, clobbered the global variable;
405 # tough, if you want diags, you want diags.
406 return if $SIG{__WARN__} eq \&warn_trap;
408 for (@_) {
410 /^-d(ebug)?$/ && do {
411 $DEBUG++;
412 next;
415 /^-v(erbose)?$/ && do {
416 $VERBOSE++;
417 next;
420 /^-p(retty)?$/ && do {
421 print STDERR "$0: I'm afraid it's too late for prettiness.\n";
422 $PRETTY++;
423 next;
426 warn "Unknown flag: $_";
429 $oldwarn = $SIG{__WARN__};
430 $olddie = $SIG{__DIE__};
431 $SIG{__WARN__} = \&warn_trap;
432 $SIG{__DIE__} = \&death_trap;
435 sub enable { &import }
437 sub disable {
438 shift;
439 return unless $SIG{__WARN__} eq \&warn_trap;
440 $SIG{__WARN__} = $oldwarn || '';
441 $SIG{__DIE__} = $olddie || '';
444 sub warn_trap {
445 my $warning = $_[0];
446 if (caller eq $WHOAMI or !splainthis($warning)) {
447 print STDERR $warning;
449 &$oldwarn if defined $oldwarn and $oldwarn and $oldwarn ne \&warn_trap;
452 sub death_trap {
453 my $exception = $_[0];
455 # See if we are coming from anywhere within an eval. If so we don't
456 # want to explain the exception because it's going to get caught.
457 my $in_eval = 0;
458 my $i = 0;
459 while (1) {
460 my $caller = (caller($i++))[3] or last;
461 if ($caller eq '(eval)') {
462 $in_eval = 1;
463 last;
467 splainthis($exception) unless $in_eval;
468 if (caller eq $WHOAMI) { print STDERR "INTERNAL EXCEPTION: $exception"; }
469 &$olddie if defined $olddie and $olddie and $olddie ne \&death_trap;
471 # We don't want to unset these if we're coming from an eval because
472 # then we've turned off diagnostics. (Actually what does this next
473 # line do? -PSeibel)
474 $SIG{__DIE__} = $SIG{__WARN__} = '' unless $in_eval;
475 local($Carp::CarpLevel) = 1;
476 confess "Uncaught exception from user code:\n\t$exception";
477 # up we go; where we stop, nobody knows, but i think we die now
478 # but i'm deeply afraid of the &$olddie guy reraising and us getting
479 # into an indirect recursion loop
482 my %exact_duplicate;
483 my %old_diag;
484 my $count;
485 my $wantspace;
486 sub splainthis {
487 local $_ = shift;
488 local $\;
489 ### &finish_compilation unless %msg;
490 s/\.?\n+$//;
491 my $orig = $_;
492 # return unless defined;
493 s/, <.*?> (?:line|chunk).*$//;
494 my $real = s/(.*?) at .*? (?:line|chunk) \d+.*/$1/;
495 s/^\((.*)\)$/$1/;
496 if ($exact_duplicate{$orig}++) {
497 return &transmo;
499 else {
500 return 0 unless &transmo;
502 $orig = shorten($orig);
503 if ($old_diag{$_}) {
504 autodescribe();
505 print THITHER "$orig (#$old_diag{$_})\n";
506 $wantspace = 1;
507 } else {
508 autodescribe();
509 $old_diag{$_} = ++$count;
510 print THITHER "\n" if $wantspace;
511 $wantspace = 0;
512 print THITHER "$orig (#$old_diag{$_})\n";
513 if ($msg{$_}) {
514 print THITHER $msg{$_};
515 } else {
516 if (0 and $standalone) {
517 print THITHER " **** Error #$old_diag{$_} ",
518 ($real ? "is" : "appears to be"),
519 " an unknown diagnostic message.\n\n";
521 return 0;
524 return 1;
527 sub autodescribe {
528 if ($VERBOSE and not $count) {
529 print THITHER &{$PRETTY ? \&bold : \&noop}("DESCRIPTION OF DIAGNOSTICS"),
530 "\n$msg{DESCRIPTION}\n";
534 sub unescape {
537 ( [A-Za-z]+ )
539 } {
540 do {
541 exists $HTML_Escapes{$1}
542 ? do { $HTML_Escapes{$1} }
543 : do {
544 warn "Unknown escape: E<$1> in $_";
545 "E<$1>";
548 }egx;
551 sub shorten {
552 my $line = $_[0];
553 if (length($line) > 79 and index($line, "\n") == -1) {
554 my $space_place = rindex($line, ' ', 79);
555 if ($space_place != -1) {
556 substr($line, $space_place, 1) = "\n\t";
559 return $line;
563 1 unless $standalone; # or it'll complain about itself
564 __END__ # wish diag dbase were more accessible