#
#  rmsgfmt.ry - ruby version of msgfmt
#
#  Copyright (C) 2002-2005 Masao Mutoh <mutoh@highway.ne.jp>
# 
#  You may redistribute it and/or modify it under the same
#  license terms as Ruby.

class GetText::PoParser

  token COMMENT MSGID MSGID_PLURAL MSGSTR STRING PLURAL_NUM

  rule

  msgfmt
  : /* empty */
  | msgfmt comment
  | msgfmt message
  ;

  message
  : MSGID string_list MSGSTR string_list
  {
    if @fuzzy
      if val[1] != ""
        $stderr.print _("Warning: fuzzy message was ignored.\n")
        $stderr.print "         msgid '#{val[1]}'\n"
      else
	@data[""] = unescape(val[3])
      end
      @fuzzy = false
    else
      @data[unescape(val[1])] = unescape(val[3]) 
    end
    result = ""
  }
  | MSGID string_list MSGID_PLURAL string_list msgstr_plural
  {
    if @fuzzy
      if val[1] != ""
        $stderr.print _("Warning: fuzzy message was ignored.\n")
        $stderr.print "msgid = '#{val[1]}\n"
      else
	@data[""] = unescape(val[3])
      end
      @fuzzy = false
    else
      @data[unescape(val[1]) + "\000" + unescape(val[3])] = unescape(val[4])
    end
    result = ""
  }
  ;

  msgstr_plural
  : msgstr_plural msgstr_plural_line
  {
    result = val[0] + "\000" + val[1]
  }
  | msgstr_plural_line
  ;
  
  msgstr_plural_line
  : MSGSTR PLURAL_NUM string_list
  {
    result = val[2]
  }
  ;

  comment	
  : COMMENT string_list
  {
    @fuzzy = true if /fuzzy/ =~ val[1]
  }
  | COMMENT
  ;

  string_list
  : string_list STRING
  {
    result = val.delete_if{|item| item == ""}.join
  }
  | STRING
  {
    result = val[0]
  }
  ;
end

---- inner
  def unescape(orig)
    ret = orig.gsub(/\\n/, "\n")
    ret.gsub!(/\\t/, "\t")
    ret.gsub!(/\\r/, "\r")
    ret.gsub!(/\\"/, "\"")
    ret
  end
  
  def parse(str, data)
    @data = data
    @fuzzy = false
    str.strip!
    @q = []
    until str.empty? do
      case str
      when /\A\s+/
	str = $'
      when /\Amsgid_plural/
	@q.push [:MSGID_PLURAL, $&]
	str = $'
      when /\Amsgid/
	@q.push [:MSGID, $&]
	str = $'
      when /\Amsgstr/
	@q.push [:MSGSTR, $&]
	str = $'
      when /\A\[(\d+)\]/
	@q.push [:PLURAL_NUM, $1]
	str = $'
      when /\A\#~(.*)/
	$stderr.print _("Warning: obsolete msgid is existed.\n")
	$stderr.print "         #{$&}\n"
	str = $'
      when /\A\#/
	@q.push [:COMMENT, $&]
	str = $'
      when /\A\"(.*)\"/
	@q.push [:STRING, $1]
	str = $'
      else
	c = str[0,1]
	@q.push [:STRING, c]
	str = str[1..-1]
      end
    end 
    @q.push [false, '$end']
    if $DEBUG
      @q.each do |a,b|
      puts "[#{a}, #{b}]"
      end
    end
    @yydebug = true if $DEBUG
    do_parse
  end
  
  def next_token
    @q.shift
  end
  
---- footer
require 'optparse'
require 'gettext'
require 'fileutils'

include GetText
GetText.bindtextdomain("rmsgfmt")

module GetText
  module RMsgfmt
    VERSION = GetText::VERSION
    DATE = %w($Date: 2005/09/03 09:54:02 $)[1]
    
    module_function
    def run(targetfile = nil, output_path = nil)
      unless targetfile
	targetfile, output_path = check_options
      end
      unless targetfile
	raise ArgumentError, _("no input files")
      end
      unless output_path
	output_path = "messages.mo"
      end

      parser = PoParser.new
      data = MOFile.new
      parser.parse(File.open(targetfile).read, data)
      data.save_to_file(output_path)
    end

    def check_options
      output = nil

      opts = OptionParser.new
      opts.banner = _("Usage: %s input.po [-o output.mo]" % $0)
      opts.separator("")
      opts.separator(_("Generate binary message catalog from textual translation description."))
      opts.separator("")
      opts.separator(_("Specific options:"))

      opts.on("-o", "--output=FILE", _("write output to specified file")) do |out|
	output = out
      end

      opts.on_tail("--version", _("display version information and exit")) do
	puts "#{$0} #{VERSION} (#{DATE})"
	exit
      end
      opts.parse!(ARGV)

      if ARGV.size == 0
	puts opts.help
	exit 1
      end

      [ARGV[0], output]
    end
  end

  module_function
  def rmsgfmt(targetfile = nil, output_path = nil)
    RMsgfmt.run(targetfile, output_path)
  end

  def create_mofiles(verbose = false, 
		     podir = "./po", targetdir = "./data/locale", 
		     targetpath_rule = "%s/LC_MESSAGES")

    modir = File.join(targetdir, targetpath_rule)
    Dir.glob(File.join(podir, "*/*.po")) do |file|
      lang, basename = /\/([^\/]+?)\/(.*)\.po/.match(file[podir.size..-1]).to_a[1,2]
      outdir = modir % lang
      FileUtils.mkdir_p(outdir) unless File.directory?(outdir)
      rmsgfmt(file, File.join(outdir, "#{basename}.mo"))
      if verbose
	$stderr.puts %Q[#{file} -> #{File.join(outdir, "#{basename}.mo")}]
      end
    end
  end
end

if $0 == __FILE__ then
  GetText.rmsgfmt
end
