#!/home/watanabe/dist/i386-cygwin/usr/local/bin/ruby
=begin
  rgettext - ruby version of xgettext

  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'
require 'getoptlong'
require 'gettext'

# 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(chrs)
        end
      end
      
    when "C", "c", "^"
      if ch == "C" and (ch = getc) != "-"
        ungetc
      elsif (ch = getc) == "\\" #"
        read_escape(chrs)
      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

######################################################################
# rgettext

class RGettext
  
  # constant values
  VERSION = %w($Revision: 1.3 $)[1].scan(/\d+/).collect {|s| s.to_i}
  DATE = %w($Date: 2002/10/22 14:07:02 $)[1]
  MAX_LINE_LEN = 70

  def start
    opt = check_options
    
    if ARGV.empty?
      print_help
      exit
    end

    generate_pot_header
    ARGV.each do |@curr_file|
      file = File.new(File.expand_path(@curr_file))
      @rl = RubyLex.new
      @rl.set_input(file)
      @rl.skip_space = true
      @rl.readed_auto_clean_up = true
      
      while tk = @rl.token
        check_tk(tk)
      end
    end
    generate_pot
  end

  # following methods are
  private

  def initialize
    # instance variables
    GetText.bindtextdomain("rgettext")

    @gettext_id = ['gettext', '_', 'N_']
    @gettext_plural_id = ['ngettext', 'n_']
    @array = Array.new
  end

  def generate_pot_header
    time = Time.now.strftime("%Y-%m-%d %H:%M%z")
    @out << "# SOME DESCRIPTIVE TITLE.\n"
    @out << "# Copyright (C) YEAR ORGANIZATION\n"
    @out << "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n"
    @out << "#\n"
    @out << "#, fuzzy\n"
    @out << "msgid \"\"\n"
    @out << "msgstr \"\"\n"
    @out << "\"Project-Id-Version: PACKAGE VERSION\\n\"\n"
    @out << "\"POT-Creation-Date: #{time}\\n\"\n"
    @out << "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n"
    @out << "\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n"
    @out << "\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n"
    @out << "\"MIME-Version: 1.0\\n\"\n"
    @out << "\"Content-Type: text/plain; charset=CHARSET\\n\"\n"
    @out << "\"Content-Transfer-Encoding: ENCODING\\n\"\n"
    @out << "\"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n"
  end

  def generate_pot
    result = Array.new
    @array.each do |key|
      msgid = key.shift
      curr_pos = MAX_LINE_LEN
      key.each do |e|
        if curr_pos + e.size > MAX_LINE_LEN
          @out << "\n#:"
          curr_pos = 3
        else
          curr_pos += (e.size + 1)
        end
        @out << " " << e
      end
      if msgid.include?("\000")
        ids = msgid.split(/\000/)
        @out << "\nmsgid \"" << ids[0] << "\"\n"
        @out << "msgid_plural \"" << ids[1] << "\"\n"
        @out << "msgstr[0] \"\"\n"
        @out << "msgstr[1] \"\"\n"
      else
        @out << "\nmsgid \"" << msgid << "\"\n"
        @out << "msgstr \"\"\n"
      end
    end
  end
  
  def print_help
    printf(GetText._("Usage: %s input.rb -o output.pot\n"), $0)
    print GetText._("Extract translatable string from given input files.\n\n")
  end

  def check_options
    command_options = [
      ['--help', '-h', GetoptLong::NO_ARGUMENT], #'print this help and exit'],
      ['--version', '-v', GetoptLong::NO_ARGUMENT], #'print version info and exit'],
      ['--output', '-o', GetoptLong::REQUIRED_ARGUMENT]#, ['FILE', 'write output to specified file']]
    ]
    
    parser = GetoptLong.new
    parser.set_options(*command_options)
    
    opt = Hash.new
    parser.each do |name, arg|
      opt.store(name.sub(/^--/, ""), arg || true)
    end
    
    if opt['version']
      print "#{$0} #{VERSION.join('.')} \(#{DATE}\)\n\n"
      exit
    end
    
    if opt['help']
      print_help
      exit
    end
    
    if opt['output']
      unless FileTest.exist? opt['output']
          @out = File.new(File.expand_path(opt['output']), "w+")
      else
          if $>.tty?
            # FIXME
            printf $stderr, "File '#{opt['output']}' already exists\n"
            exit 1
          else
            printf $stderr, "File '#{opt['output']}' already exists"
            exit 1
          end
      end
    else
      @out = STDOUT
    end
    
    opt
  end
  
  def check_tk(tk)
    case tk
    when RubyToken::TkIDENTIFIER, RubyToken::TkCONSTANT
      if (@gettext_id.include? tk.name)
        str = @rl.token
        if str.is_a? RubyToken::TkLPAREN
          str = @rl.token
        end
        if str.is_a? RubyToken::TkSTRING
          assoc_data = @array.assoc(str.value)
          if assoc_data 
            @array[@array.index(assoc_data)] = assoc_data <<
              @curr_file + ":" + str.line_no.to_s
          else
            @array << [str.value, @curr_file + ":" + str.line_no.to_s]
          end
        end
      elsif (@gettext_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 = @array.assoc(plural_data)
          if assoc_data 
            @array[@array.index(assoc_data)] = assoc_data <<
              @curr_file + ":" + line_no
          else
            @array << [plural_data, @curr_file + ":" + line_no]
          end
        end
      end
    end
  end
  
end  # class RGettext

rgettext = RGettext.new
rgettext.start

# Local variables:
# mode: Ruby
# End:
