#!@PERL@ use strict; use lib "../../infrastructure"; use BoxPlatform; # Make protocol C++ classes from a protocol description file # built in type info (values are is basic type, C++ typename) # may get stuff added to it later if protocol uses extra types my %translate_type_info = ( 'int64' => [1, 'int64_t'], 'int32' => [1, 'int32_t'], 'int16' => [1, 'int16_t'], 'int8' => [1, 'int8_t'], 'bool' => [1, 'bool'], 'string' => [0, 'std::string'] ); # built in instructions for logging various types # may be added to my %log_display_types = ( 'int64' => ['0x%llx', 'VAR'], 'int32' => ['0x%x', 'VAR'], 'int16' => ['0x%x', 'VAR'], 'int8' => ['0x%x', 'VAR'], 'bool' => ['%s', '((VAR)?"true":"false")'], 'string' => ['%s', 'VAR.c_str()'] ); if (@ARGV != 1) { die "Usage: $0 \n"; } my ($file) = @ARGV; open IN, $file or die "Can't open input file $file\n"; print "Making protocol classes from $file...\n"; my @extra_header_files; # read attributes my %attr; while() { # get and clean line my $l = $_; $l =~ s/#.*\Z//; $l =~ s/\A\s+//; $l =~ s/\s+\Z//; next unless $l =~ m/\S/; last if $l eq 'BEGIN_OBJECTS'; my ($k,$v) = split /\s+/,$l,2; if($k eq 'AddType') { add_type($v); } elsif($k eq 'ImplementLog') { # Always implement logging } elsif($k eq 'LogTypeToText') { my ($type_name,$printf_format,$arg_template) = split /\s+/,$v; $log_display_types{$type_name} = [$printf_format,$arg_template] } else { $attr{$k} = $v; } } sub add_type { my ($protocol_name, $cpp_name, $header_file) = split /\s+/,$_[0]; $translate_type_info{$protocol_name} = [0, $cpp_name]; push @extra_header_files, $header_file; } # check attributes for(qw/Name ServerContextClass IdentString/) { if(!exists $attr{$_}) { die "Attribute $_ is required, but not specified\n"; } } my $protocol_name = $attr{'Name'}; my ($context_class, $context_class_inc) = split /\s+/,$attr{'ServerContextClass'}; my $ident_string = $attr{'IdentString'}; my $current_cmd = ''; my %cmd_contents; my %cmd_attributes; my %cmd_constants; my %cmd_id; my @cmd_list; # read in the command definitions while() { # get and clean line my $l = $_; $l =~ s/#.*\Z//; $l =~ s/\s+\Z//; next unless $l =~ m/\S/; # definitions or new command thing? if($l =~ m/\A\s+/) { die "No command defined yet" if $current_cmd eq ''; # definition of component $l =~ s/\A\s+//; my ($type,$name,$value) = split /\s+/,$l; if($type eq 'CONSTANT') { push @{$cmd_constants{$current_cmd}},"$name = $value" } else { push @{$cmd_contents{$current_cmd}},$type,$name; } } else { # new command my ($name,$id,@attributes) = split /\s+/,$l; $cmd_attributes{$name} = [@attributes]; $cmd_id{$name} = int($id); $current_cmd = $name; push @cmd_list,$name; } } close IN; # open files my $filename_base = 'autogen_'.$protocol_name.'Protocol'; print "Writing $filename_base.cpp\n"; print "Writing $filename_base.h\n"; open CPP, "> $filename_base.cpp"; open H, "> $filename_base.h"; my $guardname = uc 'AUTOGEN_'.$protocol_name.'Protocol_H'; print CPP <<__E; // Auto-generated file -- do not edit #include "Box.h" #include #include "$filename_base.h" #include "IOStream.h" __E print H <<__E; // Auto-generated file -- do not edit #ifndef $guardname #define $guardname #include #include #ifndef WIN32 #include #endif #include "Protocol.h" #include "Message.h" #include "ServerException.h" class IOStream; __E # extra headers for(@extra_header_files) { print H qq@#include "$_"\n@; } print H <<__E; // need utils file for the server #include "Utils.h" __E my $message_base_class = "${protocol_name}ProtocolMessage"; my $objects_extra_h = ''; my $objects_extra_cpp = ''; # define the context print H "class $context_class;\n\n"; print CPP <<__E; #include "$context_class_inc" #include "MemLeakFindOn.h" __E my $request_base_class = "${protocol_name}ProtocolRequest"; my $reply_base_class = "${protocol_name}ProtocolReply"; # the abstract protocol interface my $protocol_base_class = $protocol_name."ProtocolBase"; my $replyable_base_class = $protocol_name."ProtocolReplyable"; print H <<__E; class $protocol_base_class; class $replyable_base_class; class $reply_base_class; class $message_base_class : public Message { public: virtual std::auto_ptr<$message_base_class> DoCommand($replyable_base_class &rProtocol, $context_class &rContext) const; }; class $reply_base_class { }; class $request_base_class { }; __E print CPP <<__E; std::auto_ptr<$message_base_class> $message_base_class\::DoCommand($replyable_base_class &rProtocol, $context_class &rContext) const { THROW_EXCEPTION(ConnectionException, Conn_Protocol_TriedToExecuteReplyCommand) } __E my %cmd_class; # output the classes foreach my $cmd (@cmd_list) { my @cmd_base_classes = ($message_base_class); if(obj_is_type($cmd, 'Command')) { push @cmd_base_classes, $request_base_class; } if(obj_is_type($cmd, 'Reply')) { push @cmd_base_classes, $reply_base_class; } my $cmd_base_class = join(", ", map {"public $_"} @cmd_base_classes); my $cmd_class = $protocol_name."Protocol".$cmd; $cmd_class{$cmd} = $cmd_class; print H <<__E; class $cmd_class : $cmd_base_class { public: $cmd_class(); $cmd_class(const $cmd_class &rToCopy); ~$cmd_class(); int GetType() const; enum { TypeID = $cmd_id{$cmd} }; __E # constants if(exists $cmd_constants{$cmd}) { print H "\tenum\n\t{\n\t\t"; print H join(",\n\t\t",@{$cmd_constants{$cmd}}); print H "\n\t};\n"; } # flags if(obj_is_type($cmd,'EndsConversation')) { print H "\tbool IsConversationEnd() const;\n"; } if(obj_is_type($cmd,'IsError')) { print H "\tbool IsError(int &rTypeOut, int &rSubTypeOut) const;\n"; print H "\tstd::string GetMessage() const;\n"; } if(obj_is_type($cmd, 'Command')) { print H <<__E; std::auto_ptr<$message_base_class> DoCommand($replyable_base_class &rProtocol, $context_class &rContext) const; // IMPLEMENT THIS\n __E } # want to be able to read from streams? print H "\tvoid SetPropertiesFromStreamData(Protocol &rProtocol);\n"; # write Get functions for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2) { my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]); print H "\t".translate_type_to_arg_type($ty)." Get$nm() {return m$nm;}\n"; } my $param_con_args = ''; # extra constructor? if($#{$cmd_contents{$cmd}} >= 0) { my @a; for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2) { my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]); push @a,translate_type_to_arg_type($ty)." $nm"; } $param_con_args = join(', ',@a); print H "\t$cmd_class(".$param_con_args.");\n"; } print H "\tvoid WritePropertiesToStreamData(Protocol &rProtocol) const;\n"; # set functions for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2) { my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]); print H "\tvoid Set$nm(".translate_type_to_arg_type($ty)." $nm) {m$nm = $nm;}\n"; } print H "\tvirtual void LogSysLog(const char *Action) const;\n"; print H "\tvirtual void LogFile(const char *Action, FILE *file) const;\n"; # write member variables and setup for cpp file my @def_constructor_list; my @copy_constructor_list; my @param_constructor_list; print H "private:\n"; for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2) { my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]); print H "\t".translate_type_to_member_type($ty)." m$nm;\n"; my ($basic,$typename) = translate_type($ty); if($basic) { push @def_constructor_list, "m$nm(0)"; } push @copy_constructor_list, "m$nm(rToCopy.m$nm)"; push @param_constructor_list, "m$nm($nm)"; } # finish off print H "};\n\n"; # now the cpp file... my $def_con_vars = join(",\n\t ",@def_constructor_list); $def_con_vars = "\n\t: ".$def_con_vars if $def_con_vars ne ''; my $copy_con_vars = join(",\n\t ",@copy_constructor_list); $copy_con_vars = "\n\t: ".$copy_con_vars if $copy_con_vars ne ''; my $param_con_vars = join(",\n\t ",@param_constructor_list); $param_con_vars = "\n\t: ".$param_con_vars if $param_con_vars ne ''; print CPP <<__E; $cmd_class\::$cmd_class()$def_con_vars { } $cmd_class\::$cmd_class(const $cmd_class &rToCopy)$copy_con_vars { } $cmd_class\::~$cmd_class() { } int $cmd_class\::GetType() const { return $cmd_id{$cmd}; } __E print CPP "void $cmd_class\::SetPropertiesFromStreamData(Protocol &rProtocol)\n{\n"; for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2) { my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]); if($ty =~ m/\Avector/) { print CPP "\trProtocol.ReadVector(m$nm);\n"; } else { print CPP "\trProtocol.Read(m$nm);\n"; } } print CPP "}\n"; # implement extra constructor? if($param_con_vars ne '') { print CPP "$cmd_class\::$cmd_class($param_con_args)$param_con_vars\n{\n}\n"; } print CPP "void $cmd_class\::WritePropertiesToStreamData(Protocol &rProtocol) const\n{\n"; for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2) { my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]); if($ty =~ m/\Avector/) { print CPP "\trProtocol.WriteVector(m$nm);\n"; } else { print CPP "\trProtocol.Write(m$nm);\n"; } } print CPP "}\n"; if(obj_is_type($cmd,'EndsConversation')) { print CPP "bool $cmd_class\::IsConversationEnd() const\n{\n\treturn true;\n}\n"; } if(obj_is_type($cmd,'IsError')) { # get parameters my ($mem_type,$mem_subtype) = split /,/,obj_get_type_params($cmd,'IsError'); print CPP <<__E; bool $cmd_class\::IsError(int &rTypeOut, int &rSubTypeOut) const { rTypeOut = m$mem_type; rSubTypeOut = m$mem_subtype; return true; } std::string $cmd_class\::GetMessage() const { switch(m$mem_subtype) { __E foreach my $const (@{$cmd_constants{$cmd}}) { next unless $const =~ /^Err_(.*)/; my $shortname = $1; $const =~ s/ = .*//; print CPP <<__E; case $const: return "$shortname"; __E } print CPP <<__E; default: std::ostringstream out; out << "Unknown subtype " << m$mem_subtype; return out.str(); } } __E } my ($log) = make_log_strings_framework($cmd); print CPP <<__E; void $cmd_class\::LogSysLog(const char *Action) const { BOX_TRACE($log); } void $cmd_class\::LogFile(const char *Action, FILE *File) const { std::ostringstream oss; oss << $log; ::fprintf(File, "%s\\n", oss.str().c_str()); ::fflush(File); } __E } my $error_class = $protocol_name."ProtocolError"; # the abstract protocol interface print H <<__E; class $protocol_base_class { public: $protocol_base_class(); virtual ~$protocol_base_class(); virtual const char *GetIdentString(); bool GetLastError(int &rTypeOut, int &rSubTypeOut); protected: void CheckReply(const std::string& requestCommand, const $message_base_class &rReply, int expectedType); void SetLastError(int Type, int SubType) { mLastErrorType = Type; mLastErrorSubType = SubType; } private: $protocol_base_class(const $protocol_base_class &rToCopy); /* do not call */ int mLastErrorType; int mLastErrorSubType; }; class $replyable_base_class : public virtual $protocol_base_class { public: $replyable_base_class(); virtual ~$replyable_base_class(); /* virtual std::auto_ptr<$message_base_class> Receive() = 0; virtual void Send(const ${message_base_class} &rObject) = 0; */ virtual std::auto_ptr ReceiveStream() = 0; virtual int GetTimeout() = 0; void SendStreamAfterCommand(IOStream *pStream); protected: std::list mStreamsToSend; void DeleteStreamsToSend(); private: $replyable_base_class(const $replyable_base_class &rToCopy); /* do not call */ }; __E print CPP <<__E; $protocol_base_class\::$protocol_base_class() : mLastErrorType(Protocol::NoError), mLastErrorSubType(Protocol::NoError) { } $protocol_base_class\::~$protocol_base_class() { } const char *$protocol_base_class\::GetIdentString() { return "$ident_string"; } $replyable_base_class\::$replyable_base_class() { } $replyable_base_class\::~$replyable_base_class() { } void $replyable_base_class\::SendStreamAfterCommand(IOStream *pStream) { ASSERT(pStream != NULL); mStreamsToSend.push_back(pStream); } void $replyable_base_class\::DeleteStreamsToSend() { for(std::list::iterator i(mStreamsToSend.begin()); i != mStreamsToSend.end(); ++i) { delete (*i); } mStreamsToSend.clear(); } void $protocol_base_class\::CheckReply(const std::string& requestCommand, const $message_base_class &rReply, int expectedType) { if(rReply.GetType() == expectedType) { // Correct response, do nothing } else { // Set protocol error int type, subType; if(rReply.IsError(type, subType)) { SetLastError(type, subType); BOX_WARNING(requestCommand << " command failed: " "received error " << (($error_class&)rReply).GetMessage()); } else { SetLastError(Protocol::UnknownError, Protocol::UnknownError); BOX_WARNING(requestCommand << " command failed: " "received unexpected response type " << rReply.GetType()); } // Throw an exception THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnexpectedReply) } } // -------------------------------------------------------------------------- // // Function // Name: Protocol::GetLastError(int &, int &) // Purpose: Returns true if there was an error, and type and subtype if there was. // Created: 2003/08/19 // // -------------------------------------------------------------------------- bool $protocol_base_class\::GetLastError(int &rTypeOut, int &rSubTypeOut) { if(mLastErrorType == Protocol::NoError) { // no error. return false; } // Return type and subtype in args rTypeOut = mLastErrorType; rSubTypeOut = mLastErrorSubType; // and unset them mLastErrorType = Protocol::NoError; mLastErrorSubType = Protocol::NoError; return true; } __E # the callable protocol interface (implemented by Client and Local classes) # with Query methods that don't take a context parameter my $callable_base_class = $protocol_name."ProtocolCallable"; print H <<__E; class $callable_base_class : public virtual $protocol_base_class { public: virtual std::auto_ptr ReceiveStream() = 0; virtual int GetTimeout() = 0; __E # add plain object taking query functions my $with_params; for my $cmd (@cmd_list) { if(obj_is_type($cmd,'Command')) { my $has_stream = obj_is_type($cmd,'StreamWithCommand'); my $argextra = $has_stream?', IOStream &rStream':''; my $queryextra = $has_stream?', rStream':''; my $request_class = $cmd_class{$cmd}; my $reply_class = $cmd_class{obj_get_type_params($cmd,'Command')}; print H "\tvirtual std::auto_ptr<$reply_class> Query(const $request_class &rQuery$argextra) = 0;\n"; my @a; my @na; for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2) { my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]); push @a,translate_type_to_arg_type($ty)." $nm"; push @na,"$nm"; } my $ar = join(', ',@a); my $nar = join(', ',@na); $nar = "($nar)" if $nar ne ''; $with_params .= <<__E; inline std::auto_ptr<$reply_class> Query$cmd($ar$argextra) { $request_class send$nar; return Query(send$queryextra); } __E } } # quick hack to correct bad argument lists for commands with zero parameters but with streams $with_params =~ s/\(, /(/g; print H <<__E; $with_params }; __E # standard remote protocol objects foreach my $type ('Client', 'Server', 'Local') { my $writing_client = ($type eq 'Client'); my $writing_server = ($type eq 'Server'); my $writing_local = ($type eq 'Local'); my $server_or_client_class = $protocol_name."Protocol".$type; my @base_classes; if (not $writing_client) { push @base_classes, $replyable_base_class; } if (not $writing_server) { push @base_classes, $callable_base_class; } if (not $writing_local) { push @base_classes, "Protocol"; } my $base_classes_str = join(", ", map {"public $_"} @base_classes); print H <<__E; class $server_or_client_class : $base_classes_str { public: __E if($writing_local) { print H <<__E; $server_or_client_class($context_class &rContext); __E } else { print H <<__E; $server_or_client_class(IOStream &rStream); std::auto_ptr<$message_base_class> Receive(); void Send(const $message_base_class &rObject); __E } print H <<__E; virtual ~$server_or_client_class(); __E if($writing_server) { # need to put in the conversation function print H <<__E; void DoServer($context_class &rContext); __E } if($writing_client or $writing_local) { # add plain object taking query functions for my $cmd (@cmd_list) { if(obj_is_type($cmd,'Command')) { my $has_stream = obj_is_type($cmd,'StreamWithCommand'); my $argextra = $has_stream?', IOStream &rStream':''; my $queryextra = $has_stream?', rStream':''; my $request_class = $cmd_class{$cmd}; my $reply_class = $cmd_class{obj_get_type_params($cmd,'Command')}; print H "\tstd::auto_ptr<$reply_class> Query(const $request_class &rQuery$argextra);\n"; } } } if($writing_local) { print H <<__E; private: $context_class &mrContext; __E } print H <<__E; protected: virtual std::auto_ptr MakeMessage(int ObjType); __E if($writing_local) { print H <<__E; virtual void InformStreamReceiving(u_int32_t Size) { } virtual void InformStreamSending(u_int32_t Size) { } public: virtual std::auto_ptr ReceiveStream() { std::auto_ptr apStream(mStreamsToSend.front()); mStreamsToSend.pop_front(); return apStream; } __E } else { print H <<__E; virtual void InformStreamReceiving(u_int32_t Size) { this->Protocol::InformStreamReceiving(Size); } virtual void InformStreamSending(u_int32_t Size) { this->Protocol::InformStreamSending(Size); } public: virtual std::auto_ptr ReceiveStream() { return this->Protocol::ReceiveStream(); } __E } print H <<__E; virtual const char *GetProtocolIdentString() { return GetIdentString(); } __E if($writing_local) { print H <<__E; virtual int GetTimeout() { return IOStream::TimeOutInfinite; } __E } else { print H <<__E; virtual int GetTimeout() { return this->Protocol::GetTimeout(); } __E } print H <<__E; /* virtual void Handshake() { this->Protocol::Handshake(); } virtual bool GetLastError(int &rTypeOut, int &rSubTypeOut) { return this->Protocol::GetLastError(rTypeOut, rSubTypeOut); } */ private: $server_or_client_class(const $server_or_client_class &rToCopy); /* no copies */ }; __E my $destructor_extra = ($writing_server) ? "\n\tDeleteStreamsToSend();" : ''; if($writing_local) { print CPP <<__E; $server_or_client_class\::$server_or_client_class($context_class &rContext) : mrContext(rContext) { } __E } else { print CPP <<__E; $server_or_client_class\::$server_or_client_class(IOStream &rStream) : Protocol(rStream) { } __E } print CPP <<__E; $server_or_client_class\::~$server_or_client_class() {$destructor_extra } __E # write receive and send functions print CPP <<__E; std::auto_ptr $server_or_client_class\::MakeMessage(int ObjType) { switch(ObjType) { __E # do objects within this for my $cmd (@cmd_list) { print CPP <<__E; case $cmd_id{$cmd}: return std::auto_ptr(new $cmd_class{$cmd}()); break; __E } print CPP <<__E; default: THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnknownCommandRecieved) } } __E if(not $writing_local) { print CPP <<__E; std::auto_ptr<$message_base_class> $server_or_client_class\::Receive() { std::auto_ptr<$message_base_class> preply(($message_base_class *) Protocol::ReceiveInternal().release()); if(GetLogToSysLog()) { preply->LogSysLog("Receive"); } if(GetLogToFile() != 0) { preply->LogFile("Receive", GetLogToFile()); } return preply; } void $server_or_client_class\::Send(const $message_base_class &rObject) { if(GetLogToSysLog()) { rObject.LogSysLog("Send"); } if(GetLogToFile() != 0) { rObject.LogFile("Send", GetLogToFile()); } Protocol::SendInternal(rObject); } __E } # write server function? if($writing_server) { print CPP <<__E; void $server_or_client_class\::DoServer($context_class &rContext) { // Handshake with client Handshake(); // Command processing loop bool inProgress = true; while(inProgress) { // Get an object from the conversation std::auto_ptr<$message_base_class> pobj = Receive(); // Run the command std::auto_ptr<$message_base_class> preply = pobj->DoCommand(*this, rContext); // Send the reply Send(*preply); // Send any streams for(std::list::iterator i = mStreamsToSend.begin(); i != mStreamsToSend.end(); ++i) { SendStream(**i); } // Delete these streams DeleteStreamsToSend(); // Does this end the conversation? if(pobj->IsConversationEnd()) { inProgress = false; } } } __E } # write client Query functions? if($writing_client or $writing_local) { for my $cmd (@cmd_list) { if(obj_is_type($cmd,'Command')) { my $request_class = $cmd_class{$cmd}; my $reply_msg = obj_get_type_params($cmd,'Command'); my $reply_class = $cmd_class{$reply_msg}; my $reply_id = $cmd_id{$reply_msg}; my $has_stream = obj_is_type($cmd,'StreamWithCommand'); my $argextra = $has_stream?', IOStream &rStream':''; my $send_stream_extra = ''; my $send_stream_method = $writing_client ? "SendStream" : "SendStreamAfterCommand"; if($writing_client) { if($has_stream) { $send_stream_extra = <<__E; // Send stream after the command SendStream(rStream); __E } print CPP <<__E; std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class &rQuery$argextra) { // Send query Send(rQuery); $send_stream_extra // Wait for the reply std::auto_ptr<$message_base_class> preply = Receive(); CheckReply("$cmd", *preply, $reply_id); // Correct response, if no exception thrown by CheckReply return std::auto_ptr<$reply_class>(($reply_class *)preply.release()); } __E } elsif($writing_local) { if($has_stream) { $send_stream_extra = <<__E; // Send stream after the command SendStreamAfterCommand(&rStream); __E } print CPP <<__E; std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class &rQuery$argextra) { // Send query $send_stream_extra std::auto_ptr<$message_base_class> preply = rQuery.DoCommand(*this, mrContext); CheckReply("$cmd", *preply, $reply_id); // Correct response, if no exception thrown by CheckReply return std::auto_ptr<$reply_class>(($reply_class *)preply.release()); } __E } } } } } print H <<__E; #endif // $guardname __E # close files close H; close CPP; sub obj_is_type ($$) { my ($c,$ty) = @_; for(@{$cmd_attributes{$c}}) { return 1 if $_ =~ m/\A$ty/; } return 0; } sub obj_get_type_params { my ($c,$ty) = @_; for(@{$cmd_attributes{$c}}) { return $1 if $_ =~ m/\A$ty\((.+?)\)\Z/; } die "Can't find attribute $ty\n" } # returns (is basic type, typename) sub translate_type { my $ty = $_[0]; if($ty =~ m/\Avector\<(.+?)\>\Z/) { my $v_type = $1; my (undef,$v_ty) = translate_type($v_type); return (0, 'std::vector<'.$v_ty.'>') } else { if(!exists $translate_type_info{$ty}) { die "Don't know about type name $ty\n"; } return @{$translate_type_info{$ty}} } } sub translate_type_to_arg_type { my ($basic,$typename) = translate_type(@_); return $basic?$typename:'const '.$typename.'&' } sub translate_type_to_member_type { my ($basic,$typename) = translate_type(@_); return $typename } sub make_log_strings_framework { my ($cmd) = @_; my @args; for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2) { my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]); if(exists $log_display_types{$ty}) { # need to translate it my ($format,$arg) = @{$log_display_types{$ty}}; $arg =~ s/VAR/m$nm/g; if ($format eq '"%s"') { $arg = "\"\\\"\" << $arg << \"\\\"\""; } elsif ($format =~ m'x$') { # my $width = 0; # $ty =~ /^int(\d+)$/ and $width = $1 / 4; $arg = "($arg == 0 ? \"0x\" : \"\") " . "<< std::hex " . "<< std::showbase " . # "<< std::setw($width) " . # "<< std::setfill('0') " . # "<< std::internal " . "<< $arg " . "<< std::dec"; } push @args, $arg; } else { # is opaque push @args, '"OPAQUE"'; } } my $log_cmd = "Action << \" $cmd(\" "; foreach my $arg (@args) { $arg = "<< $arg "; } $log_cmd .= join('<< "," ',@args); $log_cmd .= '<< ")"'; return $log_cmd; }