package ComErr;

use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);

require Exporter;
require DynaLoader;

@ISA = qw(Exporter DynaLoader);

# Note that exporting $! to packages other than 'main' isn't useful:
# while the export itself is OK, trying to refer to $Package::! is a
# syntax error.  There are only two ways to deal, though:
#
# We could do gross hacks, like tie'ing @EXPORT to a function that examines
# the stack and role-plays accordingly.  But I don't want to deal with
# maintaining any code that works like that. =)
#
# Therefore, to avoid grossitude, we just export $! by default. Any package
# that wishes to avoid the useless symbol in its namespace can explicitly
# provide the exports list in the call to use().

@EXPORT    = qw( $! );
@EXPORT_OK = qw( $ERRNO $SYS_ERRNO );
$VERSION = '0.01';

#bootstrap ComErr $VERSION;

use vars qw( $ERRNO $SYS_ERRNO );

# If $main::! is overridden, we may need to be able to get at 'real' errno.
*SYS_ERRNO = \$!;

# We can't call code to reset $ComErr::ERRNO whenever the variable errno
# gets by a C library.  However, we *can* run code whenever that variable
# is accessed, by using 'tie'.  The object class specified in this case is
# just a wrapper around relevant XSUB functions.
tie $ERRNO, 'ComErr::TiedErrno', $SYS_ERRNO;

# If $! is exported into main, it should be a synonym for $ComErr::ERRNO.
# This accomplishes that.  The mechanism is analogous to '*FOO = *BAR', but
# '$Package::!' isn't syntactically legal.  (man perlmod for details)
$ComErr::{'!'} = $ComErr::{'ERRNO'};

### The following is a wrapper package for $ERRNO tie'ing.
package ComErr::TiedErrno;

use strict;
use vars qw( $errno $debug );

$debug = 1;

sub TIESCALAR { warn "TIESCALAR\n" if $debug;  bless \$_[1], $_[0]; }
sub FETCH     { warn "FETCH @_\n"  if $debug;  "[${$_[0]}]"; }
sub STORE     { warn "STORE @_\n"  if $debug;  ${$_[0]} = $_[1]; }

1;
__END__

=head1 NAME

ComErr - extended error handling using the com_err library

=head1 SYNOPSIS

  use ComErr;
  use some_library_that_uses_com_err;

  function_setting_extended_errors('arg')
    or die "$!";

Or, without overriding the default $! mechanism:

  use ComErr ();
  use some_library_that_uses_com_err;

  function_setting_extended_errors('arg')
    or die "$ComErr::ERRNO";

=head1 DESCRIPTION

The ComErr module provides a Perl interface to the com_err(3) library.
[This library is used to provide extended error codes for various
libraries developed at MIT under the auspices of Project Athena, such
as Kerberos 4 or Zephyr.]

It would be possible to parse the .et files directly from Perl and use
the results to map the error codes onto messages.  However, the author
believes that it's more reliable to use the existing C interface,
since it ensures that the codes rerurned from C libraries correspond
to what's in the .et file.

=head1 AUTHOR

Albert Dvornik <bert@mit.edu>

=head1 SEE ALSO

com_err(3), perl(1).

=cut
