#!/usr/bin/ruby
=begin
  parser/ruby.rb - parser for ruby script

  Copyright (C) 2003,2004  Masao Mutoh
  Copyright (C) 2001,2002  Yasushi Shoji, Masao Mutoh
 
      Yasushi Shoji   <yashi@yashi.com>
      Masao Mutoh     <mutoh@highway.ne.jp>
 
  You may redistribute it and/or modify it under the same
  license terms as Ruby.
=end

require 'irb/ruby-lex'
require 'irb/ruby-token'

# method replacements
class RubyLex
  def read_escape
    case ch = getc
    when "\n", "\r", "\f"
    when "\\", "n", "t", "r", "f", "v", "a", "e", "b" #"
      return "\\".concat(ch)
    when /[0-7]/
      ungetc ch
      3.times do
        case ch = getc
        when /[0-7]/
        when nil
          break
        else
          ungetc
          break
        end
      end
      
    when "x"
      2.times do
        case ch = getc
        when /[0-9a-fA-F]/
        when nil
          break
        else
          ungetc
          break
        end
      end
      
    when "M"
      if (ch = getc) != '-'
        ungetc
      else
        if (ch = getc) == "\\" #"
          read_escape
        end
      end
      
    when "C", "c", "^"
      if ch == "C" and (ch = getc) != "-"
        ungetc
      elsif (ch = getc) == "\\" #"
        read_escape
      end
    else
      # other characters
    end
  end
  
  def identify_string(ltype, quoted = ltype)
    @ltype = ltype
    @quoted = quoted
    subtype = nil
    str = ''
    begin
      while ch = getc
        if @quoted == ch
      break
        elsif @ltype != "'" && @ltype != "]" and ch == "#"
          subtype = true
        elsif ch == '\\' #'
          e = read_escape
          str.concat e unless e.nil?
        else
          str.concat ch
        end
      end
      if @ltype == "/"
    if peek(0) =~ /i|o|n|e|s/
      getc
    end
      end
      if subtype
        tk = Token(DLtype2Token[ltype], str)
      else
        tk = Token(Ltype2Token[ltype], str)
      end
    ensure
      @ltype = nil
      @quoted = nil
      @lex_state = EXPR_END
    end
  end
end

######################################################################
# GetText::RubyParser

module GetText
  module RubyParser
    ID = ['gettext', '_', 'N_', 'sgettext', 's_']
    PLURAL_ID = ['ngettext', 'n_']

    module_function
    def parse(files, targets = [])
      @targets = targets
      files.each do |file|
        lines = IO.readlines(file)
        parse_lines(file, lines)
      end
      @targets
    end
    
    def parse_lines(file_name, lines)
      file = File.new(file_name)
      rl = RubyLex.new
      rl.set_input(file)
      rl.skip_space = true
      rl.readed_auto_clean_up = true
      str_flag = false
      while tk = rl.token
        case tk
        when RubyToken::TkIDENTIFIER, RubyToken::TkCONSTANT
          if (ID.include? tk.name)
            str = rl.token
            if str.is_a? RubyToken::TkLPAREN
              str = rl.token
            end
            if str.is_a? RubyToken::TkSTRING
              str_flag = true
              assoc_data = @targets.assoc(str.value)
              if assoc_data 
                @targets[@targets.index(assoc_data)] = assoc_data <<
                  file_name + ":" + str.line_no.to_s
              else
                @targets << [str.value.gsub(/\n/, '\n'), file_name + ":" + str.line_no.to_s]
              end
            end
          elsif (PLURAL_ID.include? tk.name)
            str = rl.token
            if str.is_a? RubyToken::TkLPAREN
              str = rl.token
            end
            if str.is_a? RubyToken::TkSTRING
              plural_data = str.value
              line_no = str.line_no.to_s
              rl.token #-> comma is ignored.
              plural_data += "\000" + rl.token.value
              assoc_data = @targets.assoc(plural_data)
              if assoc_data 
                @targets[@targets.index(assoc_data)] = assoc_data <<
                  file_name + ":" + line_no
              else
                @targets << [plural_data, file_name + ":" + line_no]
              end
            end
          end
        when RubyToken::TkSTRING
          if str_flag
            @targets.last[0] << tk.value
          end
        else
          str_flag = false
        end
      end
     @targets
    end
  end 
end  

if __FILE__ == $0
  # ex) ruby c.rb foo.c bar.c
  p GetText::RubyParser.parse(ARGV)
end
