Tail - latest incarnation

Hi all,

Here’s the latest incarnation I’ve come up with, stealing bits of code from James Hranicky and
ideas from Curt Sampson.

The inode and dev checks are untested, so if there’s a logic flaw there, please let me know.

Opions & feedback welcome/desired.

Regards,

Dan

Da code!

class Tail < File

def initialize(file,sleeptime=10)
@filename = file
@fh = File.open(file,“r”)
@sleeptime = sleeptime

  @ino = @fh.stat.ino
  @dev = @fh.stat.dev

  @ino_changed = false
  @dev_changed = false

end

···

##############################################################

In block form, read a line at a time in a loop. Otherwise,

just return the number of lines specified as an array.

##############################################################
def tail(max=10)
if block_given?
yield get_lines(max)
loop do
line = @fh.gets
yield line unless line.nil?
if @fh.eof?
check_move()
if (@ino_changed == true) || (@dev_changed == true)
@fh.close
initialize(@filename,@sleeptime)
next
end
@fh.seek(@fh.pos)
end
sleep @sleeptime
end
else
get_lines(max)
end
end

def check_move
begin
if(File.stat(@filename).ino != @ino)
@ino_changed = true
end
if(File.stat(@filename).dev != @dev)
@dev_changed = true
end
rescue Errno::ENOENT
retry
end
end

#######################################################################

Grab the last ‘max’ lines (default is 10). This method was created

for two reasons. First, even a “tail -f” reads the last 10 lines.

Second, it’s separated from the tail() method in the event the

programmer just wants a “plain” tail.

#######################################################################
def get_lines(max)

  @fh.seek(0,IO::SEEK_END)
  newline_count = 0
  while newline_count < max 

     begin
        @fh.pos -= 2
     rescue Errno::EINVAL
        break
     end

     break if @fh.eof?

     if @fh.getc.chr == "\n"
        newline_count += 1
     end
  end

  @fh.readlines

end
end