#!/usr/bin/env ruby # Usage: output_directory xml_spec_file [xml_spec_file...] # $: << '..' require 'cppgen' class StructGen < CppGen def initialize(outdir, amqp) super(outdir, amqp) end EncodingMap={ "octet"=>"Octet", "short"=>"Short", "long"=>"Long", "longlong"=>"LongLong", "longstr"=>"LongString", "shortstr"=>"ShortString", "timestamp"=>"LongLong", "uuid"=>"ShortString",#FIXME "table"=>"FieldTable", "content"=>"Content", "long-struct"=>"LongString" } SizeMap={ "octet"=>"1", "short"=>"2", "long"=>"4", "longlong"=>"8", "timestamp"=>"8" } ValueTypes=["octet", "short", "long", "longlong", "timestamp"] def printable_form(f) if (f.cpptype == "u_int8_t") return "(int) " + f.cppname else return f.cppname end end def generate_encode(f, combined) if (f.field_type == "bit") genl "uint8_t #{f.cppname}_bits = #{f.cppname};" count = 0 combined.each { |c| genl "#{f.cppname}_bits |= #{c.cppname} << #{count += 1};" } genl "buffer.putOctet(#{f.cppname}_bits);" else encoded = EncodingMap[f.field_type] if (encoded) genl "buffer.put#{encoded}(#{f.cppname});" else genl "#{f.cppname}.encode(buffer);" end end end def generate_decode(f, combined) if (f.field_type == "bit") genl "uint8_t #{f.cppname}_bits = buffer.getOctet();" genl "#{f.cppname} = 1 & #{f.cppname}_bits;" count = 0 combined.each { |c| genl "#{c.cppname} = (1 << #{count += 1}) & #{f.cppname}_bits;" } else encoded = EncodingMap[f.field_type] if (encoded) if (ValueTypes.include?(f.field_type)) genl "#{f.cppname} = buffer.get#{encoded}();" else genl "buffer.get#{encoded}(#{f.cppname});" end else genl "#{f.cppname}.decode(buffer);" end end end def generate_size(f, combined) if (f.field_type == "bit") names = ([f] + combined).collect {|g| g.cppname} genl "+ 1 //#{names.join(", ")}" else size = SizeMap[f.field_type] if (size) genl "+ #{size} //#{f.cppname}" elsif (f.cpp_member_type == "SequenceNumberSet") genl "+ #{f.cppname}.encodedSize()" else encoded = EncodingMap[f.field_type] gen "+ 4 " if encoded == "LongString" gen "+ 1 " if encoded == "ShortString" genl "+ #{f.cppname}.size()" end end end def process_fields(s) last = nil count = 0 bits = [] s.fields.each { |f| if (last and last.bit? and f.bit? and count < 7) count += 1 bits << f else if (last and last.bit?) yield last, bits count = 0 bits = [] end if (not f.bit?) yield f end last = f end } if (last and last.bit?) yield last, bits end end def methodbody_extra_defs(s) gen <#{s.cppname} ( EOS if (s.amqp_parent.name == "message" && (s.name == "transfer" || s.name == "append")) indent(4) { genl "*this" } else indent(4) { genl s.param_names.join(",\n") } end genl <(target); if (ptr) { ptr->#{s.cppname}( EOS if (s.amqp_parent.name == "message" && (s.name == "transfer" || s.name == "append")) indent(5) { genl "*this" } else indent(5) { genl s.param_names.join(",\n") } end gen < 0) genl "#{name}(" if (s.kind_of? AmqpMethod) indent {gen "ProtocolVersion, "} end indent { gen s.fields.collect { |f| "#{f.cpptype} _#{f.cppname}" }.join(",\n") } gen ")" genl ": " if s.fields.size > 0 indent { gen s.fields.collect { |f| " #{f.cppname}(_#{f.cppname})" }.join(",\n") } genl " {}" end if (s.kind_of? AmqpMethod) genl "#{name}(ProtocolVersion=ProtocolVersion()) {}" end end def define_accessors(f) genl "void set#{f.name.caps}(#{f.cpptype} _#{f.cppname}) { #{f.cppname} = _#{f.cppname}; }" genl "#{f.cpptype} get#{f.name.caps}() const { return #{f.cppname}; }" end def define_struct(s) classname = s.cppname inheritance = "" if (s.kind_of? AmqpMethod) classname = s.body_name inheritance = ": public AMQMethodBody" end h_file("qpid/framing/#{classname}.h") { if (s.kind_of? AmqpMethod) gen < #include "qpid/framing/amqp_types_full.h" namespace qpid { namespace framing { class #{classname} #{inheritance} { EOS indent { s.fields.each { |f| genl "#{f.cpp_member_type} #{f.cppname};" } } genl "public:" if (s.kind_of? AmqpMethod) indent { genl "static const ClassId CLASS_ID = #{s.amqp_parent.index};" } indent { genl "static const MethodId METHOD_ID = #{s.index};" } end if (s.kind_of? AmqpStruct) if (s.type) if (s.result?) #as result structs have types that are only unique to the #class, they have a class dependent qualifier added to them #(this is inline with current python code but a formal #solution is expected from the WG indent { genl "static const uint16_t TYPE = #{s.type} + #{s.amqp_parent.amqp_parent.index} * 256;" } else indent { genl "static const uint16_t TYPE = #{s.type};" } end end end indent { define_constructor(classname, s) genl "" s.fields.each { |f| define_accessors(f) } } if (s.kind_of? AmqpMethod) methodbody_extra_defs(s) end if (s.kind_of? AmqpStruct) indent {genl "friend std::ostream& operator<<(std::ostream&, const #{classname}&);" } end gen < 0) buffer = "buffer" else buffer = "/*buffer*/" end gen <