=begin
= Ruby-space definitions that completes C-space funcs for Config
= Info
Copyright (C) 2010 Hiroshi Nakamura <nahi@ruby-lang.org>
= Licence
This program is licenced under the same licence as Ruby.
(See the file 'LICENCE'.)
=endrequire'stringio'moduleOpenSSLclassConfigincludeEnumerableclass<<selfdefparse(str)c=new()parse_config(StringIO.new(str)).eachdo|section,hash|c[section]=hashendcendaliasloadnewdefparse_config(io)beginparse_config_lines(io)rescueConfigError=>ee.message.replace("error in line #{io.lineno}: "+e.message)raiseendenddefget_key_string(data,section,key)# :nodoc:ifv=data[section]&&data[section][key]returnvelsifsection=='ENV'ifv=ENV[key]returnvendendifv=data['default']&&data['default'][key]returnvendendprivatedefparse_config_lines(io)section='default'data={section=>{}}whiledefinition=get_definition(io)definition=clear_comments(definition)nextifdefinition.empty?ifdefinition[0]==?[if/\[([^\]]*)\]/=~definitionsection=$1.stripdata[section]||={}elseraiseConfigError,"missing close square bracket"endelseif/\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/=~definitionif$2section=$1key=$2elsekey=$1endvalue=unescape_value(data,section,$3)(data[section]||={})[key]=value.stripelseraiseConfigError,"missing equal sign"endendenddataend# escape with backslashQUOTE_REGEXP_SQ=/\A([^'\\]*(?:\\.[^'\\]*)*)'/# escape with backslash and doubled dqQUOTE_REGEXP_DQ=/\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/# escaped char mapESCAPE_MAP={"r"=>"\r","n"=>"\n","b"=>"\b","t"=>"\t",}defunescape_value(data,section,value)scanned=[]whilem=value.match(/['"\\$]/)scanned<<m.pre_matchc=m[0]value=m.post_matchcasecwhen"'"ifm=value.match(QUOTE_REGEXP_SQ)scanned<<m[1].gsub(/\\(.)/,'\\1')value=m.post_matchelsebreakendwhen'"'ifm=value.match(QUOTE_REGEXP_DQ)scanned<<m[1].gsub(/""/,'').gsub(/\\(.)/,'\\1')value=m.post_matchelsebreakendwhen"\\"c=value.slice!(0,1)scanned<<(ESCAPE_MAP[c]||c)when"$"ref,value=extract_reference(value)refsec=sectionifref.index('::')refsec,ref=ref.split('::',2)endifv=get_key_string(data,refsec,ref)scanned<<velseraiseConfigError,"variable has no value"endelseraise'must not reaced'endendscanned<<valuescanned.joinenddefextract_reference(value)rest=''ifm=value.match(/\(([^)]*)\)|\{([^}]*)\}/)value=m[1]||m[2]rest=m.post_matchelsif[?(,?{].include?(value[0])raiseConfigError,"no close brace"endifm=value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)returnm[0],m.post_match+restelseraiseendenddefclear_comments(line)# FCOMMENTifm=line.match(/\A([\t\n\f ]*);.*\z/)returnm[1]end# COMMENTscanned=[]whilem=line.match(/[#'"\\]/)scanned<<m.pre_matchc=m[0]line=m.post_matchcasecwhen'#'line=nilbreakwhen"'",'"'regexp=(c=="'")?QUOTE_REGEXP_SQ:QUOTE_REGEXP_DQscanned<<cifm=line.match(regexp)scanned<<m[0]line=m.post_matchelsescanned<<lineline=nilbreakendwhen"\\"scanned<<cscanned<<line.slice!(0,1)elseraise'must not reaced'endendscanned<<linescanned.joinenddefget_definition(io)ifline=get_line(io)while/[^\\]\\\z/=~lineifextra=get_line(io)line+=extraelsebreakendendreturnline.stripendenddefget_line(io)ifline=io.getsline.gsub(/[\r\n]*/,'')endendenddefinitialize(filename=nil)@data={}iffilenameFile.open(filename.to_s)do|file|Config.parse_config(file).eachdo|section,hash|self[section]=hashendendendenddefget_value(section,key)ifsection.nil?raiseTypeError.new('nil not allowed')endsection='default'ifsection.empty?get_key_string(section,key)enddefvalue(arg1,arg2=nil)warn('Config#value is deprecated; use Config#get_value')ifarg2.nil?section,key='default',arg1elsesection,key=arg1,arg2endsection||='default'section='default'ifsection.empty?get_key_string(section,key)enddefadd_value(section,key,value)check_modify(@data[section]||={})[key]=valueenddef[](section)@data[section]||{}enddefsection(name)warn('Config#section is deprecated; use Config#[]')@data[name]||{}enddef[]=(section,pairs)check_modify@data[section]||={}pairs.eachdo|key,value|self.add_value(section,key,value)endenddefsections@data.keysenddefto_sary=[]@data.keys.sort.eachdo|section|ary<<"[ #{section} ]\n"@data[section].keys.eachdo|key|ary<<"#{key}=#{@data[section][key]}\n"endary<<"\n"endary.joinenddefeach@data.eachdo|section,hash|hash.eachdo|key,value|yield[section,key,value]endendenddefinspect"#<#{self.class.name} sections=#{sections.inspect}>"endprotecteddefdata@dataendprivatedefinitialize_copy(other)@data=other.data.dupenddefcheck_modifyraiseTypeError.new("Insecure: can't modify OpenSSL config")iffrozen?enddefget_key_string(section,key)Config.get_key_string(@data,section,key)endendend