Skip to content

Instantly share code, notes, and snippets.

@kimoto
Created October 31, 2012 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kimoto/3986233 to your computer and use it in GitHub Desktop.
Save kimoto/3986233 to your computer and use it in GitHub Desktop.
SourceEngine config diff
#!/bin/env ruby
#
# Usage: cfg_diff.rb dirA/autoexec.cfg dirB/autoexec.cfg
#
require 'kconv'
require 'active_support/all'
# 末尾にsuffixを付加するだけの関数
def add_suffix(path, suffix)
if path !~ /#{suffix}$/
path += suffix
end
path
end
# 指定したディレクトリにあるautoexec.cfgを読み込んで
# そこに記載してあるexec行に含まれる何かを実行したりします
def read_cfg_file(base_dir, path)
readed_lines = []
data = File.read(File.join(base_dir, path))
data.each_line{ |line|
line = line.toutf8
line.chomp!
line.sub!(/\r|\n/, "")
next if line == "" # ignore blank
next if line =~ /^\/\// # ignore comment
line.sub!(/;$/, "") # trim last ;
line.strip!
if line =~ /^exec ([^\s\;\"\/]+)/
# 末尾がcfgで終わってなかったときは.cfgを付加
exec_cfg_name = add_suffix(Regexp.last_match(1), ".cfg")
#STDERR.puts "exec detected: #{exec_cfg_name}"
# 指定のcfgファイルを読み込み
readed_lines += read_cfg_file(base_dir, exec_cfg_name)
next # exec行は実行されたので追加しない
end
readed_lines << line
}
readed_lines
end
def trim_quote!(str)
str.sub!(/^"/, "")
str.sub!(/"$/, "")
end
def read_cvarlist(path)
def_cmds = Hash.new
def_cvars = Hash.new
data = File.read(path)
line_size = data.each_line.to_a.size
data.each_line.with_index{ |line, index|
line = line.toutf8
line.chomp!
next if index <= 1 # drop first 2 line
next if index >= line_size - 2 # drop last 2 line
columns = line.split(":")
key = columns[0].strip
value = columns[1].strip
flags = columns[2].split(",").map{|e| e.strip}.reject{|e|e == ""}.map{|e| trim_quote!(e)}
other = columns[3 .. -1].join(" ").strip
if value == "cmd"
def_cmds[key] = [value, flags, other]
else
def_cvars[key] = [value, flags, other]
end
}
return [def_cmds, def_cvars]
end
def extract_parts(def_cmds, def_cvars, cfgs)
aliases = Hash.new
binds = Hash.new
cvars = Hash.new
cmds = Hash.new
unk = Hash.new
cfgs.each{ |line|
if line =~ /^echo\s+(.*)$/
params = Regexp.last_match(1)
trim_quote! params
elsif line =~ /^alias\s+(.*)$/
params = Regexp.last_match(1)
if params =~ /(\S+)\s(.*)$/
key = Regexp.last_match(1)
value = Regexp.last_match(2)
trim_quote! key
aliases[key] = value
else
raise "illegal format"
end
elsif line =~ /^bind\s+(\S+)\s+(.*)$/
key = Regexp.last_match(1)
value = Regexp.last_match(2)
trim_quote! key
binds[key.upcase] = value
elsif line =~ /^(\S+)(\s+(.*))?$/
key = Regexp.last_match(1)
value = Regexp.last_match(2)
if def_cmds.has_key? key
cmds[key] = value
elsif def_cvars.has_key? key
value.sub!(/\/\/.*$/, "")
value.strip!
trim_quote! value
cvars[key] = value
else
if not value.nil?
value.sub!(/\/\/.*$/, "")
value.strip!
trim_quote! value
end
unk[key] = value
end
else
puts "err"
p line.inspect
raise "hoge"
end
}
return [binds, aliases, cmds, cvars, unk]
end
def read_and_parse_cfg_file(def_cmds, def_cvars, path)
base_dir = File.dirname(path)
basename = File.basename(path)
return extract_parts(def_cmds, def_cvars, read_cfg_file(base_dir, basename))
end
def show_cvars(cvarlist_path, autoexec_path)
(def_cmds, def_cvars) = read_cvarlist(cvarlist_path)
(binds, aliases, cmds, cvars, unk) = read_and_parse_cfg_file(def_cmds, def_cvars, autoexec_path)
# http://tf2wiki.net/wiki/Bindable_keys
all_keys = %w(1 2 3 4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 ` ' - = ] \\ , / SPACE ENTER ESCAPE PAUSE BACKSPACE TAB SEMICOLON SHIFT CTRL ALT UPARROW DOWNARROW LEFTARROW RIGHTARROW INS HOME PGUP PGDN DEL END KP_HOME KP_UPARROW KP_PGUP KP_LEFTARROW KP_5 KP_RIGHTARROW KP_END KP_ENTER KP_DOWNARROW KP_PGDN KP_INS KP_DEL KP_SLASH KP_MINUS KP_PLUS KP_MULTIPLY MOUSE1 MOUSE2 MOUSE3 MOUSE4 MOUSE5 MWHEELUP MWHEELDOWN)
#puts "Using binds: #{binds.keys.sort}"
puts "No binding keys: #{(all_keys - binds.keys).sort}"
puts "No binding keys (except numpads): #{(all_keys - binds.keys).reject{|e|e =~ /KP_/}.sort}"
puts "Using aliases: #{aliases.keys.sort.join(",")}"
puts "Using cmds: #{cmds.keys.sort.join(",")}"
puts "Using cvars: #{cvars.keys.sort.join(",")}"
puts "Unknowns: #{unk.keys.sort.join(",")}"
end
def diff_cvars(cvarlist_path, cfg1_path, cfg2_path)
if not cvarlist_path.nil?
(def_cmds, def_cvars) = read_cvarlist(cvarlist_path)
else
def_cmds = {}
def_cvars = {}
end
(binds1, aliases1, cmds1, cvars1, unk1) = read_and_parse_cfg_file(def_cmds, def_cvars, cfg1_path)
(binds2, aliases2, cmds2, cvars2, unk2) = read_and_parse_cfg_file(def_cmds, def_cvars, cfg2_path)
params1 = cmds1.merge(cvars1).merge(unk1)
params2 = cmds2.merge(cvars2).merge(unk2)
(params1.diff(params2)).each{ |key, val|
if params1.has_key? key and params2.has_key? key
puts "Diff: #{key}: a = '#{params1[key]}', b = '#{params2[key]}'"
elsif not params1.has_key?(key)
puts "Only exist in a: #{key} = '#{params2[key]}'"
else
puts "Only exist in b: #{key} = '#{params1[key]}'"
end
}
end
diff1 = ARGV.shift
diff2 = ARGV.shift
if diff1.nil? or diff2.nil?
puts "Usage: #{File.basename($0)} diff1 diff2"
else
diff_cvars(nil, diff1, diff2)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment