# class GxG::IO::IO

    local input / output objects: Stream, Pipe, File, Device
    replacement File/Pipe/Socket IO object and methods built upon EM/EM-Synchrony (uses std. IO obj. for low-level work but attempts actual non-blocking)
    built-in 'non-blocking' does not appear to actually work (looking at you matz)
    .fd: numeric file descriptor or IO object
    mode: file mode. a string or an integer
    opt: hash for specifying mode by name.
       :mode

Same as mode parameter

:external_encoding

External encoding for the `IO`. “-” is a synonym for the default external encoding.

:internal_encoding

Internal encoding for the `IO`. “-” is a synonym for the default internal encoding.

If the value is nil no conversion occurs.

:encoding

Specifies external and internal encodings as “extern:intern”.

:textmode

If the value is truth value, same as “t” in argument mode.

:binmode

If the value is truth value, same as “b” in argument mode.

:autoclose

If the value is false, the fd will be kept open after this `IO` instance gets finalized.

### Public Class Methods

new(*args) click to toggle source
Calls superclass method

    # File lib/gxg/gxg_io.rb, line 1396
    def initialize(*args)
      # Sockets : http://www.tutorialspoint.com/ruby/ruby_socket_programming.htm
      # io.c : http://rxr.whitequark.org/mri/source/io.c?v=1.9.3#8028
      # File Permission Modes : http://www.tutorialspoint.com/ruby/ruby_input_output.htm
      params = self.process_parameters(*args)
      mode_string = ""
      mode_numeric = 0
      if params[:file_descriptor]
        mode_flags = {:binary => ::File::BINARY, :text => ::File::TEXT, :read => ::File::RDONLY, :write => ::File::WRONLY, :readwrite => ::File::RDWR, :create => ::File::CREAT, :overwrite => ::File::TRUNC, :append => ::File::APPEND}
        modes = GxG::IO::IO::valid_mode_set({:type => :file, :read => true, :write => true, :text => true, :binary => true})
      else
        mode_flags = {:binary => ::IO::BINARY, :text => ::IO::TEXT, :read => ::IO::RDONLY, :write => ::IO::WRONLY, :readwrite => ::IO::RDWR, :create => ::IO::CREAT, :overwrite => ::IO::TRUNC, :append => ::IO::APPEND}
        modes = GxG::IO::IO::valid_mode_set({:type => :io, :read => true, :write => true, :text => true, :binary => true})
      end
      the_mode_used = nil
      options = {}
      # :mode
      #Same as mode parameter
      if params[:mode]
        if params[:mode].index(:binary)
          if params[:mode].index(:read)
            if params[:mode].index(:write)
              mode_string = "binary_readwrite"
              mode_numeric = (mode_numeric | mode_flags[:binary] | mode_flags[:readwrite])
            else
              mode_string = "binary_read"
              mode_numeric = (mode_numeric | mode_flags[:binary] | mode_flags[:read])
            end
          else
            if params[:mode].index(:write)
              mode_string = "binary_write"
              mode_numeric = (mode_numeric | mode_flags[:binary] | mode_flags[:write])
            end
          end
        else
          if params[:mode].index(:read)
            if params[:mode].index(:write)
              mode_string = "text_readwrite"
              mode_numeric = (mode_numeric | mode_flags[:text] | mode_flags[:readwrite])
            else
              mode_string = "text_read"
              mode_numeric = (mode_numeric | mode_flags[:text] | mode_flags[:read])
            end
          else
            if params[:mode].index(:write)
              mode_string = "text_write"
              mode_numeric = (mode_numeric | mode_flags[:text] | mode_flags[:write])
            end
          end
        end
        if (params[:mode].index(:overwrite) || params[:mode].index(:truncate) )
          mode_string << "_overwrite"
          mode_numeric = (mode_numeric | mode_flags[:overwrite])
        else
          if params[:mode].index(:append)
            mode_string << "_append"
            mode_numeric = (mode_numeric | mode_flags[:append])
          else
            if params[:mode].index(:create)
              mode_string << "_create"
              mode_numeric = (mode_numeric | mode_flags[:create])
            end
          end
        end
        # [:read, :write, :readwrite, :overwrite, :truncate:, :append, :text, :binary]
        modes.to_enum.each do |mode_entry|
          mode_entry[:synonyms].to_enum.each do |the_synonym|
            if the_synonym.is_a?(Symbol)
              if the_synonym == mode_string.to_sym
                the_mode_used = mode_entry
                break
              end
            else
              if the_synonym.is_a?(Numeric)
                if (the_synonym & mode_numeric == mode_numeric)
                  the_mode_used = mode_entry
                  break
                end
              end
            end
          end
          if the_mode_used
            break
          end
          #
        end
        if (the_mode_used)
          if params[:file_descriptor]
            # At this point, only fs objects that already exist will be referenced here.
            if (mode_numeric & mode_flags[:create]) == mode_flags[:create]
              if the_mode_used[:if_create]
                options[:mode] = the_mode_used[:if_create].to_i
              else
                raise ArgumentError, "you cannot open read-only on a non-existent file system object"
              end
            else
              options[:mode] = the_mode_used[:if_exist].to_i
            end
          else
            # IO-ish object.
            # When the mode of original IO is read only, the mode cannot be changed to be writable. Similarly,
            # the mode cannot be changed from write only to readable.  When such a change is attempted
            # the error is raised in different locations according to the platform.
            if params[:object].is_any?(::IO, GxG::IO::IO)
              if (params[:object].stat.readable? && (params[:mode].include?(:write) || params[:mode].include?(:readwrite)) && (params[:object].stat.writable? == false))
                raise ArgumentError, "you cannot make a read-only IO writable"
              end
              if (params[:object].stat.writable? && (params[:mode].include?(:read) || params[:mode].include?(:readwrite)) && (params[:object].stat.readable? == false))
                raise ArgumentError, "you cannot make a write-only IO readable"
              end
              if (params[:object].stat.binmode? && params[:mode].include?(:text))
                raise ArgumentError, "you cannot make a binary IO text-only"
              end
            else
              unless params[:object].is_any?( ::StringIO, GxG::IO::StringIO)
                raise ArgumentError, "you MUST specify an IO :object or a :file_descriptor Fixnum"
              end
            end
            #              if params[:mode].include?(:binary)
            #                unless params[:object].binmode?
            #                  params[:object].binmode
            #                end
            #              end
            if (mode_numeric & mode_flags[:create]) == mode_flags[:create]
              if the_mode_used[:if_create]
                options[:mode] = the_mode_used[:if_create].to_i
              else
                raise ArgumentError, "you cannot open read-only on a non-existent file system object"
              end
            else
              options[:mode] = the_mode_used[:if_exist].to_i
            end
          end
          #
        else
          modes_list = []
          modes.to_enum.each do |item|
            modes_list << item[:synonyms]
          end
          raise ArgumentError, "#{params[:mode].inspect} is an invalid :mode, use one of the following: #{modes_list.inspect}"
        end
      end
      #
      @conversion_options = {:external => {}, :internal => {}}
      #
      if params[:mode].include?(:binary)
        options[:external_encoding] = ::Encoding::ASCII_8BIT
      else
        if params[:external_encoding].is_a?(::Encoding)
          options[:external_encoding] = params.delete(:external_encoding)
          #:2nd internal_encoding parameter and 3rd parameter optional hash ignored
          # if you want the supplied string's encoding - best to simply pass it on the .new method call params.
        else
          options[:external_encoding] = ::Encoding.default_external
        end
      end
      #
      # if external_encoding is BINARY/ASCII_8BIT - just nullify internal_encoding, and skip external/internal conversion option mapping.
      if params[:mode].include?(:binary)
        @internal_encoding = nil
      else
        if (params[:internal_encoding].is_a?(::Encoding) && params[:internal_encoding] != options[:external_encoding])
          @internal_encoding = params.delete(:internal_encoding)
        else
          @internal_encoding = ::Encoding.default_internal
        end
        #
        if @internal_encoding
          if @internal_encoding != options[:external_encoding]
            if params[:external_conversion]
              # External conversion options will have to be dynamically generated upon transcode_to_external as *any* encoding is possible, not just internal_encoding
              @conversion_options[:external] = ::String::transcode_options(options[:external_encoding],@internal_encoding,params[:external_conversion])
            else
              @conversion_options[:external] = ::String::transcode_options(options[:external_encoding],@internal_encoding)
            end
            #
            if @internal_encoding == ::Encoding::ASCII_8BIT
              #
              if params[:internal_conversion]
                nl_op = self.newline_option_used(params[:internal_conversion])
                conv_options = {}
                if nl_op
                  conv_options[(nl_op)] = true
                end
                @conversion_options[:internal] = conv_options
              end
            else
              if params[:internal_conversion]
                @conversion_options[:internal] = ::String::transcode_options(@internal_encoding,options[:external_encoding],params[:internal_conversion])
              else
                @conversion_options[:internal] = ::String::transcode_options(@internal_encoding,options[:external_encoding])
              end
            end
            #
          end
        end
        #
      end
      #
      @external_field_separator = nil
      if params[:external_field_separator]
        @external_field_separator = params[:external_field_separator]
      end
      @external_record_separator = nil
      if params[:external_record_separator]
        @external_record_separator = params[:external_record_separator]
      end
      @internal_field_separator = nil
      if params[:internal_field_separator]
        @internal_field_separator = params[:internal_field_separator]
      end
      @internal_record_separator = nil
      if params[:internal_record_separator]
        @internal_record_separator = params[:internal_record_separator]
      end
      #:autoclose
      # If the value is false, the fd will be kept open after this IO instance gets finalized.
      if params[:autoclose]
        options[:autoclose] = params.delete(:autoclose)
      end
      #
      mode_numeric = options.delete(:mode)
      if params[:file_descriptor]
        super(params[:file_descriptor],mode_numeric,options)
      else
        super(params[:object],mode_numeric,options)
      end
      #
      unless params[:object].is_any?(::StringIO, GxG::IO::StringIO)
        self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
      end
      #
      self
    end

