BEGIN
{
use
vars
qw( $DEBUG $VERSION $ERROR @EXPORT )
;
no
warnings
'once'
;
our
@EXPORT
=
@Module::Generic::File::IO
;
our
$ERROR
=
''
;
our
$VERSION
=
'v0.2.1'
;
};
sub
new
{
my
$this
=
shift
(
@_
);
my
$class
= (
ref
(
$this
) ||
$this
);
my
$self
;
local
$@;
eval
{
$self
=
$class
->IO::File::new;
};
if
( $@ )
{
return
(
$self
->error(
"Error trying to get a file handle: $@"
) );
}
*$self
= {};
if
( Want::want(
'OBJECT'
) )
{
return
(
$self
->init(
@_
) );
}
my
$new
=
$self
->init(
@_
);
if
( !
defined
(
$new
) )
{
if
(
$self
->_is_object(
$this
) &&
$this
->can(
'pass_error'
) )
{
return
(
$this
->pass_error(
$self
->error ) );
}
else
{
return
(
$self
->pass_error );
}
};
return
(
$new
);
}
sub
init
{
my
(
$p
,
$f
,
$l
) =
caller
;
my
$self
=
shift
(
@_
);
my
$class
= (
ref
(
$self
) ||
$self
);
my
(
$ref
,
$mode
);
if
(
@_
)
{
$ref
=
shift
(
@_
);
return
(
$self
->error(
"No scalar reference was provided."
) )
if
( !
defined
(
$ref
) );
return
(
$self
->error(
"I was expecting a scalar reference, but got a string of "
, CORE::
length
(
$ref
),
" bytes instead."
) )
if
( !
ref
(
$ref
) );
return
(
$self
->error(
"I was expecting a scalar reference, but got instead '"
, overload::StrVal(
$ref
),
"'."
) )
if
( !
$self
->_is_scalar(
$ref
) );
$mode
= (
scalar
(
@_
) && (
ref
(
$_
[0] ) ne
'HASH'
|| (
@_
> 2 && (
@_
% 2 ) ) ) ) ?
shift
(
@_
) :
'+<'
;
$mode
=~ s/^(.*?)\:$//
if
(
substr
(
$mode
, -1, 1 ) eq
':'
);
}
else
{
my
$str
=
''
;
$ref
= \
$str
;
$mode
=
'+<'
;
}
*$self
->{sr} =
$ref
;
my
$opts
=
$self
->_get_args_as_hash(
@_
);
my
$core
= {};
$core
->{
binmode
} = CORE::
delete
(
$opts
->{
binmode
} )
if
(
exists
(
$opts
->{
binmode
} ) );
$core
->{autoflush} = CORE::
delete
(
$opts
->{autoflush} )
if
(
exists
(
$opts
->{autoflush} ) );
$self
->SUPER::init(
@_
) ||
return
(
$self
->pass_error );
my
$this
=
*$self
;
if
(
defined
(
$core
->{
binmode
} ) &&
length
(
$core
->{
binmode
} ) )
{
if
(
$core
->{
binmode
} eq
'scalar'
)
{
}
elsif
(
$core
->{
binmode
} eq
'bytes'
||
$core
->{
binmode
} eq
'crlf'
||
$core
->{
binmode
} eq
'perlio'
||
$core
->{
binmode
} eq
'raw'
||
$core
->{
binmode
} eq
'stdio'
||
$core
->{
binmode
} eq
'unix'
||
$core
->{
binmode
} eq
'win32'
)
{
$mode
.=
':'
.
$core
->{
binmode
};
}
else
{
$mode
.=
':encoding('
.
$core
->{
binmode
} .
')'
;
}
}
$self
->
open
(
$ref
=>
$mode
) ||
return
(
$self
->pass_error );
$self
->autoflush(
$core
->{autoflush} )
if
(
exists
(
$core
->{autoflush} ) );
return
(
$self
);
}
sub
bit {
return
( *{
shift
(
@_
)}->{bit} ); }
sub
can_read {
return
( ( (
$_
[0]->bit & O_RDONLY ) == O_RDONLY ) || (
$_
[0]->bit & O_RDWR ) ); }
sub
can_write {
return
(
shift
->bit & ( O_APPEND | O_WRONLY | O_CREAT | O_RDWR ) ); }
sub
clearerr {
return
(
shift
->clear_error ); }
sub
fcntl
{
my
$self
=
shift
(
@_
);
my
(
$func
,
$bit
) =
@_
;
return
(
$self
->error(
"Function bit value is not an integer."
) )
if
( !
$self
->_is_integer(
$func
) );
if
(
$func
& F_GETFL )
{
return
(
*$self
->{bit} );
}
elsif
(
$func
& F_SETFL )
{
return
(
$self
->error(
"Bitwise value provided '$bit' is not an integer."
) )
if
( !
$self
->_is_integer(
$bit
) );
*$self
->{bit} =
$bit
;
}
else
{
return
(
$self
->error(
"Unknown fcntl function provided Please use either F_GETFL or F_SETFL"
) );
}
}
sub
getline
{
my
$self
=
shift
(
@_
);
return
if
(
$self
->
eof
);
return
(
$self
->SUPER::getline() );
}
sub
is_append {
return
(
shift
->bit & O_APPEND ); }
sub
is_create {
return
(
shift
->bit & O_CREAT ); }
sub
is_readonly {
return
(
shift
->bit == O_RDONLY ); }
sub
is_readwrite {
return
(
shift
->bit & O_RDWR ); }
sub
is_writeonly {
return
(
shift
->bit & O_WRONLY ); }
sub
length
{
my
$self
=
shift
(
@_
);
return
( CORE::
length
( ${
*$self
->{sr} } ) );
}
sub
line
{
my
$self
=
shift
(
@_
);
my
$code
=
shift
(
@_
);
return
(
$self
->error(
"No callback code was provided for line()"
) )
if
( !
defined
(
$code
) ||
ref
(
$code
) ne
'CODE'
);
my
$opts
=
ref
(
$_
[0] ) eq
'HASH'
?
shift
(
@_
) : {
@_
};
return
if
( !
$self
->can_read );
$opts
->{
chomp
} //= 0;
$opts
->{auto_next} //= 0;
my
$l
;
while
(
defined
(
$l
=
$self
->getline ) )
{
chomp
(
$l
)
if
(
$opts
->{
chomp
} );
local
$_
=
$l
;
my
$rv
=
$code
->(
$l
);
if
( !
defined
(
$rv
) && !
$opts
->{auto_next} )
{
last
;
}
}
return
(
$self
);
}
sub
object {
return
( *{
$_
[0] }->{sr} ) }
sub
open
{
my
$self
=
shift
(
@_
);
my
$class
= (
ref
(
$self
) ||
$self
);
return
(
$self
->error(
"open() is not a class function. You need to call it using a $class object."
) )
if
( !
ref
(
$self
) );
my
$ref
=
shift
(
@_
);
return
(
$self
->error(
"No scalar reference was provided."
) )
if
( !
defined
(
$ref
) );
return
(
$self
->error(
"I was expecting a scalar reference, but got a string of "
, CORE::
length
(
$ref
),
" bytes instead."
) )
if
( !
ref
(
$ref
) );
return
(
$self
->error(
"I was expecting a scalar reference, but got instead '"
, overload::StrVal(
$ref
),
"'."
) )
if
( !
$self
->_is_scalar(
$ref
) );
my
$mode
=
shift
(
@_
) ||
return
(
$self
->error(
"No mode was provided. Supported modes are: >, >>, +>, +>>, <, <+, r, r+, w, w+, a, a+"
) );
my
$equi
=
{
'r'
=>
'<'
,
'r+'
=>
'+<'
,
'w'
=>
'>'
,
'w+'
=>
'+>'
,
'a'
=>
'>>'
,
'a+'
=>
'+>>'
,
};
my
$pl_mode
=
$mode
;
if
(
index
(
$mode
,
':'
) != -1 )
{
my
@parts
=
split
( /:/,
$mode
);
$mode
=
$parts
[0];
$parts
[0] =
$equi
->{
$parts
[0] }
if
( CORE::
exists
(
$equi
->{
$parts
[0] } ) );
splice
(
@parts
, 1, 0,
'scalar'
)
if
( !
scalar
(
grep
(
$_
eq
'scalar'
,
@parts
) ) );
$pl_mode
=
join
(
':'
,
@parts
);
}
else
{
$pl_mode
=
$equi
->{
$pl_mode
}
if
( CORE::
exists
(
$equi
->{
$pl_mode
} ) );
$pl_mode
.=
':scalar'
;
}
no
warnings
'uninitialized'
;
local
$@;
my
$rv
=
eval
{
open
(
$self
,
$pl_mode
,
$ref
);
};
if
( $@ )
{
return
(
$self
->error(
"Unable to open( $self, $pl_mode, "
, overload::StrVal(
$ref
),
" ) scalar reference: $@"
) );
}
elsif
( !
$rv
)
{
return
(
$self
->error(
"Unable to open( $self, $pl_mode, "
, overload::StrVal(
$ref
),
" ) scalar reference: $!"
) );
}
my
$bit
;
my
$bitmap
=
{
'<'
=> O_RDONLY,
'<+'
=> O_RDWR,
'+<'
=> O_RDWR,
'>'
=> ( O_CREAT | O_WRONLY ),
'+>'
=> ( O_CREAT | O_RDWR ),
'>>'
=> O_APPEND,
'+>>'
=> ( O_RDWR | O_APPEND ),
'r'
=> O_RDONLY,
'r+'
=> O_RDWR,
'w'
=> ( O_CREAT | O_WRONLY ),
'w+'
=> ( O_CREAT | O_RDWR ),
'a'
=> O_APPEND,
'a+'
=> ( O_RDWR | O_APPEND ),
};
if
(
$mode
=~ /^(<|<\+|\+<|>|\+>|>>|\+>>|r|r\+|w|w\+|a|a\+)$/ )
{
die
(
"Unable to find mode '$1' in our bitmap!\n"
)
if
( !CORE::
exists
(
$bitmap
->{ $1 } ) );
$bit
=
$bitmap
->{ $1 };
if
(
$bit
& O_CREAT )
{
$$ref
=
''
unless
( !
defined
(
$$ref
) );
}
}
else
{
return
(
$self
->error(
"Unsupported mode '$mode'"
) );
}
*$self
->{sr} =
$ref
;
*$self
->{bit} =
$bit
;
return
(
$self
);
}
sub
setpos {
return
(
shift
->
seek
(
$_
[0], 0 ) ); }
sub
size {
return
(
shift
->
length
); }
sub
sref {
return
(
shift
->object ); }
sub
truncate
{
my
$self
= CORE::
shift
(
@_
);
return
if
( !
$self
->can_write );
my
$pos
=
$self
->
tell
;
return
( CORE::
length
( CORE::
substr
( ${
*$self
->{sr}},
$pos
, CORE::
length
( ${
*$self
->{sr}} ) -
$pos
,
''
) ) );
}
sub
sysread
{
return
(
shift
->
read
(
@_
) ); }
sub
syswrite
{
return
(
shift
->
write
(
@_
) ); }
sub
write
{
my
$self
=
$_
[0];
my
$n
=
$_
[2] // CORE::
length
(
$_
[1] );
my
$off
=
$_
[3] || 0;
return
(
$self
->error(
"Wrong number of parameters. Usage: \$io->write( \$buffer, \$length, \$offset ); \$offset is optional."
) )
if
(
@_
< 2 ||
@_
> 4 );
return
if
( !
$self
->can_write );
if
(
@_
== 4 )
{
$n
= ( CORE::
length
(
$_
[1] ) -
$off
)
if
( (
$off
+
$n
) > CORE::
length
(
$_
[1] ) );
}
else
{
$n
= CORE::
length
(
$_
[1] )
if
(
$n
> CORE::
length
(
$_
[1] ) );
}
$self
->
print
(
substr
(
$_
[1],
$off
,
$n
) ) ||
return
(
$self
->pass_error );
return
(
$n
);
}
sub
DESTROY
{
shift
->
close
;
}
sub
FREEZE
{
my
$self
= CORE::
shift
(
@_
);
my
$serialiser
= CORE::
shift
(
@_
) //
''
;
my
$class
= CORE::
ref
(
$self
) ||
$self
;
my
%hash
= %{
*$self
};
CORE::
return
( [
$class
, \
%hash
] )
if
(
$serialiser
eq
'Sereal'
&& Sereal::Encoder->VERSION <= version->parse(
'4.023'
) );
CORE::
return
(
$class
, \
%hash
);
}
sub
THAW
{
my
(
$self
,
undef
,
@args
) =
@_
;
my
$ref
= ( CORE::
scalar
(
@args
) == 1 && CORE::
ref
(
$args
[0] ) eq
'ARRAY'
) ? CORE::
shift
(
@args
) : \
@args
;
my
$class
= ( CORE::
defined
(
$ref
) && CORE::
ref
(
$ref
) eq
'ARRAY'
&& CORE::
scalar
(
@$ref
) > 1 ) ? CORE::
shift
(
@$ref
) : ( CORE::
ref
(
$self
) ||
$self
);
my
$hash
= CORE::
ref
(
$ref
) eq
'ARRAY'
? CORE::
shift
(
@$ref
) : {};
my
$new
=
$class
->new;
foreach
( CORE::
keys
(
%$hash
) )
{
*$new
->{
$_
} = CORE::
delete
(
$hash
->{
$_
} );
}
CORE::
return
(
$new
);
}
1;