document shell function portability
[autoconf.git] / lib / Autom4te / Channels.pm
blob9840a3a9956b9c5a61b5395fac49c004cb8b09ef
1 # Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation, either version 3 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ###############################################################
17 # The main copy of this file is in Automake's CVS repository. #
18 # Updates should be sent to automake-patches@gnu.org. #
19 ###############################################################
21 package Autom4te::Channels;
23 =head1 NAME
25 Autom4te::Channels - support functions for error and warning management
27 =head1 SYNOPSIS
29 use Autom4te::Channels;
31 # Register a channel to output warnings about unused variables.
32 register_channel 'unused', type => 'warning';
34 # Register a channel for system errors.
35 register_channel 'system', type => 'error', exit_code => 4;
37 # Output a message on channel 'unused'.
38 msg 'unused', "$file:$line", "unused variable `$var'";
40 # Make the 'unused' channel silent.
41 setup_channel 'unused', silent => 1;
43 # Turn on all channels of type 'warning'.
44 setup_channel_type 'warning', silent => 0;
46 # Treat all warnings as errors.
47 $warnings_are_errors = 1;
49 # Exit with the greatest exit code encountered so far.
50 exit $exit_code;
52 =head1 DESCRIPTION
54 This perl module provides support functions for handling diagnostic
55 channels in programs. Channels can be registered to convey fatal,
56 error, warning, or debug messages. Each channel has various options
57 (e.g. is the channel silent, should duplicate messages be removed,
58 etc.) that can also be overridden on a per-message basis.
60 =cut
62 use 5.005;
63 use strict;
64 use Exporter;
65 use Carp;
66 use File::Basename;
68 use vars qw (@ISA @EXPORT %channels $me);
70 @ISA = qw (Exporter);
71 @EXPORT = qw ($exit_code $warnings_are_errors
72 &reset_local_duplicates &reset_global_duplicates
73 &register_channel &msg &exists_channel &channel_type
74 &setup_channel &setup_channel_type
75 &dup_channel_setup &drop_channel_setup
76 &buffer_messages &flush_messages
77 US_GLOBAL US_LOCAL
78 UP_NONE UP_TEXT UP_LOC_TEXT);
80 $me = basename $0;
82 =head2 Global Variables
84 =over 4
86 =item C<$exit_code>
88 The greatest exit code seen so far. C<$exit_code> is updated from
89 the C<exit_code> options of C<fatal> and C<error> channels.
91 =cut
93 use vars qw ($exit_code);
94 $exit_code = 0;
96 =item C<$warnings_are_errors>
98 Set this variable to 1 if warning messages should be treated as
99 errors (i.e. if they should update C<$exit_code>).
101 =cut
103 use vars qw ($warnings_are_errors);
104 $warnings_are_errors = 0;
106 =back
108 =head2 Constants
110 =over 4
112 =item C<UP_NONE>, C<UP_TEXT>, C<UP_LOC_TEXT>
114 Possible values for the C<uniq_part> options. This selects the part
115 of the message that should be considered when filtering out duplicates.
116 If C<UP_LOC_TEXT> is used, the location and the explanation message
117 are used for filtering. If C<UP_TEXT> is used, only the explanation
118 message is used (so the same message will be filtered out if it appears
119 at different locations). C<UP_NONE> means that duplicate messages
120 should be output.
122 =cut
124 use constant UP_NONE => 0;
125 use constant UP_TEXT => 1;
126 use constant UP_LOC_TEXT => 2;
128 =item C<US_LOCAL>, C<US_GLOBAL>
130 Possible values for the C<uniq_scope> options.
131 Use C<US_GLOBAL> for error messages that should be printed only
132 once during the execution of the program, C<US_LOCAL> for message that
133 should be printed only once per file. (Actually, C<Channels> does not
134 do this now when files are changed, it relies on you calling
135 C<reset_local_duplicates> when this happens.)
137 =cut
139 # possible values for uniq_scope
140 use constant US_LOCAL => 0;
141 use constant US_GLOBAL => 1;
143 =back
145 =head2 Options
147 Channels accept the options described below. These options can be
148 passed as a hash to the C<register_channel>, C<setup_channel>, and C<msg>
149 functions. The possible keys, with their default value are:
151 =over
153 =item C<type =E<gt> 'warning'>
155 The type of the channel. One of C<'debug'>, C<'warning'>, C<'error'>, or
156 C<'fatal'>. Fatal messages abort the program when they are output.
157 Error messages update the exit status. Debug and warning messages are
158 harmless, except that warnings can be treated as errors of
159 C<$warnings_are_errors> is set.
161 =item C<exit_code =E<gt> 1>
163 The value to update C<$exit_code> with when a fatal or error message
164 is emitted. C<$exit_code> is also updated for warnings output
165 when @<$warnings_are_errors> is set.
167 =item C<file =E<gt> \*STDERR>
169 The file where the error should be output.
171 =item C<silent =E<gt> 0>
173 Whether the channel should be silent. Use this do disable a
174 category of warning, for instance.
176 =item C<uniq_part =E<gt> UP_LOC_TEXT>
178 The part of the message subject to duplicate filtering. See the
179 documentation for the C<UP_NONE>, C<UP_TEXT>, and C<UP_LOC_TEXT>
180 constants above.
182 C<uniq_part> can also be set to an arbitrary string that will be used
183 instead of the message when considering duplicates.
185 =item C<uniq_scope =E<gt> US_LOCAL>
187 The scope of duplicate filtering. See the documentation for the
188 C<US_LOCAL>, and C<US_GLOBAL> constants above.
190 =item C<header =E<gt> ''>
192 A string to prepend to each message emitted through this channel.
194 =item C<footer =E<gt> ''>
196 A string to append to each message emitted through this channel.
198 =item C<backtrace =E<gt> 0>
200 Die with a stack backtrace after displaying the message.
202 =item C<partial =E<gt> 0>
204 When set, indicates a partial message that should
205 be output along with the next message with C<partial> unset.
206 Several partial messages can be stacked this way.
208 Duplicate filtering will apply to the I<global> message resulting from
209 all I<partial> messages, using the options from the last (non-partial)
210 message. Linking associated messages is the main reason to use this
211 option.
213 For instance the following messages
215 msg 'channel', 'foo:2', 'redefinition of A ...';
216 msg 'channel', 'foo:1', '... A previously defined here';
217 msg 'channel', 'foo:3', 'redefinition of A ...';
218 msg 'channel', 'foo:1', '... A previously defined here';
220 will result in
222 foo:2: redefinition of A ...
223 foo:1: ... A previously defined here
224 foo:3: redefinition of A ...
226 where the duplicate "I<... A previously defined here>" has been
227 filtered out.
229 Linking these messages using C<partial> as follows will prevent the
230 fourth message to disappear.
232 msg 'channel', 'foo:2', 'redefinition of A ...', partial => 1;
233 msg 'channel', 'foo:1', '... A previously defined here';
234 msg 'channel', 'foo:3', 'redefinition of A ...', partial => 1;
235 msg 'channel', 'foo:1', '... A previously defined here';
237 Note that because the stack of C<partial> messages is printed with the
238 first non-C<partial> message, most options of C<partial> messages will
239 be ignored.
241 =back
243 =cut
245 use vars qw (%_default_options %_global_duplicate_messages
246 %_local_duplicate_messages);
248 # Default options for a channel.
249 %_default_options =
251 type => 'warning',
252 exit_code => 1,
253 file => \*STDERR,
254 silent => 0,
255 uniq_scope => US_LOCAL,
256 uniq_part => UP_LOC_TEXT,
257 header => '',
258 footer => '',
259 backtrace => 0,
260 partial => 0,
263 # Filled with output messages as keys, to detect duplicates.
264 # The value associated with each key is the number of occurrences
265 # filtered out.
266 %_local_duplicate_messages = ();
267 %_global_duplicate_messages = ();
269 sub _reset_duplicates (\%)
271 my ($ref) = @_;
272 my $dup = 0;
273 foreach my $k (keys %$ref)
275 $dup += $ref->{$k};
277 %$ref = ();
278 return $dup;
282 =head2 Functions
284 =over 4
286 =item C<reset_local_duplicates ()>
288 Reset local duplicate messages (see C<US_LOCAL>), and
289 return the number of messages that have been filtered out.
291 =cut
293 sub reset_local_duplicates ()
295 return _reset_duplicates %_local_duplicate_messages;
298 =item C<reset_global_duplicates ()>
300 Reset local duplicate messages (see C<US_GLOBAL>), and
301 return the number of messages that have been filtered out.
303 =cut
305 sub reset_global_duplicates ()
307 return _reset_duplicates %_global_duplicate_messages;
310 sub _merge_options (\%%)
312 my ($hash, %options) = @_;
313 local $_;
315 foreach (keys %options)
317 if (exists $hash->{$_})
319 $hash->{$_} = $options{$_}
321 else
323 confess "unknown option `$_'";
328 =item C<register_channel ($name, [%options])>
330 Declare channel C<$name>, and override the default options
331 with those listed in C<%options>.
333 =cut
335 sub register_channel ($;%)
337 my ($name, %options) = @_;
338 my %channel_opts = %_default_options;
339 _merge_options %channel_opts, %options;
340 $channels{$name} = \%channel_opts;
343 =item C<exists_channel ($name)>
345 Returns true iff channel C<$name> has been registered.
347 =cut
349 sub exists_channel ($)
351 my ($name) = @_;
352 return exists $channels{$name};
355 =item C<channel_type ($name)>
357 Returns the type of channel C<$name> if it has been registered.
358 Returns the empty string otherwise.
360 =cut
362 sub channel_type ($)
364 my ($name) = @_;
365 return $channels{$name}{'type'} if exists_channel $name;
366 return '';
369 # _format_sub_message ($LEADER, $MESSAGE)
370 # ---------------------------------------
371 # Split $MESSAGE at new lines and add $LEADER to each line.
372 sub _format_sub_message ($$)
374 my ($leader, $message) = @_;
375 return $leader . join ("\n" . $leader, split ("\n", $message)) . "\n";
378 # _format_message ($LOCATION, $MESSAGE, %OPTIONS)
379 # -----------------------------------------------
380 # Format the message. Return a string ready to print.
381 sub _format_message ($$%)
383 my ($location, $message, %opts) = @_;
384 my $msg = '';
385 if (ref $location)
387 # If $LOCATION is a reference, assume it's an instance of the
388 # Autom4te::Location class and display contexts.
389 my $loc = $location->get || $me;
390 $msg = _format_sub_message ("$loc: ", $opts{'header'}
391 . $message . $opts{'footer'});
392 for my $pair ($location->get_contexts)
394 $msg .= _format_sub_message ($pair->[0] . ": ", $pair->[1]);
397 else
399 $location ||= $me;
400 $msg = _format_sub_message ("$location: ", $opts{'header'}
401 . $message . $opts{'footer'});
403 return $msg;
406 # Store partial messages here. (See the 'partial' option.)
407 use vars qw ($partial);
408 $partial = '';
410 # _print_message ($LOCATION, $MESSAGE, %OPTIONS)
411 # ----------------------------------------------
412 # Format the message, check duplicates, and print it.
413 sub _print_message ($$%)
415 my ($location, $message, %opts) = @_;
417 return 0 if ($opts{'silent'});
419 my $msg = _format_message ($location, $message, %opts);
420 if ($opts{'partial'})
422 # Incomplete message. Store, don't print.
423 $partial .= $msg;
424 return;
426 else
428 # Prefix with any partial message send so far.
429 $msg = $partial . $msg;
430 $partial = '';
433 # Check for duplicate message if requested.
434 if ($opts{'uniq_part'} ne UP_NONE)
436 # Which part of the error should we match?
437 my $to_filter;
438 if ($opts{'uniq_part'} eq UP_TEXT)
440 $to_filter = $message;
442 elsif ($opts{'uniq_part'} eq UP_LOC_TEXT)
444 $to_filter = $msg;
446 else
448 $to_filter = $opts{'uniq_part'};
451 # Do we want local or global uniqueness?
452 my $dups;
453 if ($opts{'uniq_scope'} == US_LOCAL)
455 $dups = \%_local_duplicate_messages;
457 elsif ($opts{'uniq_scope'} == US_GLOBAL)
459 $dups = \%_global_duplicate_messages;
461 else
463 confess "unknown value for uniq_scope: " . $opts{'uniq_scope'};
466 # Update the hash of messages.
467 if (exists $dups->{$to_filter})
469 ++$dups->{$to_filter};
470 return 0;
472 else
474 $dups->{$to_filter} = 0;
477 my $file = $opts{'file'};
478 print $file $msg;
479 return 1;
482 =item C<msg ($channel, $location, $message, [%options])>
484 Emit a message on C<$channel>, overriding some options of the channel with
485 those specified in C<%options>. Obviously C<$channel> must have been
486 registered with C<register_channel>.
488 C<$message> is the text of the message, and C<$location> is a location
489 associated to the message.
491 For instance to complain about some unused variable C<mumble>
492 declared at line 10 in F<foo.c>, one could do:
494 msg 'unused', 'foo.c:10', "unused variable `mumble'";
496 If channel C<unused> is not silent (and if this message is not a duplicate),
497 the following would be output:
499 foo.c:10: unused variable `mumble'
501 C<$location> can also be an instance of C<Autom4te::Location>. In this
502 case, the stack of contexts will be displayed in addition.
504 If C<$message> contains newline characters, C<$location> is prepended
505 to each line. For instance,
507 msg 'error', 'somewhere', "1st line\n2nd line";
509 becomes
511 somewhere: 1st line
512 somewhere: 2nd line
514 If C<$location> is an empty string, it is replaced by the name of the
515 program. Actually, if you don't use C<%options>, you can even
516 elide the empty C<$location>. Thus
518 msg 'fatal', '', 'fatal error';
519 msg 'fatal', 'fatal error';
521 both print
523 progname: fatal error
525 =cut
528 use vars qw (@backlog %buffering @chain);
530 # See buffer_messages() and flush_messages() below.
531 %buffering = (); # The map of channel types to buffer.
532 @backlog = (); # The buffer of messages.
534 sub msg ($$;$%)
536 my ($channel, $location, $message, %options) = @_;
538 if (! defined $message)
540 $message = $location;
541 $location = '';
544 confess "unknown channel $channel" unless exists $channels{$channel};
546 my %opts = %{$channels{$channel}};
547 _merge_options (%opts, %options);
549 if (exists $buffering{$opts{'type'}})
551 push @backlog, [$channel, $location->clone, $message, %options];
552 return;
555 # Print the message if needed.
556 if (_print_message ($location, $message, %opts))
558 # Adjust exit status.
559 if ($opts{'type'} eq 'error'
560 || $opts{'type'} eq 'fatal'
561 || ($opts{'type'} eq 'warning' && $warnings_are_errors))
563 my $es = $opts{'exit_code'};
564 $exit_code = $es if $es > $exit_code;
567 # Die on fatal messages.
568 confess if $opts{'backtrace'};
569 exit $exit_code if $opts{'type'} eq 'fatal';
574 =item C<setup_channel ($channel, %options)>
576 Override the options of C<$channel> with those specified by C<%options>.
578 =cut
580 sub setup_channel ($%)
582 my ($name, %opts) = @_;
583 confess "channel $name doesn't exist" unless exists $channels{$name};
584 _merge_options %{$channels{$name}}, %opts;
587 =item C<setup_channel_type ($type, %options)>
589 Override the options of any channel of type C<$type>
590 with those specified by C<%options>.
592 =cut
594 sub setup_channel_type ($%)
596 my ($type, %opts) = @_;
597 foreach my $channel (keys %channels)
599 setup_channel $channel, %opts
600 if $channels{$channel}{'type'} eq $type;
604 =item C<dup_channel_setup ()>, C<drop_channel_setup ()>
606 Sometimes it is necessary to make temporary modifications to channels.
607 For instance one may want to disable a warning while processing a
608 particular file, and then restore the initial setup. These two
609 functions make it easy: C<dup_channel_setup ()> saves a copy of the
610 current configuration for later restoration by
611 C<drop_channel_setup ()>.
613 You can think of this as a stack of configurations whose first entry
614 is the active one. C<dup_channel_setup ()> duplicates the first
615 entry, while C<drop_channel_setup ()> just deletes it.
617 =cut
619 use vars qw (@_saved_channels);
620 @_saved_channels = ();
622 sub dup_channel_setup ()
624 my %channels_copy;
625 foreach my $k1 (keys %channels)
627 $channels_copy{$k1} = {%{$channels{$k1}}};
629 push @_saved_channels, \%channels_copy;
632 sub drop_channel_setup ()
634 my $saved = pop @_saved_channels;
635 %channels = %$saved;
638 =item C<buffer_messages (@types)>, C<flush_messages ()>
640 By default, when C<msg> is called, messages are processed immediately.
642 Sometimes it is necessary to delay the output of messages.
643 For instance you might want to make diagnostics before
644 channels have been completely configured.
646 After C<buffer_messages(@types)> has been called, messages sent with
647 C<msg> to a channel whose type is listed in C<@types> will be stored in a
648 list for later processing.
650 This backlog of messages is processed when C<flush_messages> is
651 called, with the current channel options (not the options in effect,
652 at the time of C<msg>). So for instance, if some channel was silenced
653 in the meantime, messages to this channel will not be printed.
655 C<flush_messages> cancels the effect of C<buffer_messages>. Following
656 calls to C<msg> are processed immediately as usual.
658 =cut
660 sub buffer_messages (@)
662 foreach my $type (@_)
664 $buffering{$type} = 1;
668 sub flush_messages ()
670 %buffering = ();
671 foreach my $args (@backlog)
673 &msg (@$args);
675 @backlog = ();
678 =back
680 =head1 SEE ALSO
682 L<Autom4te::Location>
684 =head1 HISTORY
686 Written by Alexandre Duret-Lutz E<lt>F<adl@gnu.org>E<gt>.
688 =cut
692 ### Setup "GNU" style for perl-mode and cperl-mode.
693 ## Local Variables:
694 ## perl-indent-level: 2
695 ## perl-continued-statement-offset: 2
696 ## perl-continued-brace-offset: 0
697 ## perl-brace-offset: 0
698 ## perl-brace-imaginary-offset: 0
699 ## perl-label-offset: -2
700 ## cperl-indent-level: 2
701 ## cperl-brace-offset: 0
702 ## cperl-continued-brace-offset: 0
703 ## cperl-label-offset: -2
704 ## cperl-extra-newline-before-brace: t
705 ## cperl-merge-trailing-else: nil
706 ## cperl-continued-statement-offset: 2
707 ## End: