# Copyright (c) 2023 Yuki Kimoto
# MIT License
class IO::File extends IO::Handle {
version_from IO;
use Sys;
use Sys::IO;
use Sys::IO::FileStream;
use StringBuffer;
# Fields
has FileStream : Sys::IO::FileStream;
has InputLineNumber : long;
has AutoFlush : protected byte;
# Class methods
static method new : IO::File ($file_name : string = undef, $open_mode : string = undef) {
my $self = new IO::File;
$self->init;
if ($file_name) {
$self->open($file_name, $open_mode);
}
return $self;
}
static method new_from_fd : IO::File ($fd : int, $open_mode : string) {
my $self = new IO::File;
$self->init;
$self->fdopen($fd, $open_mode);
return $self;
}
# Instance methods
protected method init : void ($options : object[] = undef) {
$self->SUPER::init($options);
}
method input_line_number : long () {
return $self->{InputLineNumber};
}
method open : void ($file_name : string, $open_mode : string) {
unless ($file_name) {
die "The file name \$file_name must be defined.";
}
unless ($open_mode) {
die "The open mode \$open_mode must be defined.";
}
if ($self->opened) {
die "Already opened.";
}
my $file_stream_ref = [(Sys::IO::FileStream)undef];
Sys->open($file_stream_ref, (string)$open_mode, $file_name);
my $file_stream = $file_stream_ref->[0];
$self->{FileStream} = $file_stream;
my $fd = Sys->fileno($file_stream);
$self->{FD} = $fd;
}
method close : void () {
unless ($self->opened) {
die "This file is not opened or already closed.";
}
my $file_stream = $self->{FileStream};
Sys::IO->fclose($file_stream);
$self->{FD} = -1;
$self->{InputLineNumber} = 0;
}
method read : int ($string : mutable string, $length : int = -1, $offset : int = 0) {
my $file_stream = $self->{FileStream};
unless ($length >= 0) {
$length = length $string;
}
my $read_length = Sys->read($file_stream, $string, $length, $offset);
return $read_length;
}
method getc : int () {
my $file_stream = $self->{FileStream};
my $char = Sys->getc($file_stream);
return $char;
}
method getline : string () {
my $file_stream = $self->{FileStream};
my $line = Sys->readline($file_stream);
if ($line) {
$self->{InputLineNumber}++;
}
return $line;
}
method getlines : string () {
my $file_stream = $self->{FileStream};
my $string_buffer = StringBuffer->new;
while (1) {
my $line = Sys->readline($file_stream);
if ($line) {
$string_buffer->push($line);
}
else {
last;
}
}
my $lines_string = $string_buffer->to_string;
return $lines_string;
}
method write : int ($string : string, $length : int = -1, $offset : int = 0) {
my $file_stream = $self->{FileStream};
unless ($length >= 0) {
$length = length $string;
}
my $write_length = Sys::IO->fwrite($string, 1, $length, $file_stream);
my $auto_flush = $self->{AutoFlush};
if ($auto_flush) {
$self->flush;
}
return $write_length;
}
method flush : void () {
my $file_stream = $self->{FileStream};
Sys::IO->fflush($file_stream);
}
method eof : int () {
my $file_stream = $self->{FileStream};
my $is_eof = Sys::IO->feof($file_stream);
return $is_eof;
}
method error : int () {
my $file_stream = $self->{FileStream};
my $is_error = Sys::IO->ferror($file_stream);
return $is_error;
}
method clearerr : void () {
my $file_stream = $self->{FileStream};
Sys::IO->clearerr($file_stream);
}
method ungetc : int ($c : int) {
my $file_stream = $self->{FileStream};
my $c_pushed = Sys::IO->ungetc($c, $file_stream);
return $c_pushed;
}
method sync : void () {
my $fd = $self->{FD};
Sys::IO->fsync($fd);
}
method truncate : void ($legnth : long) {
my $fd = $self->{FD};
Sys::IO->ftruncate($fd, $legnth);
}
protected method fdopen : void ($fd : int, $open_mode : string) {
unless ($open_mode) {
die "The open mode \$open_mode must be defined.";
}
if ($self->opened) {
die "Already opened.";
}
my $file_stream_ref = [(Sys::IO::FileStream)undef];
Sys->fdopen($file_stream_ref, $open_mode, $fd);
my $file_stream = $file_stream_ref->[0];
$self->{FileStream} = $file_stream;
$self->{FD} = $fd;
}
method autoflush : int () {
return $self->{AutoFlush};
}
method set_autoflush : void ($autoflush : int) {
$self->{AutoFlush} = (byte)$autoflush;
}
method seek : void ($offset : long, $whence : int) {
my $file_stream = $self->{FileStream};
Sys->seek($file_stream, $offset, $whence);
}
method tell : long () {
my $file_stream = $self->{FileStream};
return Sys->tell($file_stream);
}
}