pipe(*args) click to toggle source
Calls superclass method

    # File lib/gxg/gxg_io.rb, line 1335
    def self.pipe(*args)
      # Goal: make IO.pipe available on ALL platforms a la false-pipe for code portability (via VFS??).  Duplex contains an @input and an @output IO channel
      # pipes are not 'select' able on Winderz, so a faux-pipe must be shimmed in.
      if [:kazoo_os].include?(GxG::SYSTEM.platform[:platform])
        # TODO: GxG::IO::IO::pipe : provide a ring buffer and return read and write endpoint ios for it where the platform does not support it
        # See: https://en.wikipedia.org/wiki/Circular_buffer
        # See also: http://comments.gmane.org/gmane.comp.lang.ruby.io-splice.general/11
        #
      else
        super(*args)
      end
    end

### Protected Class Methods

interpret_mode(params={}) click to toggle source

    # File lib/gxg/gxg_io.rb, line 1271
    def self.interpret_mode(params={})
      # [:read, :write, :binary, :sync, :tty, :duplex, :append, :create, :wsplit, :wsplit_initialized, :trunc, :text, :setenc_by_bom]
      #
    end

valid_mode_set(params={}) click to toggle source

    # File lib/gxg/gxg_io.rb, line 1275
    def self.valid_mode_set(params={})
      # [:read, :write, :binary, :sync, :tty, :duplex, :append, :create, :wsplit, :wsplit_initialized, :trunc, :text, :setenc_by_bom]
      valid_modes = []
      valid_flags = []
      if params[:binary]
        if params[:read]
          if params[:write]
            valid_flags << @@valid_modes[:flags][(params[:type] || :io)][:binary_read]
            valid_flags << @@valid_modes[:flags][(params[:type] || :io)][:binary_readwrite]
          else
            valid_flags << @@valid_modes[:flags][(params[:type] || :io)][:binary_read]
          end
        else
          if params[:write]
            valid_flags << @@valid_modes[:flags][(params[:type] || :io)][:binary_write]
          end
        end
      else
        if params[:read]
          if params[:write]
            valid_flags << @@valid_modes[:flags][(params[:type] || :io)][:text_read]
            valid_flags << @@valid_modes[:flags][(params[:type] || :io)][:text_readwrite]
          else
            valid_flags << @@valid_modes[:flags][(params[:type] || :io)][:text_read]
          end
        else
          if params[:write]
            valid_flags << @@valid_modes[:flags][(params[:type] || :io)][:text_write]
          end
        end
      end
      @@valid_modes[(params[:type] || :io)].keys.to_enum.each do |mode_key|
        @@valid_modes[(params[:type] || :io)][(mode_key)][:synonyms].to_enum.each do |synonym|
          if synonym.is_a?(Numeric)
            valid_flags.to_enum.each do |flag|
              if synonym & flag == flag
                unless valid_modes.include?(@@valid_modes[(params[:type] || :io)][(mode_key)])
                  valid_modes << @@valid_modes[(params[:type] || :io)][(mode_key)]
                end
              end
            end
          end
        end
      end
      #
      valid_modes
    end

