# Data.pm: Class Used for Managing Data package RDA::Handle::Data; # $Id: Data.pm,v 1.10 2015/08/19 19:15:05 RDA Exp $ # ARCS: $Header: /home/cvs/cvs/RDA_8/src/scripting/lib/RDA/Handle/Data.pm,v 1.10 2015/08/19 19:15:05 RDA Exp $ # # Change History # 20140731 MSC Enhance the getline method. =head1 NAME RDA::Handle::Data - Class Used for Managing Data =head1 SYNOPSIS require RDA::Handle::Data; =head1 DESCRIPTION The objects of the C class are used for managing data. The following methods are available: =cut use strict; BEGIN { use Exporter; use Symbol; use RDA::Text qw(get_string); use RDA::Handle::Vector; use RDA::Object::Message; } # Define the global public variables use vars qw($STRINGS $VERSION @ISA); $VERSION = sprintf('%d.%02d', q$Revision: 1.10 $ =~ /(\d+)\.(\d+)/); @ISA = qw(Exporter); # Define the global private constants # Define the global private variables # Report the package version sub Version { return $VERSION; } =head2 S<$h = RDA::Handle::Data-Enew($message[,$dft])> The object constructor. C is represented by a symbol, which can be used as a file handle. The following special keys are used: =over 12 =item S< B<'buf' > > String buffer =item S< B<'eol' > > End of line (for read operations) =item S< B<'flg' > > Line indicator =item S< B<'lin' > > Line number =item S< B<'msg' > > Reference to the message object =item S< B<'pos' > > Current position =back =cut sub new { my ($cls, $msg, $dft) = @_; my ($dat, $slf); # Check which data are present in the message return RDA::Handle::Vector->new($msg, $dft) unless ref($msg) eq 'RDA::Object::Message'; return RDA::Handle::Vector->new($dat, $dft) unless ref($dat = $msg->get_info('dat')) eq 'CODE'; # Create the handle object $slf = bless Symbol::gensym(), ref($cls) || $cls; tie *$slf, $slf; ## no critic (Tie) $slf->open($msg); # Return the handle reference return $slf; } sub open ## no critic (Builtin) { my ($slf, $msg) = @_; # Create the handle when not yet done return $slf->new($msg) unless ref($slf); # Initilize the handle *$slf->{'eol'} = qq{\n}; *$slf->{'flg'} = $msg->has_lines; *$slf->{'lin'} = 0; *$slf->{'msg'} = $msg; *$slf->{'pos'} = 0; delete(*$slf->{'buf'}); # Return the handle reference return $slf; } # Manage object attributes sub setinfo { my ($slf, $key, $val) = @_; my ($old); $old = *$slf->{$key}; *$slf->{$key} = $val if defined($val); return $old; } # Declare a routine for an undefined functionality my $und = sub { return }; =head1 BASIC I/O METHODS See L for complete descriptions of each of the following methods, which are just front ends for the corresponding built-in functions: $io->close $io->eof $io->fileno $io->getc $io->read(BUF,LEN,[OFFSET]) $io->print(ARGS) $io->printf(FMT,[ARGS]) $io->stat $io->sysread(BUF,LEN,[OFFSET]) $io->syswrite(BUF,[LEN,[OFFSET]]) $io->truncate(LEN) =cut sub close ## no critic (Ambiguous,Builtin) { my ($slf) = @_; delete(*$slf->{'buf'}); delete *$slf->{'eol'}; delete(*$slf->{'flg'}); delete(*$slf->{'msg'})->skip_data if exists(*$slf->{'msg'}); delete(*$slf->{'lin'}); delete(*$slf->{'pos'}); undef *$slf; return 1; } sub eof ## no critic (Builtin) { my ($slf) = @_; return !exists(*$slf->{'msg'}); } *fileno = $und; sub getc ## no critic (Builtin) { my ($slf) = @_; my ($buf); return $buf if $slf->read($buf, 1); return; } sub read ## no critic (Builtin,Unpack) { my ($slf, undef, $lgt, $off) = @_; my ($blk, $buf, $max, $pos); return unless *$slf->{'msg'}; if (*$slf->{'flg'}) { if (exists(*$slf->{'buf'})) { $buf = delete(*$slf->{'buf'}); $pos = 0; } else { unless (defined($buf = *$slf->{'msg'}->getline)) { delete(*$slf->{'msg'}); return } $buf .= *$slf->{'eol'}; $pos = 1; } $max = length($buf); } else { $buf = exists(*$slf->{'buf'}) ? delete(*$slf->{'buf'}) : q{}; $max = length($buf); $max += _read_block($slf, \$buf, 0) while $max < $lgt && exists(*$slf->{'msg'}); } if ($lgt < $max) { *$slf->{'buf'} = substr($buf, $lgt); } else { $lgt = $max; } if ($off) { substr($_[1], $off) = substr($buf, 0, $lgt); } else { $_[1] = substr($buf, 0, $lgt); } *$slf->{'pos'} += defined($pos) ? $pos : $lgt; return $lgt; } sub _read_block { my ($slf, $buf, $dft) = @_; my ($blk, $lgt); if (($blk, $lgt) = *$slf->{'msg'}->read_data) { $$buf .= $blk; return $lgt; } delete(*$slf->{'msg'}); return $dft; } *print = $und; *printf = $und; *stat = $und; *sysread = \&read; *syswrite = $und; *truncate = $und; =head1 I/O METHODS RELATED TO PERL VARIABLES See L for complete descriptions of each of the following methods. All of them return the previous value of the attribute and takes an optional single argument that when given will set the value. If no argument is given the previous value is unchanged. $| $io-Eautoflush([BOOL]) $. $io-Einput_line_number([NUM]) =cut *autoflush = $und; sub input_line_number { my ($slf, $val) = @_; return $slf->setinfo('lin', $val); } =head1 IO::HANDLE LIKE METHODS See L for complete descriptions of each of the following methods: $io->blocking([BOOL]) $io->clearerr $io->error $io->flush $io->getline $io->getlines $io->opened $io->printflush(ARGS) $io->sync $io->ungetc(ORD) $io->untaint $io->write(BUF,LEN[,OFFSET]) =cut *blocking = $und; *clearerr = $und; *error = $und; *fcntl = $und; *flush = $und; sub getline ## no critic (Complex) { my ($slf) = @_; my ($buf, $chr, $del, $eol, $lgt, $lin, $max, $off); $. = ++*$slf->{'lin'}; # Read from data lines (mode already treated at that level) if (*$slf->{'flg'}) { if (exists(*$slf->{'buf'})) { $lin = delete(*$slf->{'buf'}); $lin =~ s/\n$//; return $lin; } return unless *$slf->{'msg'}; if (defined($lin = *$slf->{'msg'}->getline)) { *$slf->{'pos'}++; return $lin; } delete(*$slf->{'msg'}); return; } # Treat file mode (No line separator defined) unless (defined($/)) { if (exists(*$slf->{'buf'})) { $max = length($lin = delete(*$slf->{'buf'})); unless (*$slf->{'msg'}) { *$slf->{'pos'} += $max; return $lin; } $max = length($lin); } else { return unless *$slf->{'msg'}; $lin = q{}; $max = 0; } $max += $lgt while defined($lgt = _read_block($slf, \$lin)); return $max ? $lin : undef; } # Treat the line mode if ($del = length($/)) { if (exists(*$slf->{'buf'})) { $max = length($lin = delete(*$slf->{'buf'})); } else { return unless *$slf->{'msg'}; $lin = q{}; $max = 0; } $max += _read_block($slf, \$lin, 0) while ($off = index($lin, $/)) < 0 && exists(*$slf->{'msg'}); return unless $max; if ($off < 0) { *$slf->{'pos'} += $max; return $lin; } *$slf->{'pos'} += $del; *$slf->{'buf'} = substr($lin, $off + $del); $lin = substr($lin, 0, $off); chomp($lin); return $lin; } # Treat the paragraph mode $lin = q{}; $eol = 0; while (defined($chr = $slf->getc)) { if ($chr eq qq{\n}) { $eol++; next if $eol > 2; } elsif ($eol > 1) { $slf->ungetc($chr); last; } else { $eol = 0; } $lin .= $chr; } return unless length($lin); $lin =~ s/[\n\r\s]+$//; return $lin; } sub getlines { my ($slf) = @_; my ($lin, @tbl); die get_string('BAD_GETLINES') unless wantarray; push(@tbl, $lin) while defined($lin = $slf->getline); return @tbl; } *ioctl = $und; sub opened { my ($slf) = @_; return defined(*$slf->{'msg'}); } *printflush = $und; *setbuf = $und; *setvbuf = $und; *sync = $und; sub ungetc { my ($slf, $chr) = @_; my ($lgt); if ($lgt = length($chr)) { *$slf->{'pos'} -= $lgt; if (exists(*$slf->{'buf'})) { *$slf->{'buf'} = $chr.*$slf->{'buf'}; } else { *$slf->{'buf'} = $chr; } } return $chr; } *untaint = $und; *write = $und; =head1 SEEK METHODS See L for complete descriptions of each of the following methods: $io->getpos $io->setpos($pos) $io->seek($pos,$whence) $io->sysseek($pos,$whence) $io->tell =cut sub getpos { my ($slf) = @_; return *$slf->{'pos'}; } *seek = $und; *setpos = $und; *sysseek = $und; *tell = \&getpos; =head1 OTHER I/O METHODS =head2 S<$h-Edump([$level[,$text[,$trace]]])> This method returns a string containing the object dump. You can provide an indentation level, a prefix text, and a trace indicator as extra parameters. =cut sub dump ## no critic (Builtin) { my ($slf, $lvl, $txt) = @_; my ($buf, $pre); $lvl = 0 unless defined($lvl); $pre = q{ } x $lvl++; $buf = $pre.$txt."bless {\n"; foreach my $key (sort keys(%{*$slf})) { if ($key eq 'buf') { $buf .= "$pre $key => '[...]'\n"; } elsif ($key eq 'eol') { $buf .= "$pre $key => " .join(q{ }, unpack('H2' x length(*$slf->{$key}), *$slf->{$key}))."\n"; } elsif ($key eq 'msg') { $buf .= *$slf->{'msg'}->dump($lvl, "$key => ")."\n"; } else { $buf .= "$pre $key => ".*$slf->{$key}.qq{\n}; } } $buf .= "$pre}, RDA::Handle::Data"; return $buf; } =head1 TIE METHODS Following methods are implemented to emulate a file handle: BINMODE this CLOSE this DESTROY this EOF this FILENO this GETC this OPEN this, mode, LIST PRINT this, LIST PRINTF this, format, LIST READ this, scalar, length, offset READLINE this SEEK this, position, whence TELL this TIEHANDLE classname, LIST WRITE this, scalar, length, offset =cut sub BINMODE { my $slf = shift; return (@_) ? 0 : 1; } *CLOSE = \&close; sub DESTROY { } *EOF = \&eof; *FILENO = $und; *GETC = \&getc; *OPEN = \&open; *PRINT = $und; *PRINTF = $und; *READ = \&read; sub READLINE { goto &getlines if wantarray; goto &getline; } *SEEK = $und; *TELL = \&getpos; sub TIEHANDLE { my $slf = shift; unless (ref($slf)) { $slf = bless Symbol::gensym(), $slf; $slf->open(@_); } return $slf; } *WRITE = $und; 1; __END__ =head1 SEE ALSO L, L, L, L =head1 COPYRIGHT NOTICE Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. =head1 TRADEMARK NOTICE Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. =cut