tmail/tmail/port.rb
#
# port.rb
#
# Copyright (c) 1999 Minero Aoki <aamine@dp.u-netsurf.ne.jp>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU Lesser General Public License version 2 or later.
#
require 'amstd/fileutils'
module TMail
class Port
# initialize() may defined by user
end
class FilePort < Port
FU = FileUtilities
def initialize( fname )
@filename = File.expand_path( fname )
super()
end
def ropen
if iterator? then
begin
p = FileIStream.new( @filename )
yield p
ensure
p.close if p
end
else
FileIStream.new( @filename )
end
end
def wopen
if iterator? then
begin
p = FileOStream.new( @filename )
yield p
ensure
p.close if p
end
else
FileOStream.new( @filename )
end
end
def aopen
if iterator? then
begin
p = FileOStream.new( @filename, 'a' )
yield p
ensure
p.close if p
end
else
FileOStream.new( @filename, 'a' )
end
end
def to_s
"<FilePort:#{@filename}>"
end
def rm
File.unlink( @filename ) if File.file?( @filename )
end
def mv( port )
FU.mv @filename, port.filename
rm
end
BSIZE = FU::BSIZE
def cp( port )
if Port === port then
FU.cp @filename, port.filename
else
ropen {|f|
while tmp = f.read( BSIZE ) do
port << tmp
end
}
end
end
def size
File.size @filename
end
def eql?( other )
FilePort === other and @filename == other.filename
end
alias == eql?
def hash
@filename.hash
end
protected
attr :filename
end
class Stream
CR = "\r"[0]
LF = "\n"[0]
def closed?
@closed
end
alias interrupted? closed?
attr :term, true
end
class FileIStream < Stream
def initialize( fname )
@filename = fname
@f = File.open( fname, 'r' )
@term = nil
@closed = false
@pre = nil
end
def stop
@pre = @f.tell
@f.close
@closed = true
end
alias interrupt stop
def restart
@f = File.open( @filename, 'r' )
@f.seek @pre, 0
@closed = false
end
def close
@f.close
@closed = true
@pre = nil
@filename = nil
end
def to_s
"<FileIStream:open?=#{not @closed},file=#{@filename}>"
end
def each
setterm unless @term
@f.each( @term ){|l| yield l }
end
def gets
setterm unless @term
@f.gets @term
end
def getc
@f.getc
end
def readall
@f.read.to_s
end
def read( num )
setterm unless @term
@f.read num
end
BSIZE = FilePort::BSIZE
def copy_to( to )
while tmp = read( BSIZE ) do
to << tmp
end
end
private
def setterm
@term = "\n"
pre = @f.tell
while ch = @f.getc do
if ch == CR then
if @f.getc == LF then
@term = "\r\n" ; break
else
@term = "\r" ; break
end
elsif ch == LF then
@term = "\n" ; break
end
end
@f.seek pre, 0
end
end
class FileOStream < Stream
def initialize( fname, mode = 'w' )
@filename = fname
@closed = false
@pre = false
@f = File.open( fname, mode )
@term = "\n"
end
def stop
@pre = @f.tell
@f.close
@closed = true
end
alias interrupt stop
def restart
@f = File.open( @filename, 'w' )
@f.seek @pre, 0
@closed = false
end
def close
@f.close
@closed = true
@pre = nil
@filename = nil
end
def to_s
"<FileOStream:open?=#{not @closed},file=#{@filename}>"
end
def puts( str = nil )
@term = "\n" unless @term
@f.write str if str
@f.write @term
end
def putc( ch )
@f.putc ch
end
def write( str )
@f.write str
end
def <<( str )
@f.write str
self
end
def rewind
@f.rewind
end
end
#--------------------------------------------------------------
class StringPort < Port
def initialize
@str = ''
super()
end
def ropen
p = StringIStream.new( @str )
if iterator? then
yield p
p.close
else
return p
end
end
def wopen
@str.replace ''
p = StringOStream.new( @str )
if iterator? then
yield p
p.close
else
return p
end
end
def aopen
p = StringOStream.new( @str )
if iterator? then
yield p
p.close
else
return p
end
end
def to_s
"<StringPort:str=#{@str[0,30]}...>"
end
def rm
@str.replace ''
@str.freeze
end
def cp( port )
if StringPort === port then
port.str.replace @str
else
port.wopen do |s|
s.write @str
end
end
end
def mv( port )
cp port
port.rm
end
def size
@str.size
end
def eql?( other )
StringPort === other and @str == other.str
end
alias == eql?
def hash
@str.hash
end
protected
attr :str
end
class StringIStream < Stream
def initialize( str )
@str = str
@closed = false
@pos = 0
@term = nil
end
def stop
@closed = true
end
alias interrupt stop
def restart
@closed = false
end
def close
@closed = true
@str = nil
end
def to_s
"<StringIStream:open?=#{not @closed},str=#{@str[0,30].inspect}>"
end
def rewind
@pos = 0
end
def each( &block )
setterm unless @term
@str.each( @term ){|l| yield l }
end
def gets
setterm unless @term
if n = @str.index( @term, @pos )
ret = @str[ @pos, n + @term.size - @pos ]
@pos = n + @term.size
if @pos == @str.size then @pos += 1 end
else
ret = @str[ @pos, @str.size - @pos ]
@pos = @str.size + 1
end
return ret
end
def getc
ret = @str[ @pos ]
@pos += 1
return ret
end
def readall
ret = @str[ @pos, @str.size - @pos ]
@pos = @str.size + 1
ret
end
def read( num )
ret = @str[ @pos, num ]
@pos += num
if @pos == @str.size then @pos += 1 end
return ret
end
def copy_to( p )
p << readall
end
private
def setterm
if /\n|\r\n|\r/o === @str then
@term = $&
else
@term = "\n"
end
end
end
class StringOStream < Stream
def initialize( str )
@str = str
@term = "\n"
@closed = false
end
def stop
@closed = true
end
alias interrupt stop
def restart
@closed = false
end
def close
@closed = true
@str = nil
end
def to_s
"<StringOStream:open?=#{not @closed},str=#{@str[0,30].inspect}>"
end
def rewind
@str.replace ''
end
def puts( str = nil )
@str << str if str
@str << @term
end
def putc( ch )
@str << ch.chr
end
def write( str )
@str << str
end
def <<( str )
@str << str
self
end
end
end # module TMail