valid_modes() click to toggle source

    # File lib/gxg/gxg_io.rb, line 1268
    def self.valid_modes()
      @@valid_modes
    end

### Public Instance Methods

<<(*args) click to toggle source

    # File lib/gxg/gxg_io.rb, line 1940
    def <<(*args)
      self.write(*args)
      self
    end

external_encoding=(*args) click to toggle source

Public Instance Methods:

    # File lib/gxg/gxg_io.rb, line 1348
    def external_encoding=(*args)
      #
      unless self.binmode?()
        if args[0].is_any?(::Encoding, ::NilClass)
          #
          if args[0] == ::Encoding::ASCII_8BIT
            self.binmode()
          else
            #              old_data = self.string().dup
            #
            if args[0].is_a?(::Encoding)
              self.set_encoding(args[0])
              if @internal_encoding
                if @internal_encoding != self.external_encoding
                  # preserve newline settings
                  nl_op = self.newline_option_used(:external)
                  options = {}
                  if nl_op
                    options[(nl_op)] = true
                  end
                  @conversion_options[:external] = ::String::transcoding_options(self.external_encoding,@internal_encoding,options)
                end
              end
            else
              self.set_encoding(::Encoding.default_external())
            end
            # convert existing data???
            #              if self.external_encoding() != old_data.encoding()
            #                # preserve newline settings
            #                nl_op = self.newline_option_used(:external)
            #                options = {}
            #                if nl_op
            #                  options[(nl_op)] = true
            #                end
            #                old_data.transcode!(self.external_encoding(),options)
            #                #
            #                self.string.replace(old_data)
            #              end
            #
          end
          #
        else
          raise ArgumentError, "Expected an Encoding or NilClass, you provided #{args[0].class}"
        end
      end
      #
    end

