class Sys::IO {

  use Sys::IO::FileStream;
  use Sys::IO::Stat;
  use Sys::IO::DirStream;
  use Sys::IO::Dirent;
  use Sys::IO::Utimbuf;
  use Sys::IO::Flock;
  use Sys::IO::Constant as IO;
  
  our $STDIN : Sys::IO::FileStream;
  our $STDOUT : Sys::IO::FileStream;
  our $STDERR : Sys::IO::FileStream;
  
  INIT {
    $STDIN = &INIT_STDIN();
    $STDOUT = &INIT_STDOUT();
    $STDERR = &INIT_STDERR();
  }
  
  native private static method INIT_STDIN : Sys::IO::FileStream ();
  native private static method INIT_STDOUT : Sys::IO::FileStream ();
  native private static method INIT_STDERR : Sys::IO::FileStream ();
  
  static method stdin : Sys::IO::FileStream () { return $STDIN; }
  static method stdout : Sys::IO::FileStream () { return $STDOUT; }
  static method stderr : Sys::IO::FileStream () { return $STDERR; }
  
  native static method open : int ($path : string, $flags : int, $mode = 0 : int);
  
  native static method read : int ($fd : int, $buf : mutable string, $count : int, $buf_offset = 0 : int);
  
  native static method write : int ($fd : int, $buf : string, $count : int, $buf_offset = 0 : int);

  native static method lseek : long ($fd : int, $offset : long, $whence : int);
  
  native static method close : int ($fd : int);
  
  native static method fopen : Sys::IO::FileStream ($path : string, $mode : string);
  
  native static method fdopen : Sys::IO::FileStream ($fd : int, $mode : string);
  
  native static method fileno : int ($stream : Sys::IO::FileStream);
  
  native static method fread : int ($ptr : mutable string, $size : int, $nmemb : int, $stream : Sys::IO::FileStream, $ptr_offset = 0 : int);
  
  native static method feof : int ($stream : Sys::IO::FileStream);
  
  native static method ferror : int ($stream : Sys::IO::FileStream);
  
  native static method clearerr : void ($stream : Sys::IO::FileStream);
  
  native static method getc : int ($stream : Sys::IO::FileStream);
  
  native static method fgets : mutable string ($s : mutable string, $size : int, $stream : Sys::IO::FileStream, $s_offset = 0 : int);
  
  native static method fwrite : int ($ptr : string, $size : int, $nmemb : int, $stream : Sys::IO::FileStream, $ptr_offset = 0 : int);
  
  native static method fseek : int ($stream : Sys::IO::FileStream, $offset : long, $whence : int);
  
  native static method ftell : long ($stream : Sys::IO::FileStream);
  
  native static method fclose : int ($stream : Sys::IO::FileStream);
  
  native static method fflush : int ($stream : Sys::IO::FileStream);
  
  native static method flock : int ($fd : int, $operation : int);

  native static method mkdir : int ($path : string, $mode : int);
  
  native static method umask : int ($mode : int);
  
  native static method rmdir : int ($path : string);
  
  native static method unlink : int ($pathname : string);
  
  native static method rename : int ($oldpath : string, $newpath : string);

  native static method getcwd : mutable string ($buf : mutable string, $size : int);

  native static method _getdcwd : mutable string ($drive : int, $buffer : mutable string, $maxlen : int);

  native static method realpath : mutable string ($path : string, $resolved_path : mutable string);

  native static method _fullpath : mutable string ($absPath : mutable string, $relPath : string, $maxLength : int);

  native static method chdir : int ($path : string);
  
  native static method chmod : int ($path : string, $mode :int);
  
  native static method chown : int ($path : string, $owner : int, $group : int);
  
  native static method truncate : int ($path : string, $length : long);
  
  native static method symlink : int ($oldpath : string, $newpath : string);
  
  native static method readlink : int ($path : string, $buf : mutable string, $bufsiz : int);
  
  native static method opendir : Sys::IO::DirStream ($dir : string);
  
  native static method closedir : int ($dirp : Sys::IO::DirStream);
  
  native static method readdir : Sys::IO::Dirent ($dirp : Sys::IO::DirStream); # Non-thead safe
  
  native static method rewinddir : void ($dirp : Sys::IO::DirStream);
  
  native static method telldir : long ($dirp : Sys::IO::DirStream);
  
  native static method seekdir : void ($dirp : Sys::IO::DirStream, $offset : long);
  
  native static method utime : int ($filename : string, $times : Sys::IO::Utimbuf);
  
  native static method access_raw : int ($pathname : string, $mode : int);
  
  native static method access : int ($pathname : string, $mode : int);
  
  native static method faccessat_raw : int ($dirfd : int, $pathname : string, $mode : int, $flags : int);
  
  native static method faccessat : int ($dirfd : int, $pathname : string, $mode : int, $flags : int);
  
  static method eaccess_emulate_raw : int ($pathname : string, $mode : int) {
    my $status = &faccessat_raw(IO->AT_FDCWD, $pathname, $mode, IO->AT_EACCESS);
    return $status;
  }
  
  static method eaccess_emulate : int ($pathname : string, $mode : int) {
    my $status = &faccessat(IO->AT_FDCWD, $pathname, $mode, IO->AT_EACCESS);
    return $status;
  }
  
  native static method fcntl : int ($fd : int, $command : int, $command_arg = undef : object of Byte|Short|Int|Long|Float|Double|Sys::IO::Flock|object);

  native static method readline : mutable string ($stream : Sys::IO::FileStream);
  
  native static method ftruncate : int ($fd : int, $length : long);
  
  native static method ungetc : int ($c : int, $stream : Sys::IO::FileStream);
  
  native static method fsync : int ($fd : int);
  
  native static method freopen : Sys::IO::FileStream ($path : string, $mode : string, $stream : Sys::IO::FileStream);

  native static method setvbuf : int ($stream : Sys::IO::FileStream, $buf : mutable string, $mode : int, $size : int);

  static method setbuf : void ($stream : Sys::IO::FileStream, $buf : mutable string) {
    my $mode : int;
    if ($buf) {
      $mode = IO->_IOFBF;
    }
    else {
      $mode = IO->_IONBF;
    }
    
    &setvbuf($stream, $buf, $mode, IO->BUFSIZ);
  }

  static method setbuffer : void ($stream : Sys::IO::FileStream, $buf : mutable string, $size : int) {
    my $mode : int;
    if ($buf) {
      $mode = IO->_IOFBF;
    }
    else {
      $mode = IO->_IONBF;
    }
    
    &setvbuf($stream, $buf, $mode, $size);
  }

  static method setlinebuf : void ($stream : Sys::IO::FileStream) {
    my $mode = IO->_IOLBF;
    &setvbuf($stream, undef, $mode, IO->BUFSIZ);
  }
}