1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
|
# frozen_string_literal: true
#
# = bio/io/flatfile/buffer.rb - Input stream buffer for FlatFile
#
# Copyright (C) 2001-2006 Naohisa Goto <ng@bioruby.org>
#
# License:: The Ruby License
#
#
#
# See documents for Bio::FlatFile::BufferedInputStream and Bio::FlatFile.
#
require 'bio/io/flatfile'
module Bio
class FlatFile
# Wrapper for a IO (or IO-like) object.
# It can input with a buffer.
class BufferedInputStream
# Creates a new input stream wrapper
def initialize(io, path)
@io = io
@path = path
# initialize prefetch buffer
@buffer = String.new
end
# Creates a new input stream wrapper from the given IO object.
def self.for_io(io)
begin
path = io.path
rescue NameError
path = nil
end
self.new(io, path)
end
# Creates a new input stream wrapper to open file _filename_
# by using File.open.
# *arg is passed to File.open.
#
# Like File.open, a block can be accepted.
#
# Unlike File.open, the default is binary mode, unless text mode
# is explicity specified in mode.
def self.open_file(filename, *arg)
params = _parse_file_open_arg(*arg)
if params[:textmode] or /t/ =~ params[:fmode_string].to_s then
textmode = true
else
textmode = false
end
if block_given? then
File.open(filename, *arg) do |fobj|
fobj.binmode unless textmode
yield self.new(fobj, filename)
end
else
fobj = File.open(filename, *arg)
fobj.binmode unless textmode
self.new(fobj, filename)
end
end
# Parses file open mode parameter.
# mode must be an Integer or a String.
def self._parse_file_open_mode(mode)
modeint = nil
modestr = nil
begin
modeint = mode.to_int
rescue NoMethodError
end
unless modeint then
begin
modestr = mode.to_str
rescue NoMethodError
end
end
if modeint then
return { :fmode_integer => modeint }
end
if modestr then
fmode, ext_enc, int_enc = modestr.split(/\:/)
ret = { :fmode_string => fmode }
ret[:external_encoding] = ext_enc if ext_enc
ret[:internal_encoding] = int_enc if int_enc
return ret
end
nil
end
private_class_method :_parse_file_open_mode
# Parses file open arguments
def self._parse_file_open_arg(*arg)
fmode_hash = nil
perm = nil
elem = arg.shift
if elem then
fmode_hash = _parse_file_open_mode(elem)
if fmode_hash then
elem = arg.shift
if elem then
begin
perm = elem.to_int
rescue NoMethodError
end
end
elem = arg.shift if perm
end
end
if elem.kind_of?(Hash) then
opt = elem.dup
else
opt = {}
end
if elem = opt[:mode] then
fmode_hash = _parse_file_open_mode(elem)
end
fmode_hash ||= {}
fmode_hash[:perm] = perm if perm
unless enc = opt[:encoding].to_s.empty? then
ext_enc, int_enc = enc.split(/\:/)
fmode_hash[:external_encoding] = ext_enc if ext_enc
fmode_hash[:internal_encoding] = int_enc if int_enc
end
[ :external_encoding, :internal_encoding,
:textmode, :binmode, :autoclose, :perm ].each do |key|
val = opt[key]
fmode_hash[key] = val if val
end
fmode_hash
end
private_class_method :_parse_file_open_arg
# Creates a new input stream wrapper from URI specified as _uri_.
# by using OpenURI.open_uri or URI#open.
# _uri_ must be a String or URI object.
# *arg is passed to OpenURI.open_uri or URI#open.
#
# Like OpenURI.open_uri, it can accept a block.
def self.open_uri(uri, *arg)
if uri.kind_of?(URI)
if block_given?
uri.open(*arg) do |fobj|
yield self.new(fobj, uri.to_s)
end
else
fobj0 = uri.open(*arg)
self.new(fobj0, uri.to_s)
end
else
if block_given?
OpenURI.open_uri(uri, *arg) do |fobj|
yield self.new(fobj, uri)
end
else
fobj0 = OpenURI.open_uri(uri, *arg)
self.new(fobj0, uri)
end
end
end
# Pathname, filename or URI to open the object.
# Like File#path, returned value isn't normalized.
attr_reader :path
# Converts to IO object if possible
def to_io
@io.to_io
end
# Closes the IO object if possible
def close
@io.close
end
# Rewinds the IO object if possible
# Internal buffer in this wrapper is cleared.
def rewind
r = @io.rewind
@buffer = ''
r
end
# Returns current file position
def pos
@io.pos - @buffer.size
end
# Sets current file position if possible
# Internal buffer in this wrapper is cleared.
def pos=(p)
r = (@io.pos = p)
@buffer = ''
r
end
# Returns true if end-of-file. Otherwise, returns false.
#
# Note that it returns false if internal buffer is this wrapper
# is not empty,
def eof?
if @buffer.size > 0
false
else
@io.eof?
end
end
# Same as IO#gets.
#
# Compatibility note: the bahavior of paragraph mode (io_rs = '')
# may differ from that of IO#gets('').
def gets(io_rs = $/)
if @buffer.size > 0
if io_rs == nil then
r = @buffer + @io.gets(nil).to_s
@buffer = ''
else
if io_rs == '' then # io_rs.empty?
sp_rs = /((?:\r?\n){2,})/n
else
sp_rs = io_rs
end
a = @buffer.split(sp_rs, 2)
if a.size > 1 then
r = a.shift
r += (io_rs.empty? ? a.shift : io_rs)
@buffer = a.shift.to_s
else
@buffer << @io.gets(io_rs).to_s
a = @buffer.split(sp_rs, 2)
if a.size > 1 then
r = a.shift
r += (io_rs.empty? ? a.shift : io_rs)
@buffer = a.shift.to_s
else
r = @buffer
@buffer = ''
end
end
end
r
else
@io.gets(io_rs)
end
end
# Pushes back given str to the internal buffer.
# Returns nil.
# str must be read previously with the wrapper object.
#
# Note that in current implementation, the str can be everything,
# but please don't depend on it.
#
def ungets(str)
@buffer = str + @buffer
nil
end
# Same as IO#getc.
def getc
if @buffer.size > 0 then
r = @buffer[0]
@buffer = @buffer[1..-1]
else
r = @io.getc
end
r
end
# Pushes back one character into the internal buffer.
# Unlike IO#getc, it can be called more than one time.
def ungetc(c)
@buffer = sprintf("%c", c) + @buffer
nil
end
# Gets current prefetch buffer
def prefetch_buffer
@buffer
end
# It does @io.gets, and addes returned string
# to the internal buffer, and returns the string.
def prefetch_gets(*arg)
r = @io.gets(*arg)
@buffer << r if r
r
end
# It does @io.readpartial, and addes returned string
# to the internal buffer, and returns the string.
def prefetch_readpartial(*arg)
r = @io.readpartial(*arg)
@buffer << r if r
r
end
# Skips space characters in the stream.
# returns nil.
def skip_spaces
ws = { ?\s => true, ?\n => true, ?\r => true, ?\t => true }
while r = self.getc
unless ws[r] then
self.ungetc(r)
break
end
end
nil
end
end #class BufferedInputStream
end #class FlatFile
end #module Bio
|