fcntl(*args) click to toggle source

portable, cross-platform facade for `Fcntl` (even under Winderz)

Calls superclass method

    # File lib/gxg/gxg_io.rb, line 1631
    def fcntl(*args)
      # Thanks to Jon Cooper for the find at http://www.mail-archive.com/beanstalk-talk@googlegroups.com/msg01092.html
      #The FD_CLOEXEC flag is part of the POSIX API, which Windows doesn't support,
      #but it does  provide analogous functionality.
      #
      #See http://www.perlmonks.org/index.pl?node_id=574349
      #
      #You can implement a patch with https://github.com/jarib/childprocess/ which
      #appears to provide a consistent facade.
      #
      #See
      #http://rubydoc.info/github/jarib/childprocess/master/ChildProcess#close_on_exec-class_method
      #
      #Cheers,
      #Jon
      #
      # Attribution: https://github.com/jarib for Childprocess work.
      #
      # For Win32 See: http://rxr.whitequark.org/mri/source/win32/win32.c?v=1.9.3#fcntl
      # ... and older stuff at : http://rxr.whitequark.org/mri/source/wince/fcntl.h?v=1.8.7
      # Ruby General Fcntl Stuff: http://ruby-doc.org/stdlib-1.9.3/libdoc/fcntl/rdoc/Fcntl.html
      #
      # ### fcntl commands:
      # F_DUPFD       Integer      Positive Integer; -1 on error       Find the lowest numbered available file descriptor greater than or equal to arg and make it a copy of the receiver’s file descriptor. If arg is omitted, it is assumed to be equal to the receiver’s file descriptor.
      # F_GETFD       N/A  File descriptor flags   Retrieves the associated file descriptor flags. Currently, these are either 0 or FD_CLOEXEC. These flags may be set with F_SETFD.
      # F_GETFL       N/A  Integer         Returns the file status flags, i.e. a bitwise OR of O_APPEND, O_ASYNC, O_DIRECT, etc. O_ACCMODE is a bitmask for extracting the access mode from these flags.
      # F_GETLK       struct flock *       N/A  The argument describes a lock the caller wishes to place on the file. If this is possible, the l_type field of the struct is set to Fcntl::F_UNLCK; otherwise the struct is updated with details of the current lock holder.
      # F_SETFD       FD_CLOEXEC or 0      0; -1 on error      Sets the file descriptor flags to arg.When arg is FD_CLOEXEC, this is equivalent to #close_on_exec=true.
      # F_SETFL       Integer      0; -1 on error      Set the file status flags to arg
      # F_SETLK       struct flock *       0; -1 on error.      When the struct’s l_type field has the value F_RDLCK or F_WRLCK, acquires the lock; when it has the value F_UNLCK, releases the lock.
      # F_SETLKW      struct flock *      0; -1 on error.     Behaves like F_SETLK, except when a conflicting lock is held this call blocks until the lock is released or a signal is caught.
      #
      fcntl_modes = {}
      case GxG::SYSTEM.platform()[:platform]
      when :windows
        #          unless nil
        #            fcntl_modes[:io] = {}
        #          end
        # I *think* as of 1.9.2+ winderz now has fcntl support in ruby code, see: win32.c
        # TODO: test fcntl under Winderz
        super(*args)
      else
        super(*args)
      end
    end

