home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / share / automake-1.7 / Automake / Channels.pm next >
Encoding:
Perl POD Document  |  2005-10-16  |  14.4 KB  |  621 lines

  1. # Copyright (C) 2002 Free Software Foundation, Inc.
  2.  
  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 2, or (at your option)
  6. # any later version.
  7.  
  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.
  12.  
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software
  15. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  16. # 02111-1307, USA.
  17.  
  18. package Automake::Channels;
  19.  
  20. =head1 NAME
  21.  
  22. Automake::Channels - support functions for error and warning management
  23.  
  24. =head1 SYNOPSIS
  25.  
  26.   use Automake::Channels;
  27.  
  28.   # Register a channel to output warnings about unused variables.
  29.   register_channel 'unused', type => 'warning';
  30.  
  31.   # Register a channel for system errors.
  32.   register_channel 'system', type => 'error', exit_code => 4;
  33.  
  34.   # Output a message on channel 'unused'.
  35.   msg 'unused', "$file:$line", "unused variable `$var'";
  36.  
  37.   # Make the 'unused' channel silent.
  38.   setup_channel 'unused', silent => 1;
  39.  
  40.   # Turn on all channels of type 'warning'.
  41.   setup_channel_type 'warning', silent => 0;
  42.  
  43.   # Treat all warnings as errors.
  44.   $warnings_are_errors = 1;
  45.  
  46.   # Exit with the greater exist code encountered so far.
  47.   exit $exit_code;
  48.  
  49. =head1 DESCRIPTION
  50.  
  51. This perl module provides support functions for handling diagnostic
  52. channels in programs.  Channels can be registered to convey fatal,
  53. error, warning, or debug messages.  Each channel has various options
  54. (e.g. is the channel silent, should duplicate messages be removed,
  55. etc.) that can also be overridden on a per-message basis.
  56.  
  57. =cut
  58.  
  59. use 5.005;
  60. use strict;
  61. use Exporter;
  62. use Carp;
  63. use File::Basename;
  64.  
  65. use vars qw (@ISA @EXPORT %channels $me);
  66.  
  67. @ISA = qw (Exporter);
  68. @EXPORT = qw ($exit_code $warnings_are_errors
  69.           &reset_local_duplicates &reset_global_duplicates
  70.           ®ister_channel &msg &exists_channel &channel_type
  71.           &setup_channel &setup_channel_type
  72.           &dup_channel_setup &drop_channel_setup
  73.           &buffer_messages &flush_messages
  74.           US_GLOBAL US_LOCAL
  75.           UP_NONE UP_TEXT UP_LOC_TEXT);
  76.  
  77. $me = basename $0;
  78.  
  79. =head2 Global Variables
  80.  
  81. =over 4
  82.  
  83. =item C<$exit_code>
  84.  
  85. The greatest exit code seen so far. C<$exit_code> is updated from
  86. the C<exit_code> options of C<fatal> and C<error> channels.
  87.  
  88. =cut
  89.  
  90. use vars qw ($exit_code);
  91. $exit_code = 0;
  92.  
  93. =item C<$warnings_are_errors>
  94.  
  95. Set this variable to 1 if warning messages should be treated as
  96. errors (i.e. if they should update C<$exit_code>).
  97.  
  98. =cut
  99.  
  100. use vars qw ($warnings_are_errors);
  101. $warnings_are_errors = 0;
  102.  
  103. =back
  104.  
  105. =head2 Constants
  106.  
  107. =over 4
  108.  
  109. =item C<UP_NONE>, C<UP_TEXT>, C<UP_LOC_TEXT>
  110.  
  111. Possible values for the C<uniq_part> options.  This select the part
  112. of the message that should be considered when filtering out duplicates.
  113. If C<UP_LOC_TEXT> is used, the location and the explanation message
  114. are used for filtering.  If C<UP_TEXT> is used, only the explanation
  115. message is used (so the same message will be filtered out if it appears
  116. at different locations).  C<UP_NONE> means that duplicate messages
  117. should be output.
  118.  
  119. =cut
  120.  
  121. use constant UP_NONE => 0;
  122. use constant UP_TEXT => 1;
  123. use constant UP_LOC_TEXT => 2;
  124.  
  125. =item C<US_LOCAL>, C<US_GLOBAL>
  126.  
  127. Possible values for the C<uniq_scope> options.
  128. Use C<US_GLOBAL> for error messages that should be printed only
  129. once in the run of the program, C<US_LOCAL> for message that
  130. should be printed only once per file.  (Actually, C<Channels> does not
  131. now when files are changed, it relies on you calling C<reset_local_duplicates>
  132. when this happens.)
  133.  
  134. =cut
  135.  
  136. # possible values for uniq_scope
  137. use constant US_LOCAL => 0;
  138. use constant US_GLOBAL => 1;
  139.  
  140. =back
  141.  
  142. =head2 Options
  143.  
  144. Channels accept the options described below.  These options can be
  145. passed as a hash to the C<register_channel>, C<setup_channel>, and C<msg>
  146. functions.  The possible keys, with there default value are:
  147.  
  148. =over
  149.  
  150. =item C<type =E<gt> 'warning'>
  151.  
  152. The type of the channel.  One of C<'debug'>, C<'warning'>, C<'error'>, or
  153. C<'fatal'>.  Fatal messages abort the program when they are output.
  154. Error messages update the exit status.  Debug and warning messages are
  155. harmless, except that warnings can be treated as errors of
  156. C<$warnings_are_errors> is set.
  157.  
  158. =item C<exit_code =E<gt> 1>
  159.  
  160. The value to update C<$exit_code> with when a fatal or error message
  161. is emitted.  C<$exit_code> is also updated for warnings output
  162. when @<$warnings_are_errors> is set.
  163.  
  164. =item C<file =E<gt> \*STDERR>
  165.  
  166. The file where the error should be output.
  167.  
  168. =item C<silent =E<gt> 0>
  169.  
  170. Whether the channel should be silent.  Use this do disable a
  171. category of warning, for instance.
  172.  
  173. =item C<uniq_part =E<gt> UP_LOC_TEXT>
  174.  
  175. The part of the message subject to duplicate filtering.  See the
  176. documentation for the C<UP_NONE>, C<UP_TEXT>, and C<UP_LOC_TEXT>
  177. constants above.
  178.  
  179. =item C<uniq_scope =E<gt> US_LOCAL>
  180.  
  181. The scope of duplicate filtering.  See the documentation for the
  182. C<US_LOCAL>, and C<US_GLOBAL> constants above.
  183.  
  184. =item C<header =E<gt> ''>
  185.  
  186. A string to prepend to each message emitted through this channel.
  187.  
  188. =item C<footer =E<gt> ''>
  189.  
  190. A string to append to each message emitted through this channel.
  191.  
  192. =item C<backtrace =E<gt> 0>
  193.  
  194. Die with a stack backtrace after displaying the message.
  195.  
  196. =back
  197.  
  198. =cut
  199.  
  200. use vars qw (%_default_options %_global_duplicate_messages
  201.          %_local_duplicate_messages);
  202.  
  203. # Default options for a channel.
  204. %_default_options =
  205.   (
  206.    type => 'warning',
  207.    exit_code => 1,
  208.    file => \*STDERR,
  209.    silent => 0,
  210.    uniq_scope => US_LOCAL,
  211.    uniq_part => UP_LOC_TEXT,
  212.    header => '',
  213.    footer => '',
  214.    backtrace => 0,
  215.    );
  216.  
  217. # Filled with output messages as keys, to detect duplicates.
  218. # The value associated with each key is the number of occurrences
  219. # filtered out.
  220. %_local_duplicate_messages = ();
  221. %_global_duplicate_messages = ();
  222.  
  223. sub _reset_duplicates (\%)
  224. {
  225.   my ($ref) = @_;
  226.   my $dup = 0;
  227.   foreach my $k (keys %$ref)
  228.     {
  229.       $dup += $ref->{$k};
  230.     }
  231.   %$ref = ();
  232.   return $dup;
  233. }
  234.  
  235.  
  236. =head2 Functions
  237.  
  238. =over 4
  239.  
  240. =item C<reset_local_duplicates ()>
  241.  
  242. Reset local duplicate messages (see C<US_LOCAL>), and
  243. return the number of messages that have been filtered out.
  244.  
  245. =cut
  246.  
  247. sub reset_local_duplicates ()
  248. {
  249.   return _reset_duplicates %_local_duplicate_messages;
  250. }
  251.  
  252. =item C<reset_global_duplicates ()>
  253.  
  254. Reset local duplicate messages (see C<US_GLOBAL>), and
  255. return the number of messages that have been filtered out.
  256.  
  257. =cut
  258.  
  259. sub reset_global_duplicates ()
  260. {
  261.   return _reset_duplicates %_global_duplicate_messages;
  262. }
  263.  
  264. sub _merge_options (\%%)
  265. {
  266.   my ($hash, %options) = @_;
  267.   local $_;
  268.  
  269.   foreach (keys %options)
  270.     {
  271.       if (exists $hash->{$_})
  272.     {
  273.       $hash->{$_} = $options{$_}
  274.     }
  275.       else
  276.     {
  277.       confess "unknown option `$_'";
  278.     }
  279.     }
  280. }
  281.  
  282. =item C<register_channel ($name, [%options])>
  283.  
  284. Declare channel C<$name>, and override the default options
  285. with those listed in C<%options>.
  286.  
  287. =cut
  288.  
  289. sub register_channel ($;%)
  290. {
  291.   my ($name, %options) = @_;
  292.   my %channel_opts = %_default_options;
  293.   _merge_options %channel_opts, %options;
  294.   $channels{$name} = \%channel_opts;
  295. }
  296.  
  297. =item C<exists_channel ($name)>
  298.  
  299. Returns true iff channel C<$name> has been registered.
  300.  
  301. =cut
  302.  
  303. sub exists_channel ($)
  304. {
  305.   my ($name) = @_;
  306.   return exists $channels{$name};
  307. }
  308.  
  309. =item C<channel_type ($name)>
  310.  
  311. Returns the type of channel C<$name> if it has been registered.
  312. Returns The empty string otherwise.
  313.  
  314. =cut
  315.  
  316. sub channel_type ($)
  317. {
  318.   my ($name) = @_;
  319.   return $channels{$name}{'type'} if exists_channel $name;
  320.   return '';
  321. }
  322.  
  323. # _format_message ($LEADER, $MESSAGE)
  324. # -----------------------------------
  325. # Split $MESSAGE at newlines and add $LEADER to each line.
  326. sub _format_message ($$)
  327. {
  328.   my ($leader, $message) = @_;
  329.   return $leader . join ("\n" . $leader, split ("\n", $message)) . "\n";
  330. }
  331.  
  332. # _print_message ($LOCATION, $MESSAGE, %OPTIONS)
  333. # ----------------------------------------------
  334. # Format the message, check duplicates, and print it.
  335. sub _print_message ($$%)
  336. {
  337.   my ($location, $message, %opts) = @_;
  338.  
  339.   return 0 if ($opts{'silent'});
  340.  
  341.   if ($location)
  342.     {
  343.       $location .= ': ';
  344.     }
  345.   else
  346.     {
  347.       $location = "$me: ";
  348.     }
  349.  
  350.   my $msg = _format_message ($location,
  351.                  $opts{'header'} . $message . $opts{'footer'});
  352.  
  353.   # Check for duplicate message if requested.
  354.   if ($opts{'uniq_part'} != UP_NONE)
  355.     {
  356.       # Which part of the error should we match?
  357.       my $to_filter;
  358.       if ($opts{'uniq_part'} == UP_TEXT)
  359.     {
  360.       $to_filter = $message;
  361.     }
  362.       elsif ($opts{'uniq_part'} == UP_LOC_TEXT)
  363.     {
  364.       $to_filter = $msg;
  365.     }
  366.       else
  367.     {
  368.       confess "unknown value for uniq_part: " . $opts{'uniq_part'};
  369.     }
  370.  
  371.       # Do we want local or global uniqueness?
  372.       my $dups;
  373.       if ($opts{'uniq_scope'} == US_LOCAL)
  374.     {
  375.       $dups = \%_local_duplicate_messages;
  376.     }
  377.       elsif ($opts{'uniq_scope'} == US_GLOBAL)
  378.     {
  379.       $dups = \%_global_duplicate_messages;
  380.     }
  381.       else
  382.     {
  383.       confess "unknown value for uniq_scope: " . $opts{'uniq_scope'};
  384.     }
  385.  
  386.       # Update the hash of messages.
  387.       if (exists $dups->{$to_filter})
  388.     {
  389.       ++$dups->{$to_filter};
  390.       return 0;
  391.     }
  392.       else
  393.     {
  394.       $dups->{$to_filter} = 0;
  395.     }
  396.     }
  397.   my $file = $opts{'file'};
  398.   print $file $msg;
  399.   return 1;
  400. }
  401.  
  402. =item C<msg ($channel, $location, $message, [%options])>
  403.  
  404. Emit a message on C<$channel>, overriding some options of the channel  with
  405. those specified in C<%options>.  Obviously C<$channel> must have been
  406. registered with C<register_channel>.
  407.  
  408. C<$message> is the text of the message, and C<$location> is a location
  409. associated to the message.
  410.  
  411. For instance to complain about some unused variable C<mumble>
  412. declared at line 10 in F<foo.c>, one could do:
  413.  
  414.   msg 'unused', 'foo.c:10', "unused variable `mumble'";
  415.  
  416. If channel C<unused> is not silent (and if this message is not a duplicate),
  417. the following would be output:
  418.  
  419.   foo.c:10: unused variable `mumble'
  420.  
  421. If C<$message> contains newline characters, C<$location> is prepended
  422. to each line.  For instance
  423.  
  424.   msg 'error', 'somewhere', "1st line\n2nd line";
  425.  
  426. becomes
  427.  
  428.   somewhere: 1st line
  429.   somewhere: 2nd line
  430.  
  431. If C<$location> is an empty string, it is replaced by the name of the
  432. program.  Actually, if you don't use C<%options>, you can even
  433. elide the empty C<$location>.  Thus
  434.  
  435.   msg 'fatal', '', 'fatal error';
  436.   msg 'fatal', 'fatal error';
  437.  
  438. both print
  439.  
  440.   progname: fatal error
  441.  
  442. =cut
  443.  
  444.  
  445. use vars qw (@backlog %buffering);
  446.  
  447. # See buffer_messages() and flush_messages() below.
  448. %buffering = ();    # The map of channel types to buffer.
  449. @backlog = ();        # The buffer of messages.
  450.  
  451. sub msg ($$;$%)
  452. {
  453.   my ($channel, $location, $message, %options) = @_;
  454.  
  455.   if (! defined $message)
  456.     {
  457.       $message = $location;
  458.       $location = '';
  459.     }
  460.  
  461.   confess "unknown channel $channel" unless exists $channels{$channel};
  462.  
  463.   my %opts = %{$channels{$channel}};
  464.   _merge_options (%opts, %options);
  465.  
  466.   if (exists $buffering{$opts{'type'}})
  467.     {
  468.       push @backlog, [@_];
  469.       return;
  470.     }
  471.  
  472.   # Print the message if needed.
  473.   if (_print_message ($location, $message, %opts))
  474.     {
  475.       # Adjust exit status.
  476.       if ($opts{'type'} eq 'error'
  477.       || $opts{'type'} eq 'fatal'
  478.       || ($opts{'type'} eq 'warning' && $warnings_are_errors))
  479.     {
  480.       my $es = $opts{'exit_code'};
  481.       $exit_code = $es if $es > $exit_code;
  482.     }
  483.  
  484.       # Die on fatal messages.
  485.       confess if $opts{'backtrace'};
  486.       exit $exit_code if $opts{'type'} eq 'fatal';
  487.     }
  488. }
  489.  
  490.  
  491. =item C<setup_channel ($channel, %options)>
  492.  
  493. Override the options of C<$channel> with those specified by C<%options>.
  494.  
  495. =cut
  496.  
  497. sub setup_channel ($%)
  498. {
  499.   my ($name, %opts) = @_;
  500.   confess "channel $name doesn't exist" unless exists $channels{$name};
  501.   _merge_options %{$channels{$name}}, %opts;
  502. }
  503.  
  504. =item C<setup_channel_type ($type, %options)>
  505.  
  506. Override the options of any channel of type C<$type>
  507. with those specified by C<%options>.
  508.  
  509. =cut
  510.  
  511. sub setup_channel_type ($%)
  512. {
  513.   my ($type, %opts) = @_;
  514.   foreach my $channel (keys %channels)
  515.     {
  516.       setup_channel $channel, %opts
  517.     if $channels{$channel}{'type'} eq $type;
  518.     }
  519. }
  520.  
  521. =item C<dup_channel_setup ()>, C<drop_channel_setup ()>
  522.  
  523. Sometimes it is necessary to make temporary modifications to channels.
  524. For instance one may want to disable a warning while processing a
  525. particular file, and then restore the initial setup.  These two
  526. functions make it easy: C<dup_channel_setup ()> saves a copy of the
  527. current configuration for later restoration by
  528. C<drop_channel_setup ()>.
  529.  
  530. You can think of this as a stack of configurations whose first entry
  531. is the active one.  C<dup_channel_setup ()> duplicates the first
  532. entry, while C<drop_channel_setup ()> just deletes it.
  533.  
  534. =cut
  535.  
  536. use vars qw (@_saved_channels);
  537. @_saved_channels = ();
  538.  
  539. sub dup_channel_setup ()
  540. {
  541.   my %channels_copy;
  542.   foreach my $k1 (keys %channels)
  543.     {
  544.       $channels_copy{$k1} = {%{$channels{$k1}}};
  545.     }
  546.   push @_saved_channels, \%channels_copy;
  547. }
  548.  
  549. sub drop_channel_setup ()
  550. {
  551.   my $saved = pop @_saved_channels;
  552.   %channels = %$saved;
  553. }
  554.  
  555. =item C<buffer_messages (@types)>, C<flush_messages ()>
  556.  
  557. By default, when C<msg> is called, messages are processed immediately.
  558.  
  559. Sometimes it is necessary to delay the output of messages.
  560. For instance you might want to make diagnostics before
  561. channels have been completely configured.
  562.  
  563. After C<buffer_messages(@types)> has been called, messages sent with
  564. C<msg> to a channel whose type is listed in C<@types> will be stored in a
  565. list for later processing.
  566.  
  567. This backlog of messages is processed when C<flush_messages> is
  568. called, with the current channel options (not the options in effect,
  569. at the time of C<msg>).  So for instance if some channel was silenced
  570. in the meantime, messages to this channels will not be print.
  571.  
  572. C<flush_messages> cancels the effect of C<buffer_messages>.  Following
  573. calls to C<msg> are processed immediately as usual.
  574.  
  575. =cut
  576.  
  577. sub buffer_messages (@)
  578. {
  579.   foreach my $type (@_)
  580.     {
  581.       $buffering{$type} = 1;
  582.     }
  583. }
  584.  
  585. sub flush_messages ()
  586. {
  587.   %buffering = ();
  588.   foreach my $args (@backlog)
  589.     {
  590.       &msg (@$args);
  591.     }
  592.   @backlog = ();
  593. }
  594.  
  595. =back
  596.  
  597. =head1 HISTORY
  598.  
  599. Written by Alexandre Duret-Lutz E<lt>F<adl@gnu.org>E<gt>.
  600.  
  601. =cut
  602.  
  603. 1;
  604.  
  605. ### Setup "GNU" style for perl-mode and cperl-mode.
  606. ## Local Variables:
  607. ## perl-indent-level: 2
  608. ## perl-continued-statement-offset: 2
  609. ## perl-continued-brace-offset: 0
  610. ## perl-brace-offset: 0
  611. ## perl-brace-imaginary-offset: 0
  612. ## perl-label-offset: -2
  613. ## cperl-indent-level: 2
  614. ## cperl-brace-offset: 0
  615. ## cperl-continued-brace-offset: 0
  616. ## cperl-label-offset: -2
  617. ## cperl-extra-newline-before-brace: t
  618. ## cperl-merge-trailing-else: nil
  619. ## cperl-continued-statement-offset: 2
  620. ## End:
  621.