This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
lib/diagnostics.pm: Generalize for EBCDIC
[perl5.git] / lib / diagnostics.pm
CommitLineData
4633a7c4 1package diagnostics;
4633a7c4
LW
2
3=head1 NAME
4
c7bcd97d 5diagnostics, splain - produce verbose warning diagnostics
4633a7c4
LW
6
7=head1 SYNOPSIS
8
c7bcd97d 9Using the C<diagnostics> pragma:
4633a7c4
LW
10
11 use diagnostics;
12 use diagnostics -verbose;
13
14 enable diagnostics;
15 disable diagnostics;
16
c7bcd97d 17Using the C<splain> standalone filter program:
4633a7c4
LW
18
19 perl program 2>diag.out
20 splain [-v] [-p] diag.out
21
58618f23
FD
22Using diagnostics to get stack traces from a misbehaving script:
23
24 perl -Mdiagnostics=-traceonly my_script.pl
25
4633a7c4
LW
26=head1 DESCRIPTION
27
28=head2 The C<diagnostics> Pragma
29
30This module extends the terse diagnostics normally emitted by both the
c411974d
SP
31perl compiler and the perl interpreter (from running perl with a -w
32switch or C<use warnings>), augmenting them with the more
4633a7c4 33explicative and endearing descriptions found in L<perldiag>. Like the
1fef88e7 34other pragmata, it affects the compilation phase of your program rather
4633a7c4
LW
35than merely the execution phase.
36
37To use in your program as a pragma, merely invoke
38
39 use diagnostics;
40
41at the start (or near the start) of your program. (Note
42that this I<does> enable perl's B<-w> flag.) Your whole
43compilation will then be subject(ed :-) to the enhanced diagnostics.
44These still go out B<STDERR>.
45
ae2c041d 46Due to the interaction between runtime and compiletime issues,
4633a7c4 47and because it's probably not a very good idea anyway,
ae2c041d 48you may not use C<no diagnostics> to turn them off at compiletime.
3d0ae7ba 49However, you may control their behaviour at runtime using the
4633a7c4
LW
50disable() and enable() methods to turn them off and on respectively.
51
52The B<-verbose> flag first prints out the L<perldiag> introduction before
1fef88e7
JM
53any other diagnostics. The $diagnostics::PRETTY variable can generate nicer
54escape sequences for pagers.
4633a7c4 55
097b73fc
BB
56Warnings dispatched from perl itself (or more accurately, those that match
57descriptions found in L<perldiag>) are only displayed once (no duplicate
49704364 58descriptions). User code generated warnings a la warn() are unaffected,
097b73fc
BB
59allowing duplicate user messages to be displayed.
60
58618f23 61This module also adds a stack trace to the error message when perl dies.
f8c3fed4
FC
62This is useful for pinpointing what
63caused the death. The B<-traceonly> (or
3c4b39be 64just B<-t>) flag turns off the explanations of warning messages leaving just
f8c3fed4 65the stack traces. So if your script is dieing, run it again with
58618f23
FD
66
67 perl -Mdiagnostics=-traceonly my_bad_script
68
f8c3fed4 69to see the call stack at the time of death. By supplying the B<-warntrace>
58618f23
FD
70(or just B<-w>) flag, any warnings emitted will also come with a stack
71trace.
72
4633a7c4
LW
73=head2 The I<splain> Program
74
75While apparently a whole nuther program, I<splain> is actually nothing
76more than a link to the (executable) F<diagnostics.pm> module, as well as
77a link to the F<diagnostics.pod> documentation. The B<-v> flag is like
78the C<use diagnostics -verbose> directive.
79The B<-p> flag is like the
80$diagnostics::PRETTY variable. Since you're post-processing with
81I<splain>, there's no sense in being able to enable() or disable() processing.
82
83Output from I<splain> is directed to B<STDOUT>, unlike the pragma.
84
85=head1 EXAMPLES
86
87The following file is certain to trigger a few errors at both
ae2c041d 88runtime and compiletime:
4633a7c4
LW
89
90 use diagnostics;
91 print NOWHERE "nothing\n";
92 print STDERR "\n\tThis message should be unadorned.\n";
93 warn "\tThis is a user warning";
94 print "\nDIAGNOSTIC TESTER: Please enter a <CR> here: ";
95 my $a, $b = scalar <STDIN>;
96 print "\n";
97 print $x/$y;
98
99If you prefer to run your program first and look at its problem
100afterwards, do this:
101
102 perl -w test.pl 2>test.out
103 ./splain < test.out
104
105Note that this is not in general possible in shells of more dubious heritage,
1fef88e7 106as the theoretical
4633a7c4
LW
107
108 (perl -w test.pl >/dev/tty) >& test.out
109 ./splain < test.out
110
111Because you just moved the existing B<stdout> to somewhere else.
112
113If you don't want to modify your source code, but still have on-the-fly
114warnings, do this:
115
116 exec 3>&1; perl -w test.pl 2>&1 1>&3 3>&- | splain 1>&2 3>&-
117
118Nifty, eh?
119
120If you want to control warnings on the fly, do something like this.
121Make sure you do the C<use> first, or you won't be able to get
122at the enable() or disable() methods.
123
124 use diagnostics; # checks entire compilation phase
125 print "\ntime for 1st bogus diags: SQUAWKINGS\n";
126 print BOGUS1 'nada';
127 print "done with 1st bogus\n";
128
129 disable diagnostics; # only turns off runtime warnings
130 print "\ntime for 2nd bogus: (squelched)\n";
131 print BOGUS2 'nada';
132 print "done with 2nd bogus\n";
133
134 enable diagnostics; # turns back on runtime warnings
135 print "\ntime for 3rd bogus: SQUAWKINGS\n";
136 print BOGUS3 'nada';
137 print "done with 3rd bogus\n";
138
139 disable diagnostics;
140 print "\ntime for 4th bogus: (squelched)\n";
141 print BOGUS4 'nada';
142 print "done with 4th bogus\n";
143
144=head1 INTERNALS
145
146Diagnostic messages derive from the F<perldiag.pod> file when available at
147runtime. Otherwise, they may be embedded in the file itself when the
148splain package is built. See the F<Makefile> for details.
149
150If an extant $SIG{__WARN__} handler is discovered, it will continue
1fef88e7 151to be honored, but only after the diagnostics::splainthis() function
4633a7c4
LW
152(the module's $SIG{__WARN__} interceptor) has had its way with your
153warnings.
154
155There is a $diagnostics::DEBUG variable you may set if you're desperately
156curious what sorts of things are being intercepted.
157
158 BEGIN { $diagnostics::DEBUG = 1 }
159
160
161=head1 BUGS
162
163Not being able to say "no diagnostics" is annoying, but may not be
164insurmountable.
165
166The C<-pretty> directive is called too late to affect matters.
864e1151 167You have to do this instead, and I<before> you load the module.
4633a7c4
LW
168
169 BEGIN { $diagnostics::PRETTY = 1 }
170
171I could start up faster by delaying compilation until it should be
a6006777 172needed, but this gets a "panic: top_level" when using the pragma form
173in Perl 5.001e.
4633a7c4
LW
174
175While it's true that this documentation is somewhat subserious, if you use
176a program named I<splain>, you should expect a bit of whimsy.
177
178=head1 AUTHOR
179
352854fa 180Tom Christiansen <F<tchrist@mox.perl.com>>, 25 June 1995.
4633a7c4
LW
181
182=cut
183
7a4340ed 184use strict;
d923656e 185use 5.009001;
5f05dabc 186use Carp;
58618f23 187$Carp::Internal{__PACKAGE__.""}++;
5f05dabc 188
a088f065 189our $VERSION = '1.38';
7a4340ed
GS
190our $DEBUG;
191our $VERBOSE;
192our $PRETTY;
58618f23
FD
193our $TRACEONLY = 0;
194our $WARNTRACE = 0;
1e4e2d84 195
5f05dabc 196use Config;
5604c790 197use Text::Tabs 'expand';
ce2c4022 198my $privlib = $Config{privlibexp};
5f05dabc 199if ($^O eq 'VMS') {
91a06757
CS
200 require VMS::Filespec;
201 $privlib = VMS::Filespec::unixify($privlib);
5f05dabc 202}
7a4340ed 203my @trypod = (
5459498c 204 "$privlib/pod/perldiag.pod",
5459498c 205 "$privlib/pods/perldiag.pod",
7ec2cea4 206 );
fb73857a 207# handy for development testing of new warnings etc
208unshift @trypod, "./pod/perldiag.pod" if -e "pod/perldiag.pod";
7a4340ed 209(my $PODFILE) = ((grep { -e } @trypod), $trypod[$#trypod])[0];
5f05dabc 210
4633a7c4 211$DEBUG ||= 0;
4633a7c4 212
7a4340ed 213local $| = 1;
0a437bc9 214local $_;
412147f6 215local $.;
4633a7c4 216
7a4340ed
GS
217my $standalone;
218my(%HTML_2_Troff, %HTML_2_Latin_1, %HTML_2_ASCII_7);
219
4633a7c4 220CONFIG: {
7a4340ed 221 our $opt_p = our $opt_d = our $opt_v = our $opt_f = '';
4633a7c4 222
7a4340ed 223 unless (caller) {
4633a7c4
LW
224 $standalone++;
225 require Getopt::Std;
91a06757
CS
226 Getopt::Std::getopts('pdvf:')
227 or die "Usage: $0 [-v] [-p] [-f splainpod]";
4633a7c4
LW
228 $PODFILE = $opt_f if $opt_f;
229 $DEBUG = 2 if $opt_d;
230 $VERBOSE = $opt_v;
231 $PRETTY = $opt_p;
7a4340ed 232 }
4633a7c4 233
1ae6ead9 234 if (open(POD_DIAG, '<', $PODFILE)) {
4633a7c4
LW
235 warn "Happy happy podfile from real $PODFILE\n" if $DEBUG;
236 last CONFIG;
237 }
238
239 if (caller) {
240 INCPATH: {
adf76805 241 for my $file ( (map { "$_/".__PACKAGE__.".pm" } @INC), $0) {
4633a7c4 242 warn "Checking $file\n" if $DEBUG;
1ae6ead9 243 if (open(POD_DIAG, '<', $file)) {
4633a7c4 244 while (<POD_DIAG>) {
7a4340ed
GS
245 next unless
246 /^__END__\s*# wish diag dbase were more accessible/;
4633a7c4
LW
247 print STDERR "podfile is $file\n" if $DEBUG;
248 last INCPATH;
249 }
250 }
251 }
252 }
253 } else {
254 print STDERR "podfile is <DATA>\n" if $DEBUG;
255 *POD_DIAG = *main::DATA;
256 }
257}
258if (eof(POD_DIAG)) {
259 die "couldn't find diagnostic data in $PODFILE @INC $0";
260}
261
262
263%HTML_2_Troff = (
264 'amp' => '&', # ampersand
265 'lt' => '<', # left chevron, less-than
266 'gt' => '>', # right chevron, greater-than
267 'quot' => '"', # double quote
bb84ab0e
TC
268 'sol' => '/', # forward slash / solidus
269 'verbar' => '|', # vertical bar
4633a7c4
LW
270
271 "Aacute" => "A\\*'", # capital A, acute accent
272 # etc
273
274);
275
276%HTML_2_Latin_1 = (
277 'amp' => '&', # ampersand
278 'lt' => '<', # left chevron, less-than
279 'gt' => '>', # right chevron, greater-than
280 'quot' => '"', # double quote
bb84ab0e
TC
281 'sol' => '/', # Forward slash / solidus
282 'verbar' => '|', # vertical bar
4633a7c4 283
a088f065
KW
284 # # capital A, acute accent
285 "Aacute" => chr utf8::unicode_to_native(0xC1)
4633a7c4
LW
286
287 # etc
288);
289
290%HTML_2_ASCII_7 = (
291 'amp' => '&', # ampersand
292 'lt' => '<', # left chevron, less-than
293 'gt' => '>', # right chevron, greater-than
294 'quot' => '"', # double quote
bb84ab0e
TC
295 'sol' => '/', # Forward slash / solidus
296 'verbar' => '|', # vertical bar
4633a7c4
LW
297
298 "Aacute" => "A" # capital A, acute accent
299 # etc
300);
301
7a4340ed 302our %HTML_Escapes;
4633a7c4
LW
303*HTML_Escapes = do {
304 if ($standalone) {
305 $PRETTY ? \%HTML_2_Latin_1 : \%HTML_2_ASCII_7;
306 } else {
307 \%HTML_2_Latin_1;
308 }
309};
310
311*THITHER = $standalone ? *STDOUT : *STDERR;
312
49704364 313my %transfmt = ();
7a4340ed 314my $transmo = <<EOFUNC;
4633a7c4 315sub transmo {
599cee73 316 #local \$^W = 0; # recursive warnings we do NOT need!
4633a7c4
LW
317EOFUNC
318
7a4340ed 319my %msg;
a1399808 320my $over_level = 0; # We look only at =item lines at the first =over level
7a4340ed 321{
4633a7c4 322 print STDERR "FINISHING COMPILATION for $_\n" if $DEBUG;
7a4340ed 323 local $/ = '';
0a437bc9 324 local $_;
7a4340ed 325 my $header;
f4739a71 326 my @headers;
7a4340ed 327 my $for_item;
f4739a71 328 my $seen_body;
4633a7c4 329 while (<POD_DIAG>) {
4633a7c4 330
4b056c06 331 sub _split_pod_link {
98e27b5a 332 $_[0] =~ m'(?:([^|]*)\|)?([^/]*)(?:/("?)(.*)\3)?'s;
4b056c06
FC
333 ($1,$2,$4);
334 }
335
4633a7c4
LW
336 unescape();
337 if ($PRETTY) {
338 sub noop { return $_[0] } # spensive for a noop
339 sub bold { my $str =$_[0]; $str =~ s/(.)/$1\b$1/g; return $str; }
340 sub italic { my $str = $_[0]; $str =~ s/(.)/_\b$1/g; return $str; }
67612b68 341 s/C<<< (.*?) >>>|C<< (.*?) >>|[BC]<(.*?)>/bold($+)/ges;
4b056c06
FC
342 s/[IF]<(.*?)>/italic($1)/ges;
343 s/L<(.*?)>/
344 my($text,$page,$sect) = _split_pod_link($1);
345 defined $text
346 ? $text
347 : defined $sect
348 ? italic($sect) . ' in ' . italic($page)
349 : italic($page)
350 /ges;
524e9188
MH
351 s/S<(.*?)>/
352 $1
353 /ges;
4633a7c4 354 } else {
67612b68 355 s/C<<< (.*?) >>>|C<< (.*?) >>|[BC]<(.*?)>/$+/gs;
4b056c06
FC
356 s/[IF]<(.*?)>/$1/gs;
357 s/L<(.*?)>/
358 my($text,$page,$sect) = _split_pod_link($1);
359 defined $text
360 ? $text
361 : defined $sect
362 ? qq '"$sect" in $page'
363 : $page
364 /ges;
524e9188
MH
365 s/S<(.*?)>/
366 $1
367 /ges;
4633a7c4
LW
368 }
369 unless (/^=/) {
370 if (defined $header) {
371 if ( $header eq 'DESCRIPTION' &&
372 ( /Optional warnings are enabled/
373 || /Some of these messages are generic./
374 ) )
375 {
376 next;
49704364 377 }
5604c790 378 $_ = expand $_;
4633a7c4
LW
379 s/^/ /gm;
380 $msg{$header} .= $_;
f4739a71
FC
381 for my $h(@headers) { $msg{$h} .= $_ }
382 ++$seen_body;
7a4340ed 383 undef $for_item;
4633a7c4
LW
384 }
385 next;
386 }
f4739a71
FC
387
388 # If we have not come across the body of the description yet, then
389 # the previous header needs to share the same description.
390 if ($seen_body) {
391 @headers = ();
392 }
393 else {
394 push @headers, $header if defined $header;
395 }
396
a1399808 397 if ( ! s/=item (.*?)\s*\z//s || $over_level != 1) {
4633a7c4
LW
398
399 if ( s/=head1\sDESCRIPTION//) {
400 $msg{$header = 'DESCRIPTION'} = '';
7a4340ed 401 undef $for_item;
4633a7c4 402 }
7a4340ed
GS
403 elsif( s/^=for\s+diagnostics\s*\n(.*?)\s*\z// ) {
404 $for_item = $1;
f1deee33 405 }
a1399808
KW
406 elsif( /^=over\b/ ) {
407 $over_level++;
408 }
409 elsif( /^=back\b/ ) { # Stop processing body here
410 $over_level--;
411 if ($over_level == 0) {
412 undef $header;
413 undef $for_item;
414 $seen_body = 0;
415 next;
416 }
f1deee33 417 }
4633a7c4
LW
418 next;
419 }
4fdae800 420
5cd5c422
RB
421 if( $for_item ) { $header = $for_item; undef $for_item }
422 else {
423 $header = $1;
6fbc9859
MH
424
425 $header =~ s/\n/ /gs; # Allow multi-line headers
5cd5c422
RB
426 }
427
49704364 428 # strip formatting directives from =item line
7a4340ed 429 $header =~ s/[A-Z]<(.*?)>/$1/g;
4633a7c4 430
6fbc9859
MH
431 # Since we strip "(\.\s*)\n" when we search a warning, strip it here as well
432 $header =~ s/(\.\s*)?$//;
c0d3a21f 433
01bfea8b 434 my @toks = split( /(%l?[dxX]|%[ucp]|%(?:\.\d+)?[fs])/, $header );
49704364
WL
435 if (@toks > 1) {
436 my $conlen = 0;
437 for my $i (0..$#toks){
438 if( $i % 2 ){
439 if( $toks[$i] eq '%c' ){
440 $toks[$i] = '.';
e958e573 441 } elsif( $toks[$i] =~ /^%(?:d|u)$/ ){
49704364 442 $toks[$i] = '\d+';
8b56d6ff 443 } elsif( $toks[$i] =~ '^%(?:s|.*f)$' ){
49704364
WL
444 $toks[$i] = $i == $#toks ? '.*' : '.*?';
445 } elsif( $toks[$i] =~ '%.(\d+)s' ){
446 $toks[$i] = ".{$1}";
01bfea8b
FC
447 } elsif( $toks[$i] =~ '^%l*([pxX])$' ){
448 $toks[$i] = $1 eq 'X' ? '[\dA-F]+' : '[\da-f]+';
e958e573 449 }
49704364 450 } elsif( length( $toks[$i] ) ){
8ec7363a 451 $toks[$i] = quotemeta $toks[$i];
49704364
WL
452 $conlen += length( $toks[$i] );
453 }
454 }
455 my $lhs = join( '', @toks );
6fbc9859 456 $lhs =~ s/(\\\s)+/\\s+/g; # Replace lit space with multi-space match
49704364 457 $transfmt{$header}{pat} =
6fbc9859 458 " s\a^\\s*$lhs\\s*\a\Q$header\E\as\n\t&& return 1;\n";
49704364 459 $transfmt{$header}{len} = $conlen;
4633a7c4 460 } else {
6fbc9859
MH
461 my $lhs = "\Q$header\E";
462 $lhs =~ s/(\\\s)+/\\s+/g; # Replace lit space with multi-space match
49704364 463 $transfmt{$header}{pat} =
6fbc9859 464 " s\a^\\s*$lhs\\s*\a\Q$header\E\a\n\t && return 1;\n";
49704364 465 $transfmt{$header}{len} = length( $header );
4633a7c4
LW
466 }
467
adf76805 468 print STDERR __PACKAGE__.": Duplicate entry: \"$header\"\n"
eff9c6e2 469 if $msg{$header};
4633a7c4
LW
470
471 $msg{$header} = '';
f4739a71 472 $seen_body = 0;
4633a7c4
LW
473 }
474
475
476 close POD_DIAG unless *main::DATA eq *POD_DIAG;
477
478 die "No diagnostics?" unless %msg;
479
49704364
WL
480 # Apply patterns in order of decreasing sum of lengths of fixed parts
481 # Seems the best way of hitting the right one.
482 for my $hdr ( sort { $transfmt{$b}{len} <=> $transfmt{$a}{len} }
483 keys %transfmt ){
484 $transmo .= $transfmt{$hdr}{pat};
485 }
4633a7c4
LW
486 $transmo .= " return 0;\n}\n";
487 print STDERR $transmo if $DEBUG;
488 eval $transmo;
489 die $@ if $@;
7a4340ed 490}
4633a7c4
LW
491
492if ($standalone) {
493 if (!@ARGV and -t STDIN) { print STDERR "$0: Reading from STDIN\n" }
7a4340ed 494 while (defined (my $error = <>)) {
4633a7c4
LW
495 splainthis($error) || print THITHER $error;
496 }
497 exit;
7a4340ed
GS
498}
499
500my $olddie;
501my $oldwarn;
4633a7c4
LW
502
503sub import {
504 shift;
7a4340ed
GS
505 $^W = 1; # yup, clobbered the global variable;
506 # tough, if you want diags, you want diags.
0dc02ca5 507 return if defined $SIG{__WARN__} && ($SIG{__WARN__} eq \&warn_trap);
4633a7c4
LW
508
509 for (@_) {
510
511 /^-d(ebug)?$/ && do {
512 $DEBUG++;
513 next;
514 };
515
516 /^-v(erbose)?$/ && do {
517 $VERBOSE++;
518 next;
519 };
520
521 /^-p(retty)?$/ && do {
522 print STDERR "$0: I'm afraid it's too late for prettiness.\n";
523 $PRETTY++;
524 next;
525 };
b4e8c6dd
FD
526 # matches trace and traceonly for legacy doc mixup reasons
527 /^-t(race(only)?)?$/ && do {
58618f23
FD
528 $TRACEONLY++;
529 next;
530 };
b4e8c6dd 531 /^-w(arntrace)?$/ && do {
58618f23
FD
532 $WARNTRACE++;
533 next;
534 };
535
4633a7c4
LW
536 warn "Unknown flag: $_";
537 }
538
539 $oldwarn = $SIG{__WARN__};
540 $olddie = $SIG{__DIE__};
541 $SIG{__WARN__} = \&warn_trap;
542 $SIG{__DIE__} = \&death_trap;
543}
544
545sub enable { &import }
546
547sub disable {
548 shift;
4633a7c4 549 return unless $SIG{__WARN__} eq \&warn_trap;
3d0ae7ba
GS
550 $SIG{__WARN__} = $oldwarn || '';
551 $SIG{__DIE__} = $olddie || '';
4633a7c4
LW
552}
553
554sub warn_trap {
555 my $warning = $_[0];
adf76805 556 if (caller eq __PACKAGE__ or !splainthis($warning)) {
58618f23
FD
557 if ($WARNTRACE) {
558 print STDERR Carp::longmess($warning);
559 } else {
560 print STDERR $warning;
561 }
4633a7c4 562 }
58618f23 563 goto &$oldwarn if defined $oldwarn and $oldwarn and $oldwarn ne \&warn_trap;
4633a7c4
LW
564};
565
566sub death_trap {
567 my $exception = $_[0];
55497cff 568
569 # See if we are coming from anywhere within an eval. If so we don't
570 # want to explain the exception because it's going to get caught.
ec087511
FC
571 my $in_eval = 0;
572 my $i = 0;
573 while (my $caller = (caller($i++))[3]) {
574 if ($caller eq '(eval)') {
575 $in_eval = 1;
576 last;
577 }
578 }
55497cff 579
580 splainthis($exception) unless $in_eval;
adf76805
FC
581 if (caller eq __PACKAGE__) {
582 print STDERR "INTERNAL EXCEPTION: $exception";
583 }
37120919 584 &$olddie if defined $olddie and $olddie and $olddie ne \&death_trap;
55497cff 585
d23f0205
MS
586 return if $in_eval;
587
55497cff 588 # We don't want to unset these if we're coming from an eval because
d23f0205
MS
589 # then we've turned off diagnostics.
590
591 # Switch off our die/warn handlers so we don't wind up in our own
592 # traps.
593 $SIG{__DIE__} = $SIG{__WARN__} = '';
594
245e6c67
FC
595 $exception =~ s/\n(?=.)/\n\t/gas;
596
2dde0467
FC
597 die Carp::longmess("__diagnostics__")
598 =~ s/^__diagnostics__.*?line \d+\.?\n/
599 "Uncaught exception from user code:\n\t$exception"
600 /re;
4633a7c4
LW
601 # up we go; where we stop, nobody knows, but i think we die now
602 # but i'm deeply afraid of the &$olddie guy reraising and us getting
603 # into an indirect recursion loop
604};
605
7a4340ed
GS
606my %exact_duplicate;
607my %old_diag;
608my $count;
609my $wantspace;
4633a7c4 610sub splainthis {
0a437bc9
FC
611 return 0 if $TRACEONLY;
612 for (my $tmp = shift) {
5025c45a 613 local $\;
2a6a970f 614 local $!;
4633a7c4 615 ### &finish_compilation unless %msg;
6fbc9859 616 s/(\.\s*)?\n+$//;
4633a7c4
LW
617 my $orig = $_;
618 # return unless defined;
49704364
WL
619
620 # get rid of the where-are-we-in-input part
4633a7c4 621 s/, <.*?> (?:line|chunk).*$//;
49704364
WL
622
623 # Discard 1st " at <file> line <no>" and all text beyond
98dc9551 624 # but be aware of messages containing " at this-or-that"
49704364
WL
625 my $real = 0;
626 my @secs = split( / at / );
18d238e4 627 return unless @secs;
49704364
WL
628 $_ = $secs[0];
629 for my $i ( 1..$#secs ){
630 if( $secs[$i] =~ /.+? (?:line|chunk) \d+/ ){
631 $real = 1;
632 last;
633 } else {
634 $_ .= ' at ' . $secs[$i];
635 }
636 }
6fbc9859 637
49704364 638 # remove parenthesis occurring at the end of some messages
4633a7c4 639 s/^\((.*)\)$/$1/;
49704364 640
097b73fc
BB
641 if ($exact_duplicate{$orig}++) {
642 return &transmo;
49704364 643 } else {
097b73fc
BB
644 return 0 unless &transmo;
645 }
49704364 646
0a437bc9 647 my $short = shorten($orig);
4633a7c4
LW
648 if ($old_diag{$_}) {
649 autodescribe();
0a437bc9 650 print THITHER "$short (#$old_diag{$_})\n";
4633a7c4 651 $wantspace = 1;
0a437bc9
FC
652 } elsif (!$msg{$_} && $orig =~ /\n./s) {
653 # A multiline message, like "Attempt to reload /
654 # Compilation failed"
655 my $found;
656 for (split /^/, $orig) {
657 splainthis($_) and $found = 1;
658 }
659 return $found;
4633a7c4
LW
660 } else {
661 autodescribe();
662 $old_diag{$_} = ++$count;
663 print THITHER "\n" if $wantspace;
664 $wantspace = 0;
0a437bc9 665 print THITHER "$short (#$old_diag{$_})\n";
4633a7c4
LW
666 if ($msg{$_}) {
667 print THITHER $msg{$_};
668 } else {
669 if (0 and $standalone) {
670 print THITHER " **** Error #$old_diag{$_} ",
671 ($real ? "is" : "appears to be"),
672 " an unknown diagnostic message.\n\n";
673 }
674 return 0;
675 }
676 }
677 return 1;
0a437bc9 678 }
4633a7c4
LW
679}
680
681sub autodescribe {
682 if ($VERBOSE and not $count) {
683 print THITHER &{$PRETTY ? \&bold : \&noop}("DESCRIPTION OF DIAGNOSTICS"),
684 "\n$msg{DESCRIPTION}\n";
685 }
686}
687
688sub unescape {
689 s {
690 E<
691 ( [A-Za-z]+ )
692 >
693 } {
694 do {
695 exists $HTML_Escapes{$1}
696 ? do { $HTML_Escapes{$1} }
697 : do {
f02a87df 698 warn "Unknown escape: E<$1> in $_";
4633a7c4
LW
699 "E<$1>";
700 }
701 }
702 }egx;
703}
704
705sub shorten {
706 my $line = $_[0];
774d564b 707 if (length($line) > 79 and index($line, "\n") == -1) {
4633a7c4
LW
708 my $space_place = rindex($line, ' ', 79);
709 if ($space_place != -1) {
710 substr($line, $space_place, 1) = "\n\t";
711 }
712 }
713 return $line;
714}
715
716
4633a7c4
LW
7171 unless $standalone; # or it'll complain about itself
718__END__ # wish diag dbase were more accessible