read(length=0,outbuffer="") click to toggle source
Calls superclass method

    # File lib/gxg/gxg_io.rb, line 1677
    def read(length=0,outbuffer="")
      if self.fcntl(::Fcntl::F_GETFL,::Fcntl::O_NONBLOCK) & ::Fcntl::O_NONBLOCK == ::Fcntl::O_NONBLOCK
        if outbuffer.is_a?(::String)
          outbuffer = self.transcode_to_internal(outbuffer)
          if self.internal_encoding
            if outbuffer.encoding != self.internal_encoding()
              outbuffer.force_encoding(self.internal_encoding())
            end
          end
        end
        #
        # Attribution: MRI 1.9.3 docs.
        # TODO: research *proper* non-blocking reads and writes
        #read_nonblock just calls the read(2) system call. It causes all errors the
        #read(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc. The caller
        #should care such errors.
        #
        #If the exception is Errno::EWOULDBLOCK or Errno::AGAIN, it is extended by
        #IO::WaitReadable. So IO::WaitReadable can be used to rescue the exceptions for
        #retrying read_nonblock.
        #
        #read_nonblock causes EOFError on EOF.
        #
        #If the read byte buffer is not empty, read_nonblock reads from the buffer like
        #readpartial. In this case, the read(2) system call is not called.
        #
        #When read_nonblock raises an exception kind of IO::WaitReadable, read_nonblock
        #should not be called until io is readable for avoiding busy loop. This can be
        #done as follows.
        #
        #  # emulates blocking read (readpartial).
        #  begin
        #    result = io.read_nonblock(maxlen)
        #  rescue IO::WaitReadable
        #    IO.select([io])
        #    retry
        #  end
        #
        #Although IO#read_nonblock doesn't raise IO::WaitWritable.
        #OpenSSL::Buffering#read_nonblock can raise IO::WaitWritable. If IO and SSL
        #should be used polymorphically, IO::WaitWritable should be rescued too. See
        #the document of OpenSSL::Buffering#read_nonblock for sample code.
        #
        #Note that this method is identical to readpartial except the non-blocking flag
        #is set.
        # millisecond: 1/1000th of a second (reminder)
        read_bytes = 0
        # unless IO is some other type, use default buffer size
        if (self.tty? || self.stat.pipe?)
          buffer_size = GxG::SYSTEM.memory_limits()[:buffers][:terminal].to_i
        else
          if self.stat.socket?
            buffer_size = GxG::SYSTEM.memory_limits()[:buffers][:socket][:ipc][:read][:initial].to_i
          else
            # assume file
            buffer_size = GxG::SYSTEM.memory_limits()[:buffers][:default].to_i
          end
        end
        #
        until (read_bytes == length)
          begin
            if ((length - read_bytes) < buffer_size)
              outbuffer << self.transcode_to_internal(read_nonblock((length - read_bytes)))
              read_bytes += (length - read_bytes)
            else
              outbuffer << self.transcode_to_internal(read_nonblock(buffer_size))
              read_bytes += buffer_size
            end
            #
          rescue ::IO::WaitReadable, ::IO::WaitWritable, GxG::IO::IO::WaitReadable, GxG::IO::IO::WaitWritable
            pause
            begin
              # about 10 ms
              selected = GxG::IO::IO::select([self],nil,nil,0.010)
              until selected
                pause
                selected = GxG::IO::IO::select([self],nil,nil,0.010)
              end
            rescue Exception
              pause
              retry
            end
            retry
          end
          #
          pause
        end
        #
        outbuffer
      else
        result = self.transcode_to_internal(super(length))
      end
      result
    end

