#
# rscan.rb
#
#   Copyright (c) 2000,2001 Minero Aoki <aamine@loveruby.net>
#
#   This program is free software.
#   You can distribute/modify this program under the terms of
#   the GNU General Public License version 2 or later.
#


class StringScanner_R

  Version = '0.6.5'

  def self.must_C_version
    raise NotImplementedError, 'strscan is not C version'
  end

  def initialize( str, dup = true )
    @rest = @str = dup ? str.dup : str
    @str.freeze
    @prev = nil
    @last_match = nil
  end

  attr :last_match

  def inspect
    ret = "#<#{type} #{@str.size - @rest.size}/#{@str.size} "
    pos = @str.size - @rest.size
    if pos > 0 then
      ret << ' '
      beg = pos - 5
      beg = 0 if beg < 0
      ret << '"...' if beg > 0
      ret << @str[beg..pos].inspect[1..-1]
    end
    ret << ' @'
    unless @rest.empty? then
      ret << ' ' << @rest[0,5].inspect
      ret[-1,1] = '..."' if @rest.size > 5
    end
    ret << '>'

    ret
  end

  def scan( re )
    if m = re.match( @rest ) then
      @last_match = m
      @prev = @rest
      @rest = m.post_match
      m[0]
    else
      @last_match = @prev = nil
      nil
    end
  end

  def skip( re )
    if m = re.match( @rest ) then
      @last_match = m
      @prev = @rest
      @rest = m.post_match
      @prev.size - @rest.size
    else
      @prev = nil
      @last_match = nil
      nil
    end
  end

  def match?( re )
    if m = re.match( @rest ) then
      @last_match = m
      @prev = @rest
      m.end(0)
    else
      @prev = nil
      @last_match = nil
      nil
    end
  end

  def check( re )
    if m = re.match( @rest ) then
      @last_match = m
      @prev = @rest
      @rest[ 0, m.end(0) ]
    else
      @prev = @last_match = nil
      nil
    end
  end

  def scan_until( re )
    if skip re then
      @last_match.pre_match + @last_match[0]
    else
      nil
    end
  end

  alias skip_until skip
  alias exist? match?
  alias check_until check

  def getch
    scan( /./ )
  end

  def empty?
    @rest.empty?
  end

  def rest?
    not @rest.empty?
  end

  def rest
    @rest.dup
  end

  def restsize
    @rest.size
  end

  def matched?
    not @last_match.nil?
  end

  def matched
    @last_match[0]
  end

  def matchedsize
    m = @last_match
    m.end(0) - m.begin(0)
  end

  def [](n)
    @last_match[n]
  end

  def string
    @str
  end

  def string=( s )
    @str = @rest = s
    @prev = nil
  end

  def pointer
    @str.size - @rest.size
  end

  def pointer=( i )
    @rest = @str[ i, @str.size - i ]
  end

  def reset
    @rest = @str
    @prev = @last_match = nil
  end

  def clear
    @rest = ''
    @prev = @last_match = nil
  end

  def unscan
    @prev or raise ScanError, 'cannot unscan: not scanned yet'
    @rest = @prev
    @prev = nil
  end

end   # class StringScanner_R