readpartial(*args) click to toggle source

    # File lib/gxg/gxg_io.rb, line 1772
    def readpartial(*args)
      # args[0] maxlen (Fixnum)
      # args[1] (optional) buffer_object
      # Note: use the same approach to pause/retry as IO.read_nonblock.
      #
      # Reads at most maxlen bytes from the I/O stream. It blocks only if ios has no data immediately available. It doesn’t block if some data available.
      # If the optional outbuf argument is present, it must reference a String, which will receive the data. It raises EOFError on end of file.
      # readpartial is designed for streams such as pipe, socket, tty, etc. It blocks only when no data immediately available.
      # This means that it blocks only when following all conditions hold:
      #   the byte buffer in the IO object is empty.
      #   the content of the stream is empty.
      #   the stream is not reached to EOF.
      # When readpartial blocks, it waits data or EOF on the stream. If some data is reached, readpartial returns with the data. If EOF is reached,
      # readpartial raises EOFError.
      # When readpartial doesn’t blocks, it returns or raises immediately. If the byte buffer is not empty, it returns the data in the buffer.
      # Otherwise if the stream has some content, it returns the data in the stream. Otherwise if the stream is reached to EOF, it raises EOFError.
      #
      if self.closed_read?
        raise IOError, "not open for reading"
      else
        if self.eof?
          raise EOFError, "end of stream reached"
        else
          result = ""
          result.force_encoding(self.internal_encoding)
          data = self.read(*args)
          if data
            # non-nil
            if data.is_a?(::String)
              # 'blocking' or not?
              if (self.eof?() || (data && data.to_s.size > 0))
                # no pseudo-blocking
                result << data
                data = nil
              else
                # pseudo-blocking
                until (self.eof?() || (data && data.to_s.size > 0))
                  data = self.read(*args)
                  # string, buffer, or nil
                  if data
                    #
                    if data.is_a?(::String)
                      if (data && data.to_s.size > 0)
                        result << data
                        data = nil
                        break
                      else
                        if self.eof?()
                          raise EOFError, "end of stream reached"
                        end
                      end
                    else
                      # buffer
                      result = data
                      data = nil
                      break
                    end
                  else
                    if self.eof?()
                      raise EOFError, "end of stream reached"
                    end
                  end
                  #
                  pause
                  #
                end
              end
            else
              # buffer
              result = data
            end
          else
            if self.eof?()
              raise EOFError, "end of stream reached"
            end
          end
          #
          if result
            if result.is_a?(::String)
              if result.bytesize > 0
                result
              else
                nil
              end
            else
              # buffer
              result
            end
          else
            nil
          end
          #
        end
      end
    end

write(data="") click to toggle source
Calls superclass method

    # File lib/gxg/gxg_io.rb, line 1868
    def write(data="")
      if self.fcntl(::Fcntl::F_GETFL,::Fcntl::O_NONBLOCK) & ::Fcntl::O_NONBLOCK == ::Fcntl::O_NONBLOCK
        # on Winderz, just to a buffer sized spoon full until done ??
        # written_bytes = self.write_nonblock(data)
        # TODO: research *proper* non-blocking reads and writes
        data = self.transcode_to_external(data)
        length = data.size
        written_bytes = 0
        # unless IO is some other type, use default buffer size
        if (self.tty? || self.stat.pipe?)
          buffer_size = GxG::SYSTEM.memory_limits()[:buffers][:terminal].to_i
        else
          if self.stat.socket?
            buffer_size = GxG::SYSTEM.memory_limits()[:buffers][:socket][:ipc][:write][:initial].to_i
          else
            # assume file
            buffer_size = GxG::SYSTEM.memory_limits()[:buffers][:default].to_i
          end
        end
        until (written_bytes == length)
          # on Winderz, use self.write(data) ??
          chunk = ""
          chunk.force_encoding(data.encoding)
          if ((written_bytes) + (buffer_size - 1)) > length
            chunk << data.slice((written_bytes),(length - 1))
          else
            chunk << data.slice((written_bytes),((written_bytes) + (buffer_size - 1)))
          end
          #
          begin
            # On some platforms such as Windows, write_nonblock is not supported according
            # to the kind of the IO object. In such cases, write_nonblock raises
            # Errno::EBADF.
            # # write_nonblock writes only 65536 bytes and return 65536.
            # (The pipe size is 65536 bytes on this environment.)
            #  s = "a" * 100000
            #  p w.write_nonblock(s)     #=> 65536
            #
            #  # write_nonblock cannot write a byte and raise EWOULDBLOCK (EAGAIN).
            #  p w.write_nonblock("b")   # Resource temporarily unavailable (Errno::EAGAIN)
            #
            #If the write buffer is not empty, it is flushed at first.
            #
            #When write_nonblock raises an exception kind of IO::WaitWritable,
            #write_nonblock should not be called until io is writable for avoiding busy
            #loop. This can be done as follows.
            #
            # bytes_written = super(data)
            written_bytes += write_nonblock(chunk).to_i
          rescue ::IO::WaitWritable, GxG::IO::IO::WaitWritable, ::Errno::EINTR, ::Errno::EWOULDBLOCK, ::Errno::EAGAIN
            pause
            begin
              selected = GxG::IO::IO::select(nil,[self],nil,0.010)
              until selected
                pause
                selected = GxG::IO::IO::select(nil,[self],nil,0.010)
              end
            rescue Exception
              pause
              retry
            end
            retry
          end
          #
          pause
        end
      else
        written_bytes = super(self.transcode_to_external(data))
      end
      written_bytes
    end